littlejsengine 1.15.2 → 1.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/littlejs.d.ts +32 -9
- package/dist/littlejs.esm.js +128 -62
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +128 -62
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +92 -40
- package/examples/electron/index.html +2 -2
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/box2dCar.js +1 -1
- package/examples/shorts/music.js +1 -0
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/sequencer.js +2 -0
- package/examples/shorts/sound.js +1 -0
- package/examples/shorts/timers.js +1 -0
- package/examples/shorts/uiSystem.js +1 -0
- package/examples/shorts/videoPlayer.js +2 -1
- package/examples/starter/index.html +2 -2
- package/examples/uiSystem/game.js +1 -0
- package/package.json +1 -1
- package/plugins/uiSystem.js +30 -3
- package/src/engine.js +1 -1
- package/src/engineAudio.js +0 -1
- package/src/engineDebug.js +36 -22
- package/src/engineDraw.js +56 -32
- package/src/engineInput.js +1 -1
- package/src/engineObject.js +3 -1
- package/src/engineTileLayer.js +1 -1
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.15.2",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 pluginList=[];class EnginePlugin{constructor(a,b,c,d){this.update=a;this.render=b;this.glContextLost=c;this.glContextRestored=d}}function engineAddPlugin(a,b,c,d){ASSERT(!pluginList.find(f=>f.update===a&&f.render===b&&f.glContextLost===c&&f.glContextRestored===d));const e=new EnginePlugin(a,b,c,d);pluginList.push(e)}async function engineInit(a,b,c,d,e,f=[],g=document.body){function h(l=0){function m(){if(!headlessMode){q||k();mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);overlayContext.imageSmoothingEnabled=mainContext.imageSmoothingEnabled=!tilesPixelated;glPreRender();d();engineObjects.sort((u,w)=>u.renderOrder-w.renderOrder);for(var t of engineObjects)t.destroyed||t.render();e();pluginList.forEach(u=>u.render?.());touchGamepadRender();debugRender();glFlush();debugVideoCaptureUpdate();showWatermark&&!debugVideoCaptureIsActive()&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",t=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(t,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(t,mainCanvas.width-2,2));drawCount=0}}var p=l-frameTimeLastMS;frameTimeLastMS=l;if(debug||showWatermark)averageFPS=lerp(averageFPS,1e3/(p||1),.05);l=debug&&keyIsDown("Equal");const r=debug&&keyIsDown("Minus");debug&&(p*=l?10:r?.1:1);timeReal+=p/1e3;frameTimeBufferMS+=paused?0:p;l||(frameTimeBufferMS=min(frameTimeBufferMS,50));let q=!1;if(paused){q=!0;k();inputUpdate();pluginList.forEach(t=>t.update?.());for(const t of engineObjects)t.parent||t.updateTransforms();debugUpdate();c();inputUpdatePost()}else{p=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(p=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,q=!0,k(),inputUpdate(),b(),pluginList.forEach(t=>t.update?.()),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost(),debugVideoCaptureIsActive()&&m();frameTimeBufferMS+=p}debugVideoCaptureIsActive()||m();requestAnimationFrame(h)}function k(){if(!headlessMode){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const l=innerWidth/innerHeight,m=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=l<m?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=l<m?"":"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 n(){await a();h()}ASSERT(!mainContext,"engine already initialized");ASSERT(isArray(f),"pass in images as array");a||=()=>{};b||=()=>{};c||=()=>{};d||=()=>{};e||=()=>{};if(headlessMode)return n();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((l,m)=>new Promise(p=>{ASSERT(isString(l),"imageSources must be an array of strings");const r=new Image;r.onerror=r.onload=()=>{const q=new TextureInfo(r);textureInfos[m]=q;p()};r.crossOrigin="anonymous";r.src=l}));f.length||g.push(new Promise(l=>{const m=new TextureInfo(new Image);textureInfos[0]=m;l()}));showSplashScreen&&g.push(new Promise(l=>{function m(){inputClear();drawEngineSplashScreen(p+=.01);1<p?l():setTimeout(m,16)}let p=0;console.log(`${engineName} Engine v${engineVersion}`);m()}));await Promise.all(g);return n()}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)if(!b.parent){b.update();b.updatePhysics();for(const c of b.children)a(c);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)e.isOverlapping(a,b)&&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*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,n,l,m,p)=>{b.beginPath();b.rect(k,n,l,p?m*h:m);(b.fillStyle=p)?b.fill():b.stroke()};f=(k,n,l,m=0,p=2*PI,r,q)=>{const t=(m+p)/2;m=h*(p-m)/2;b.beginPath();q&&b.lineTo(k,n);b.arc(k,n,l,t-m,t+m);(b.fillStyle=r)?b.fill():b.stroke()};e=(k=0,n=0)=>hsl([.98,.3,.57,.14][k%4]-10,.8,[0,.3,.5,.8,.9][n]).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,n=41-g/2;k<f.length;++k)b.fillStyle=e(k,2),d=b.measureText(f[k]).width,b[c?"strokeText":"fillText"](f[k],n+d/2,55.5,17*h),n+=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 LOG(){}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(){}function debugProtectConstant(a){return a}const PI=Math.PI,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,min=Math.min,max=Math.max,sign=Math.sign,hypot=Math.hypot,log2=Math.log2,sin=Math.sin,cos=Math.cos,tan=Math.tan,atan2=Math.atan2;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**ceil(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-cos(d+c*a*2*PI))}function formatTime(a){const b=0>a?"-":"";a=abs(a)|0;return b+(a/60|0)+":"+(10>a%60?"0":"")+a%60}async function fetchJSON(a){const b=await fetch(a);if(!b.ok)throw Error(`Failed to fetch JSON from ${a}: ${b.status} ${b.statusText}`);return b.json()}function isNumber(a){return"number"===typeof a&&!isNaN(a)}function isString(a){return void 0!==a&&null!==a&&"string"===typeof a.toString()}function isArray(a){return Array.isArray(a)}function lineTest(a,b,c,d){ASSERT(isVector2(a),"posStart must be a vec2");ASSERT(isVector2(b),"posEnd must be a vec2");ASSERT("function"===typeof c,"testFunction must be a function");ASSERT(!d||isVector2(d),"normal must be a vec2");var e=b.x-a.x,f=b.y-a.y;if(b=hypot(e,f)){var g=a.floor();e/=b;var h=f/b;f=sign(e);var k=sign(h),n=e?abs(1/e):Infinity,l=h?abs(1/h):Infinity,m=0<f?g.x+1:g.x,p=0<k?g.y+1:g.y,r=0;m=e?(m-a.x)/e:Infinity;var q=h?(p-a.y)/h:Infinity;for(p=n<l;r<b;){if(c(g))return a=vec2(a.x+e*r,a.y+h*r),p&&0>f&&(a.x-=1e-9),0>k&&(a.y-=1e-9),d&&(p?d.set(-f,0):d.set(0,-k)),a;(p=m<q)?(g.x+=f,r=m,m+=n):(g.y+=k,r=q,q+=l)}}}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return 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 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))}randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return c?a.lerp(b,this.float()):new Color(this.float(a.r,b.r),this.float(a.g,b.g),this.float(a.b,b.b),this.float(a.a,b.a))}mutateColor(a,b=.05,c=0){ASSERT_NUMBER_VALID(b);ASSERT_NUMBER_VALID(c);return new Color(a.r+this.float(b,-b),a.g+this.float(b,-b),a.b+this.float(b,-b),a.a+this.float(c,-c)).clamp()}}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 atan2(this.x,this.y)}setAngle(a=0,b=1){ASSERT_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);this.x=b*sin(a);this.y=b*cos(a);return this}rotate(a){ASSERT_NUMBER_VALID(a);const b=cos(-a);a=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.");this.x=a%2?a-1?-b:b:0;this.y=a%2?0:a?-b:b;return this}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}abs(){return new Vector2(abs(this.x),abs(this.y))}floor(){return new Vector2(floor(this.x),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);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 n=e-f;k=.5<g?n/(2-e-f):n/(e+f);a===e?h=(b-c)/n+(b<c?6:0):b===e?h=(c-a)/n+2:c===e&&(h=(a-b)/n+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){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(isString(a),"Color hex code must be a string");ASSERT("#"===a[0],"Color hex code must start 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=debugProtectConstant(rgb()),CLEAR_WHITE=debugProtectConstant(rgb(1,1,1,0)),BLACK=debugProtectConstant(rgb(0,0,0)),CLEAR_BLACK=debugProtectConstant(rgb(0,0,0,0)),GRAY=debugProtectConstant(rgb(.5,.5,.5)),RED=debugProtectConstant(rgb(1,0,0)),ORANGE=debugProtectConstant(rgb(1,.5,0)),YELLOW=debugProtectConstant(rgb(1,1,0)),GREEN=debugProtectConstant(rgb(0,1,0)),CYAN=debugProtectConstant(rgb(0,1,1)),BLUE=debugProtectConstant(rgb(0,0,1)),PURPLE=debugProtectConstant(rgb(.5,0,1)),MAGENTA=debugProtectConstant(rgb(1,0,1));class Timer{constructor(a,b=!1){ASSERT(void 0===a||isNumber(a),"Constructed Timer is invalid.",a);this.useRealTime=b;b=this.getGlobalTime();this.time=void 0===a?void 0:b+a;this.setTime=a}set(a=0){ASSERT(isNumber(a),"Timer is invalid.",a);this.time=this.getGlobalTime()+a;this.setTime=a}setUseRealTime(a=!0){ASSERT(!this.isSet(),"Cannot change global time setting while timer is set.");this.useRealTime=a}unset(){this.time=void 0}isSet(){return void 0!==this.time}active(){return this.getGlobalTime()<this.time}elapsed(){return this.getGlobalTime()>=this.time}get(){return this.isSet()?this.getGlobalTime()-this.time:0}getPercent(){return this.isSet()?1-percent(this.time-this.getGlobalTime(),0,this.setTime):0}getSetTime(){return this.isSet()?this.setTime:0}getGlobalTime(){return this.useRealTime?timeReal:time}toString(){return this.isSet()?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,touchGamepadCenterButton=!0,touchGamepadAnalog=!0,touchGamepadButtonCount=4,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.copy()}function setCameraAngle(a){cameraAngle=a}function setCameraScale(a){cameraScale=a}function setCanvasColorTiles(a){canvasColorTiles=a}function setCanvasClearColor(a){canvasClearColor=a.copy()}function setCanvasMaxSize(a){canvasMaxSize=a.copy()}function setCanvasFixedSize(a){canvasFixedSize=a.copy()}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){a&&!glCanBeEnabled?console.warn("Can not enable WebGL if it was disabled on start."):(glEnable=a,glCanvas&&(glCanvas.style.display=a?"":"none"))}function setGLCircleSides(a){glCircleSides=a}function setTileSizeDefault(a){tileSizeDefault=a.copy()}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.copy()}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 setTouchGamepadCenterButton(a){touchGamepadCenterButton=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.copy()}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=WHITE,f=0){ASSERT(isVector2(a),"object pos must be a vec2");ASSERT(isVector2(b),"object size must 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()}updatePhysics(){ASSERT(!this.parent);this.clampSpeed&&(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed));const 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(!this.isOverlappingObject(e))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)){c=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);if(d=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this)){f=floor(a.y-this.size.y/2+1)+this.size.y/2+.001;if(.1>f-this.pos.y&&!tileCollisionTest(vec2(this.pos.x,f),this.size,this)){this.pos.y=f;debugPhysics&&debugRect(this.pos,this.size,"#ff0");return}this.pos.x=a.x;this.velocity.x*=-this.restitution}if(c||!d)c=max(this.restitution,e.restitution),this.velocity.y*=-c,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);debugPhysics&&debugRect(this.pos,this.size,"#f00")}}}update(){}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}getUp(a=1){return vec2().setAngle(this.angle,a)}getRight(a=1){return vec2().setAngle(this.angle+PI/2,a)}getAliveTime(){return time-this.spawnTime}getSpeed(){return this.velocity.length()}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));ASSERT(a instanceof EngineObject,"child must be an EngineObject");ASSERT(a!==this,"cannot add self as child");this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent===this&&this.children.includes(a));ASSERT(a instanceof EngineObject,"child must be an EngineObject");this.children.splice(this.children.indexOf(a),1);a.parent=0}isOverlappingObject(a){return this.isOverlapping(a.pos,a.size)}isOverlapping(a,b=vec2()){return isOverlapping(this.pos,this.size,a,b)}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){this.pos=new Vector2;this.size=a.size.copy();this.textureInfo=a;this.bleedScale=this.padding=0;return this}}class TextureInfo{constructor(a,b=!0){this.size=(this.image=a)?vec2(a.width,a.height):vec2();this.sizeInverse=a?vec2(1/a.width,1/a.height):vec2();this.glTexture=void 0;b&&this.createWebGLTexture()}createWebGLTexture(){glRegisterTextureInfo(this)}destroyWebGLTexture(){glUnregisterTextureInfo(this)}hasWebGL(){return!!this.glTexture}}function drawTile(a,b=new Vector2(1),c,d=WHITE,e=0,f,g,h=glEnable,k,n){ASSERT(isVector2(a),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(d),"color is invalid");ASSERT(isNumber(e),"angle must be a number");ASSERT(!g||isColor(g),"additiveColor must be a color");ASSERT(!n||!h,"context only supported in canvas 2D mode");const l=c&&c.textureInfo,m=c?c.bleedScale:0;if(h)if(ASSERT(!!glContext,"WebGL is not enabled!"),k&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),l){var p=l.sizeInverse;h=c.pos.x*p.x;k=c.pos.y*p.y;n=c.size.x*p.x;const r=c.size.y*p.y;glSetTexture(l.glTexture);if(m){const q=p.x*m;p=p.y*m;glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+q,k+p,h-q+n,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+n,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(l)drawImageColor(r,l.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1,d,g,m);else{const q=g?d.add(g):d;r.fillStyle=q.toString();r.fillRect(-.5,-.5,1,1)}},k,n)}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),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(c)&&isColor(d),"color is invalid");ASSERT(isNumber(e),"angle must be a number");ASSERT(!h||!f,"context only supported in canvas 2D mode");if(f){ASSERT(!!glContext,"WebGL is not enabled!");g&&(a=screenToWorld(a),b=b.scale(1/cameraScale));f=[];g=[];h=b.x/2;b=b.y/2;const k=c.rgbaInt(),n=d.rgbaInt(),l=cos(-e);e=sin(-e);for(let m=4;m--;){const p=m&1?h:-h,r=m&2?b:-b,q=m&2?k:n;f.push(vec2(a.x+(p*l-r*e),a.y+(p*e+r*l)));g.push(q)}glDrawColoredPoints(f,g)}else++drawCount,b=new Vector2(b.x,-b.y),drawCanvas2D(a,b,e,!1,k=>{const n=k.createLinearGradient(0,-.5,0,.5);n.addColorStop(0,c.toString());n.addColorStop(1,d.toString());k.fillStyle=n;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(isArray(a),"points must be an array");ASSERT(isNumber(b),"width must be a number");ASSERT(isColor(c),"color is invalid");ASSERT(isVector2(e),"pos must be a vec2");ASSERT(isNumber(f),"angle must be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?(ASSERT(!!glContext,"WebGL is not enabled!"),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,n=>{n.strokeStyle=c.toString();n.lineWidth=b;n.beginPath();for(let l=0;l<a.length;++l){const m=a[l];l?n.lineTo(m.x,m.y):n.moveTo(m.x,m.y)}d&&n.closePath();n.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));h&&(b.y*=-1);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,n){ASSERT(isVector2(b),"size must be a vec2");ASSERT(isNumber(c),"sides must be a number");const l=[],m=b.x/2;b=b.y/2;for(let p=c;p--;){const r=p/c*PI*2;l.push(vec2(sin(r)*m,cos(r)*b))}drawPoly(l,d,e,f,a,g,h,k,n)}function drawPoly(a,b=WHITE,c=0,d=BLACK,e=vec2(),f=0,g=glEnable,h=!1,k){ASSERT(isVector2(e),"pos must be a vec2");ASSERT(isArray(a),"points must be an array");ASSERT(isColor(b)&&isColor(d),"color is invalid");ASSERT(isNumber(c),"lineWidth must be a number");ASSERT(isNumber(f),"angle must be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?(ASSERT(!!glContext,"WebGL is not enabled!"),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,n=>{n.fillStyle=b.toString();n.beginPath();for(const l of a)n.lineTo(l.x,l.y);n.closePath();n.fill();c&&(n.strokeStyle=d.toString(),n.lineWidth=c,n.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),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(c)&&isColor(f),"color is invalid");ASSERT(isNumber(d),"angle must be a number");ASSERT(isNumber(e),"lineWidth must be a number");ASSERT(0<=e&&e<b.x&&e<b.y,"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,n=>{n.fillStyle=c.toString();n.beginPath();n.ellipse(0,0,b.x/2,b.y/2,0,0,9);n.fill();e&&(n.strokeStyle=f.toString(),n.lineWidth=e,n.stroke())},h,k)}function drawCircle(a,b=1,c=WHITE,d=0,e=BLACK,f=glEnable,g=!1,h){ASSERT(isNumber(b),"size must 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){ASSERT(isVector2(a),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isNumber(c),"angle must be a number");ASSERT("function"===typeof e,"drawFunction must be a function");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,n,l=0,m=drawContext){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,h,k,n,l,m)}function drawTextOverlay(a,b,c=1,d,e=0,f,g,h,k,n,l=0){drawText(a,b,c,d,e,f,g,h,k,n,l,overlayContext)}function drawTextScreen(a,b,c=1,d=WHITE,e=0,f=BLACK,g="center",h=fontDefault,k="",n,l=0,m=overlayContext){ASSERT(isString(a),"text must be a string");ASSERT(isVector2(b),"pos must be a vec2");ASSERT(isNumber(c),"size must be a number");ASSERT(isColor(d),"color must be a color");ASSERT(isNumber(e),"lineWidth must be a number");ASSERT(isColor(f),"lineColor must be a color");ASSERT(["left","center","right"].includes(g),"align must be left, center, or right");ASSERT(isString(h),"font must be a string");ASSERT(isString(k),"fontStyle must be a string");ASSERT(isNumber(l),"angle must be a number");m.fillStyle=d.toString();m.strokeStyle=f.toString();m.lineWidth=e;m.textAlign=g;m.font=k+" "+c+"px "+h;m.textBaseline="middle";a=(a+"").split("\n");d=b.y-(a.length-1)*c/2;m.save();m.translate(b.x,d);m.rotate(-l);let p=0;a.forEach(r=>{e&&m.strokeText(r,0,p,n);m.fillText(r,0,p,n);p+=c});m.restore()}function screenToWorld(a){let b=(a.x-mainCanvasSize.x/2+.5)/cameraScale;a=(a.y-mainCanvasSize.y/2+.5)/-cameraScale;if(cameraAngle){const c=cos(-cameraAngle),d=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=cos(cameraAngle),d=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 screenToWorldDelta(a){let b=a.x/cameraScale;a=a.y/-cameraScale;if(cameraAngle){const c=cos(-cameraAngle),d=sin(-cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b,a)}function worldToScreenDelta(a){let b=a.x;a=a.y;if(cameraAngle){const c=cos(cameraAngle),d=sin(cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b*cameraScale,a*-cameraScale)}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,n,l,m,p=0){function r(u){return 1<=u.r&&1<=u.g&&1<=u.b}e=max(1,e|0);f=max(1,f|0);const q=e-2*p,t=f-2*p;if(!canvasColorTiles||(m?r(l.add(m))&&0>=m.a:r(l)))a.globalAlpha=l.a,a.drawImage(b,c+p,d+p,q,t,g,h,k,n),a.globalAlpha=1;else if(workCanvas.width=e,workCanvas.height=f,workContext.drawImage(b,c|0,d|0,e,f,0,0,e,f),b=workContext.getImageData(0,0,e,f),c=b.data,!m||0>=m.r&&0>=m.g&&0>=m.b&&0>=m.a){for(m=0;m<c.length;m+=4)c[m]*=l.r,c[m+1]*=l.g,c[m+2]*=l.b;workContext.putImageData(b,0,0);a.globalAlpha=l.a;a.drawImage(workCanvas,p,p,q,t,g,h,k,n);a.globalAlpha=1}else{l=[l.r,l.g,l.b,l.a];m=[255*m.r,255*m.g,255*m.b,255*m.a];for(d=0;d<c.length;++d)c[d]=c[d]*l[d&3]+m[d&3]|0;workContext.putImageData(b,0,0);a.drawImage(workCanvas,p,p,q,t,g,h,k,n)}}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)){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=!0,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,n)=>{const l=d?k.length*f.x*c/2|0:0;for(let r=k.length;r--;){var m=k[r].charCodeAt(0);if(32>m||127<m)m=127;var p=m-32;m=p%h;p=p/h|0;const q=b.add(vec2(r,n).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,q.x-l,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,mouseInWindow=!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=screenToWorldDelta(mouseDeltaScreen),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){if(!isTouchDevice||!touchInputEnable){soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioContext.resume();isUsingGamepad=!1;inputData[0][b.button]=3;var c=mousePosScreen;mousePosScreen=mouseEventToScreen(vec2(b.x,b.y));mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(c));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){mouseInWindow=!0;const c=mousePosScreen;mousePosScreen=mouseEventToScreen(vec2(b.x,b.y));b=pointerLockIsActive()?vec2(b.movementX,b.movementY):mousePosScreen.subtract(c);mouseDeltaScreen=mouseDeltaScreen.add(b)}),document.addEventListener("mouseleave",function(){mouseInWindow=!1}),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(){var a=f=>{const g=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;return vec2(g(f.x),g(-f.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice){if(touchGamepadTimer.isSet()){var b=gamepadStickData[0]||(gamepadStickData[0]=[]);b[0]=vec2();touchGamepadAnalog?b[0]=a(touchGamepadStick):.3<touchGamepadStick.lengthSquared()&&(b[0].x=round(touchGamepadStick.x),b[0].y=-round(touchGamepadStick.y),b[0]=b[0].clampLength());a=inputData[1]||(inputData[1]=[]);for(b=10;b--;){var c=gamepadIsDown(b,0);a[b]=touchGamepadButtons[b]?c?1:3:c?4:0}}}else if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){var d=b[c];const f=inputData[c+1]||(inputData[c+1]=[]),g=gamepadStickData[c]||(gamepadStickData[c]=[]);if(d){for(var e=0;e<d.axes.length-1;e+=2)g[e>>1]=a(vec2(d.axes[e],d.axes[e+1]));for(e=d.buttons.length;e--;){const h=d.buttons[e],k=gamepadIsDown(e,c);f[e]=h.pressed?k?1:3:k?4:0;(!h.value||.9<h.value)&&!c&&h.pressed&&(isUsingGamepad=!0)}gamepadDirectionEmulateStick&&(d=vec2((gamepadIsDown(15,c)&&1)-(gamepadIsDown(14,c)&&1),(gamepadIsDown(12,c)&&1)-(gamepadIsDown(13,c)&&1)),d.lengthSquared()&&(g[0]=d.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 touchGamepadButtonCenter(){const a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);2>=touchGamepadButtonCount&&(a.x+=touchGamepadSize/2);return a}function touchInputInit(){function a(c){if(touchInputEnable){if(touchGamepadEnable)a:{touchGamepadStick=vec2();touchGamepadButtons=[];isUsingGamepad=!0;if(c.touches.length&&(touchGamepadTimer.set(),touchGamepadCenterButton&&!b&&paused)){touchGamepadButtons[9]=1;break a}var d=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),e=touchGamepadButtonCenter(),f=mainCanvasSize.scale(.5);for(const h of c.touches){var g=mouseEventToScreen(vec2(h.clientX,h.clientY));if(d.distance(g)<touchGamepadSize)touchGamepadStick=g.subtract(d).scale(2/touchGamepadSize).clampLength();else if(e.distance(g)<touchGamepadSize){let k=e.subtract(g).direction();k=mod(k+2,4);1===touchGamepadButtonCount?k=0:2===touchGamepadButtonCount&&(g=e.subtract(g),k=-g.x<g.y?1:0);k=3===k?2:2===k?3:k;k<touchGamepadButtonCount&&(touchGamepadButtons[k]=1)}else touchGamepadCenterButton&&!b&&f.distance(g)<touchGamepadSize&&(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.cancelable&&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=touchGamepadButtonCenter();c=1<touchGamepadButtonCount?touchGamepadSize/4:touchGamepadSize/2;for(d=0;d<touchGamepadButtonCount;d++){var e=mod(d-1,4);let f=2<touchGamepadButtonCount?e:min(e,touchGamepadButtonCount-1);f=3===f?2:2===f?3:f;e=a.add(vec2().setDirection(e,touchGamepadSize/2));b.fillStyle=touchGamepadButtons[f]?"#fff":"#000";b.beginPath();b.arc(e.x,e.y,c,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&&(ASSERT(!a||isArray(a),"zzfxSound is invalid"),ASSERT(isNumber(b),"range must be a number"),ASSERT(isNumber(c),"taper must be a number"),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){ASSERT(!a||isVector2(a),"pos must be a vec2");ASSERT(isNumber(b),"volume must be a number");ASSERT(isNumber(c),"pitch must be a number");ASSERT(isNumber(d),"randomnessScale must be a number");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=0,b,c){ASSERT(isNumber(a),"semitoneOffset must be a number");a=getNoteFrequency(a,1);return this.play(b,c,a,0)}getDuration(){return this.sampleChannels&&this.sampleRate?this.sampleChannels[0].length/this.sampleRate:0}isLoaded(){return 1===this.loadedPercent}}class SoundWave extends Sound{constructor(a,b=0,c,d,e){super(void 0,c,d);soundEnable&&!headlessMode&&(ASSERT(!a||isString(a),"filename must be a string"),ASSERT(isNumber(b),"randomness must be a number"),this.onloadCallback=e,this.randomness=b,a&&this.loadSound(a))}async loadSound(a){var b=await fetch(a);if(!b.ok)throw Error(`Failed to load sound from ${a}: ${b.status} ${b.statusText}`);a=await b.arrayBuffer();a=await audioContext.decodeAudioData(a);b=a.numberOfChannels;const 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(this)}}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):(this.startTime=void 0,this.pausedTime=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.rate?this.sound.getDuration()/this.rate:0}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){if(audioIsRunning()){var n=audioContext.createBuffer(a.length,a[0].length,f),l=audioContext.createBufferSource();a.forEach((m,p)=>n.getChannelData(p).set(m));l.buffer=n;l.playbackRate.value=c;l.loop=e;g=g||audioContext.createGain();g.gain.value=b;g.connect(audioMasterGain);a=new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)});l.connect(a).connect(g);k&&l.addEventListener("ended",()=>k(l));l.start(0,h*c);return l}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,n=0,l=0,m=0,p=0,r=0,q=0,t=0,u=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=cos(M),N=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;u*=v;n*=500*y/v**3;q*=y/v;l*=y/v;m*=v;p=p*v|0;for(v=d+x+e+f+u|0;A<v;K[A++]=C*a)++H%(100*t|0)||(C=g?1<g?2<g?3<g?4<g?F/y%1<h/2?1:-1:sin(F**3):max(min(tan(F),1),-1):1-(2*F/y%2+2)%2:1-4*abs(round(F/y)-F/y):sin(F),C=(p?1-B+B*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-u?(v-A-u)/f*w:0),C=u?C/2+(u>A?0:(A<v-u?1:(v-A)/u)*K[A-u|0]/2/a):C,z&&(C=S=P*I+L*(I=Q)+P*(Q=C)-N*R-M*(R=S))),O=(c+=k+=n)*cos(q*G++),F+=O+O*r*sin(A**5),E&&++E>m&&(c+=l,b+=l,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,e=!0){for(const f of tileCollisionLayers)if(!e||f.isSolid){const g=f.collisionRaycast(a,b,c,d);if(g)return g}}function tileLayersLoad(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 l=h;l--;){const m=a.layers[l];ASSERT(m.data&&m.data.length);ASSERT(g.area()===m.data.length);var k=c-(h-1-l);k=new TileCollisionLayer(vec2(),g,b,k);f[l]=k;const p=m.tintcolor?(new Color).setHex(m.tintcolor):m.color||WHITE;ASSERT(isColor(p),"layer color is not a color");for(let r=g.x;r--;)for(let q=g.y;q--;){const t=vec2(r,g.y-1-q);var n=m.data[r+q*g.x];n&&(n=new TileLayerData(n-1,0,!1,p),k.setData(t,n),l===d&&k.setCollisionData(t,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)){ASSERT(isVector2(e),"canvasSize must be a Vector2");super(a,b,void 0,c,WHITE,d);this.canvas=headlessMode?void 0:new OffscreenCanvas(e.x,e.y);this.context=this.canvas?.getContext("2d");this.textureInfo=new TextureInfo(this.canvas,!1);this.refreshWebGL=!1;this.mass=this.gravityScale=this.friction=this.restitution=0}destroy(){this.destroyed||(this.textureInfo.destroyWebGLTexture(),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&&this.textureInfo.hasWebGL();k&&this.refreshWebGL&&(this.textureInfo.createWebGLTexture(),this.refreshWebGL=!1);const n=(new TileInfo).setFullImage(this.textureInfo);drawTile(a,b,n,d,c,e,f,k,g,h)}drawCanvas2D(a,b,c,d,e){if(this.context){var 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.toString(),g.fillRect(-.5,-.5,1,1))})}drawRect(a,b,c,d){this.drawTile(a,b,void 0,c,d)}useWebGL(a=!0,b=!1){!b&&a&&this.textureInfo.hasWebGL()?this.refreshWebGL=!0:a?this.textureInfo.createWebGLTexture():this.textureInfo.destroyWebGLTexture()}}class TileLayer extends CanvasLayer{constructor(a,b,c=tile(),d=0){const e=c?b.multiply(c.size):b;super(a,b,0,d,e);this.tileInfo=c;this.data=[];for(a=this.size.area();a--;)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){ASSERT(isVector2(a),"layerPos must be a Vector2");ASSERT(b instanceof TileLayerData,"data must be a TileLayerData");a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){ASSERT(isVector2(a),"layerPos must be a Vector2");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!");this.refreshWebGL&&(this.textureInfo.createWebGLTexture(),this.refreshWebGL=!1);const a=(new TileInfo).setFullImage(this.textureInfo),b=this.drawSize||this.size,c=this.pos.add(b.scale(.5)),d=glEnable&&this.textureInfo.hasWebGL();drawTile(c,b,a,WHITE,0,!1,CLEAR_BLACK,d)}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.useWebGL()}redrawStart(a=!1){if(this.context){this.savedRenderSettings=[drawCanvas,drawContext,mainCanvasSize,cameraPos,cameraScale];drawCanvas=this.canvas;drawContext=this.context;cameraPos=this.size.scale(.5);var b=this.tileInfo?this.tileInfo.size:vec2(1);cameraScale=b.x;mainCanvasSize=this.size.multiply(b);a&&(drawCanvas.width=mainCanvasSize.x,drawCanvas.height=mainCanvasSize.y);this.context.imageSmoothingEnabled=!tilesPixelated;glPreRender()}}redrawEnd(){this.context&&(ASSERT(drawContext===this.context,"must call redrawStart() before drawing tiles"),glCopyToContext(drawContext),[drawCanvas,drawContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings)}drawTileData(a,b=!0){if(this.context){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){super(a,b.floor(),c,d);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){ASSERT(isVector2(a),"size must be a Vector2");this.size=a.floor();this.collisionData=[];this.collisionData.length=a.area();this.collisionData.fill(0)}setCollisionData(a,b=1){ASSERT(isVector2(a),"gridPos must be a Vector2");const c=(a.y|0)*this.size.x+a.x|0;a.arrayCheck(this.size)&&(this.collisionData[c]=b)}getCollisionData(a){ASSERT(isVector2(a),"gridPos must be a Vector2");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){ASSERT(isVector2(a)&&isVector2(b),"pos and size must be Vector2s");ASSERT(!c||c instanceof EngineObject,"object must be an EngineObject");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+this.pos.x,f+this.pos.y))))return!0}return!1}collisionRaycast(a,b,c,d){ASSERT(isVector2(a)&&isVector2(b),"positions must be Vector2s");ASSERT(!c||c instanceof EngineObject,"object must be an EngineObject");const e=new Vector2;debugRaycast&&debugLine(a,b,"#00f",.02);if(b=lineTest(a,b,f=>{e.set(f.x-this.pos.x,f.y-this.pos.y);const g=this.getCollisionData(e);return g&&(!c||c.collideWithTile(g,f))},d)){const f=b.floor().add(vec2(.5));debugRaycast&&debugRect(f,vec2(1),"#f008");debugRaycast&&debugLine(a,b,"#f00",.02);debugRaycast&&debugPoint(b,"#0f0");debugRaycast&&d&&debugLine(b,b.add(d),"#ff0",.02);return b}}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=WHITE,k=WHITE,n=CLEAR_WHITE,l=CLEAR_WHITE,m=.5,p=.1,r=1,q=.1,t=.05,u=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 instanceof Vector2?c.copy():c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h.copy();this.colorStartB=k.copy();this.colorEndA=n.copy();this.colorEndB=l.copy();this.randomColorLinear=G;this.particleTime=m;this.sizeStart=p;this.sizeEnd=r;this.speed=q;this.angleSpeed=t;this.damping=u;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.velocityInheritance=this.emitTimeBuffer=0;this.previousAngle=this.angle;this.previousPos=this.pos.copy()}updatePhysics(){}update(){if(this.velocityInheritance){var a=this.velocityInheritance;this.velocity.x=a*(this.pos.x-this.previousPos.x);this.velocity.y=a*(this.pos.y-this.previousPos.y);this.angleVelocity=a*(this.angle-this.previousAngle);this.previousAngle=this.angle;this.previousPos.x=this.pos.x;this.previousPos.y=this.pos.y}if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(this.emitRate&&particleEmitRateScale)for(a=1/this.emitRate/particleEmitRateScale,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=m=>m+m*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 n=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a=new Particle(a,this.tileInfo,b,n,l,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&&0<this.velocityInheritance&&(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,n,l,m,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEnd=e;this.lifeTime=f;this.sizeStart=g;this.sizeEnd=h;this.fadeRate=k;this.additive=n;this.trailScale=l;this.localSpaceEmitter=m;this.destroyCallback=p;this.clampSpeed=!1}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)}0<this.lifeTime&&time-this.spawnTime>this.lifeTime&&(a=this.colorEnd,this.color.set(a.r,a.g,a.b,a.a),this.size.set(this.sizeEnd,this.sizeEnd),this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}render(){var a=0<this.lifeTime?min((time-this.spawnTime)/this.lifeTime,1):1,b=1-a;const c=vec2(b*this.sizeStart+a*this.sizeEnd);this.color.r=b*this.colorStart.r+a*this.colorEnd.r;this.color.g=b*this.colorStart.g+a*this.colorEnd.g;this.color.b=b*this.colorStart.b+a*this.colorEnd.b;this.color.a=b*this.colorStart.a+a*this.colorEnd.a;b=this.fadeRate/2;this.color.a*=a<b?a/b:a>1-b?(1-a)/b:1;this.additive&&setBlendMode(!0);a=this.pos;b=this.angle;if(this.localSpaceEmitter){var d=this.localSpaceEmitter.angle,e=cos(d);d=sin(d);a=this.localSpaceEmitter.pos.add(new Vector2(a.x*e-a.y*d,a.x*d+a.y*e));b+=this.localSpaceEmitter.angle}if(this.trailScale){if(e=this.localSpaceEmitter?this.velocity.rotate(-this.localSpaceEmitter.angle):this.velocity,d=e.length())c.y=max(c.x,d*this.trailScale),b=atan2(e.x,e.y),drawTile(a,c,this.tileInfo,this.color,b,this.mirror)}else drawTile(a,c,this.tileInfo,this.color,b,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(a,c,"#f005",0,b)}}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;var f=hsl(0,0,.9);b.save();b.beginPath();b.fillStyle=f.toString();b.strokeStyle=BLACK.toString();b.lineWidth=3;b.rect(e,a,c,d);b.fill();b.stroke();b.clip();f=vec2(.1,.05).scale(d);const 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,void 0,c);e.y=a+d-2*f.y-k/2;drawTextScreen(this.description,e,k,BLACK,0,void 0,"left",void 0,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,glTextureInfos,glCanBeEnabled=!0;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(){function a(){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 b=new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);glPositionData=new Float32Array(b);glColorData=new Uint32Array(b);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();b=new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,b,glContext.STATIC_DRAW)}glTextureInfos=new Set;!glEnable||headlessMode?glCanBeEnabled=!1:(glCanvas=document.createElement("canvas"),(glContext=glCanvas.getContext("webgl2",{antialias:glAntialias}))?(mainCanvas.parentElement.appendChild(glCanvas),a(),glCanvas.addEventListener("webglcontextlost",b=>{glEnable=!1;glCanvas.style.display="none";b.preventDefault();LOG("WebGL context lost! Switching to Canvas2d rendering.");for(const c of glTextureInfos)c.glTexture=void 0;glActiveTexture=void 0;pluginList.forEach(c=>c.glContextLost?.())}),glCanvas.addEventListener("webglcontextrestored",()=>{glEnable=!0;glCanvas.style.display="";LOG("WebGL context restored, reinitializing...");a();for(const b of glTextureInfos)b.glTexture=glCreateTexture(b.image);pluginList.forEach(b=>b.glContextRestored?.())})):(console.warn("WebGL2 not supported, falling back to 2D canvas rendering!"),glCanvas=glContext=void 0,glCanBeEnabled=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=cos(cameraAngle),d=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 glRegisterTextureInfo(a){headlessMode||(glTextureInfos.add(a),glContext&&(a.glTexture?glSetTextureData(a.glTexture,a.image):a.glTexture=glCreateTexture(a.image)))}function glUnregisterTextureInfo(a){if(!headlessMode){glTextureInfos.delete(a);var b=a.glTexture;a.glTexture=void 0;glDeleteTexture(b)}}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,n=-1,l=0){(glBatchCount>=gl_MAX_INSTANCES||glBatchAdditive!==glAdditive)&&glFlush();glSetInstancedMode();glPolyMode=!1;let m=glBatchCount++*gl_INDICES_PER_INSTANCE;glPositionData[m++]=a;glPositionData[m++]=b;glPositionData[m++]=c;glPositionData[m++]=d;glPositionData[m++]=f;glPositionData[m++]=g;glPositionData[m++]=h;glPositionData[m++]=k;glColorData[m++]=n;glColorData[m++]=l;glPositionData[m++]=e}function glDrawPointsTransform(a,b,c,d,e,f,g,h=!0){const k=[];for(const n of a){a=n.x*e;const l=n.y*f,m=sin(-g),p=cos(-g);k.push(vec2(c+p*a-m*l,d+m*a+p*l))}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)],n=h.x-g.x,l=h.y-g.y,m=(n*n+l*l)**.5;g=k.x-h.x;const r=k.y-h.y;k=(g*g+r*r)**.5;1e-6>m&&1e-6>k||(l=1e-6<m?-l/m:0,m=1e-6<m?n/m:0,n=l+(1e-6<k?-r/k:0),g=m+(1e-6<k?g/k:0),k=(n*n+g*g)**.5,1e-6>k?(n=l,g=m):(n/=k,g/=k,l=l*n+m*g,1e-6<l&&(l=min(1/l,b),n*=l,g*=l)),l=vec2(h.x-n*d,h.y-g*d),h=vec2(h.x+n*d,h.y+g*d),e.push(l),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,t,u)=>(t.x-q.x)*(u.y-q.y)-(t.y-q.y)*(u.x-q.x);0>(q=>{let t=0;for(let u=q.length;u--;)t+=q[u].cross(q[(u+1)%q.length]);return t})(a)&&(a=a.reverse());var c=(q,t,u,w)=>{const x=b(t,u,q);u=b(u,w,q);q=b(w,t,q);return!((-1e-9>x?1:0)+(-1e-9>u?1:0)+(-1e-9>q?1:0)&&(1e-9<x?1:0)+(1e-9<u?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 n=d[(k+d.length-1)%d.length],l=d[k];const q=d[(k+1)%d.length],t=a[n],u=a[l],w=a[q];if(1e-9>b(t,u,w))continue;let x=!1;for(let B=0;B<d.length;B++){const z=d[B];if(z!==n&&z!==l&&z!==q&&(x=c(a[z],t,u,w)))break}if(!x){e.push([n,l,q]);d.splice(k,1);h=!0;break}}if(!h){h=-1;k=Infinity;for(n=0;n<d.length;n++)l=abs(b(a[d[(n+d.length-1)%d.length]],a[d[n]],a[d[(n+1)%d.length]])),l<k&&(k=l,h=n);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[m,p,r]=e[0];c.push(a[m],a[p],a[r]);for(d=1;d<e.length;d++){const[q,t,u]=e[d];c.push(a[r],a[q]);c.push(a[q],a[t],a[u]);r=u}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&&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&&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&&LOG("newgrounds call failed",e);return}debugMedals&&LOG(b.responseText);return b.responseText&&JSON.parse(b.responseText)}}let postProcess;class PostProcessPlugin{constructor(a,b=!1,c=!0){function d(){headlessMode||(glEnable?(postProcess.texture=glCreateTexture(),postProcess.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.;}")):console.warn("PostProcessPlugin: WebGL not enabled!"))}ASSERT(!postProcess,"Post process already initialized");postProcess=this;a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}";this.texture=this.shader=void 0;d();engineAddPlugin(void 0,function(){if(!headlessMode&&glEnable){glFlush();if(c||b)mainContext.drawImage(glCanvas,0,0),b&&(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);(c||b)&&glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,mainCanvas);var e=glContext.getAttribLocation(postProcess.shader,"p");glContext.enableVertexAttribArray(e);glContext.vertexAttribPointer(e,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)}},function(){postProcess.shader=void 0;postProcess.texture=void 0;LOG("PostProcessPlugin: WebGL context lost")},function(){d();LOG("PostProcessPlugin: WebGL context restored")})}}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,n,l,m,p,r,q,t,u,w=0,x,B=[],z=[],v=[],y=0,D=0,G=1,J={},H=audioDefaultSampleRate/d*60>>2;for(;G;y++)B=[G=m=t=0],c.forEach((E,K)=>{l=b[E][y]||[0,0,0];G|=b[E][y]&&1;x=t+(b[E][0].length-2-(m?0:1))*H;u=K===c.length-1;e=2;for(g=t;e<l.length+u;m=++e){k=l[e];p=e===l.length+u-1&&u||r!==(l[0]||0)||k|0;for(f=0;f<H&&m;f++>H-99&&p&&1>q?q+=1/99:0)n=(1-q)*B[w++]/2||0,z[g]=(z[g]||0)-n*D+n,v[g]=(v[g++]||0)+n*D+n;k&&(q=k%1,D=l[1]||0,k|=0)&&(B=J[[r=l[w=0]||0,k]]=J[[r,k]]||(h=[...a[r]],h[2]=(h[2]||220)*2**(k/12-1),0<k?zzfxG(...h):[]))}t=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.defaultGradientColor=void 0;this.defaultLineWidth=4;this.defaultCornerRadius=0;this.defaultTextScale=.8;this.defaultFont=fontDefault;this.defaultSoundClick=this.defaultSoundRelease=this.defaultSoundPress=void 0;this.uiObjects=[];this.uiContext=a;this.lastHoverObject=this.hoverObject=this.activeObject=void 0;this.nativeHeight=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.lastHoverObject=uiSystem.hoverObject;uiSystem.hoverObject=void 0;for(let d=uiSystem.uiObjects.length;d--;){const e=uiSystem.uiObjects[d];e.parent||c(e)}uiSystem.uiObjects=uiSystem.uiObjects.filter(d=>!d.destroyed)},function(){function b(d){if(d.visible){d.parent&&(d.pos=d.localPos.add(d.parent.pos));d.render();for(const e of d.children)b(e)}}const c=uiSystem.uiContext;c.save();if(uiSystem.nativeHeight){const d=mainCanvasSize.y/uiSystem.nativeHeight;c.translate(-d*mainCanvasSize.x/2,0);c.scale(d,d);c.translate(mainCanvasSize.x/2/d,0)}uiSystem.uiObjects.forEach(d=>d.parent||b(d));c.restore()})}drawRect(a,b,c=WHITE,d=0,e=BLACK,f=0,g){ASSERT(isVector2(a),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(c),"color must be a color");ASSERT(isNumber(d),"lineWidth must be a number");ASSERT(isColor(e),"lineColor must be a color");ASSERT(isNumber(f),"cornerRadius must be a number");const h=uiSystem.uiContext;if(g){const k=h.createLinearGradient(a.x,a.y-b.y/2,a.x,a.y+b.y/2);c=c.toString();k.addColorStop(0,c);k.addColorStop(.5,g.toString());k.addColorStop(1,c);h.fillStyle=k}else h.fillStyle=c.toString();h.beginPath();f&&h.roundRect?h.roundRect(a.x-b.x/2,a.y-b.y/2,b.x,b.y,f):h.rect(a.x-b.x/2,a.y-b.y/2,b.x,b.y);h.fill();d&&(h.strokeStyle=e.toString(),h.lineWidth=d,h.stroke())}drawLine(a,b,c=uiSystem.defaultLineWidth,d=uiSystem.defaultLineColor){ASSERT(isVector2(a),"posA must be a vec2");ASSERT(isVector2(b),"posB must be a vec2");ASSERT(isNumber(c),"lineWidth must be a number");ASSERT(isColor(d),"lineColor must be a color");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="",n=!0,l){l&&drawTextScreen(a,b.add(l),c.y,BLACK,e,f,g,h,k,n?c.x:void 0,0,uiSystem.uiContext);drawTextScreen(a,b,c.y,d,e,f,g,h,k,n?c.x:void 0,0,uiSystem.uiContext)}setupDragAndDrop(a,b,c,d){function e(f,g){document.addEventListener(g,function(h){h.preventDefault();f&&f(h)})}e(a,"drop");e(b,"dragenter");e(c,"dragleave");e(d,"dragover")}screenToNative(a){if(!uiSystem.nativeHeight)return a;const b=mainCanvasSize.y/uiSystem.nativeHeight,c=1/b;a=a.copy();a.x+=b*mainCanvasSize.x/2;a.x*=c;a.y*=c;a.x-=c*mainCanvasSize.x/2;return a}destroyObjects(){for(const a of this.uiObjects)a.parent||a.destroy();this.uiObjects=this.uiObjects.filter(a=>!a.destroyed)}}class UIObject{constructor(a=vec2(),b=vec2()){ASSERT(isVector2(a),"ui object pos must be a vec2");ASSERT(isVector2(b),"ui object size must be a vec2");this.localPos=a.copy();this.pos=a.copy();this.size=b.copy();this.color=uiSystem.defaultColor.copy();this.text=this.activeColor=void 0;this.disabledColor=uiSystem.defaultDisabledColor.copy();this.disabled=!1;this.textColor=uiSystem.defaultTextColor.copy();this.hoverColor=uiSystem.defaultHoverColor.copy();this.lineColor=uiSystem.defaultLineColor.copy();this.gradientColor=uiSystem.defaultGradientColor?uiSystem.defaultGradientColor.copy():void 0;this.lineWidth=uiSystem.defaultLineWidth;this.cornerRadius=uiSystem.defaultCornerRadius;this.font=uiSystem.defaultFont;this.textHeight=this.textWidth=this.fontStyle=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;this.canBeHover=!0;uiSystem.uiObjects.push(this);this.textShadow=void 0}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}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.parent=0,a.destroy()}}isMouseOverlapping(){if(!mouseInWindow)return!1;const a=isTouchDevice?this.size.add(vec2(this.extraTouchSize||0)):this.size,b=uiSystem.screenToNative(mousePosScreen);return isOverlapping(this.pos,a,b)}update(){this.onUpdate();const a=uiSystem.lastHoverObject===this,b=this.isActiveObject(),c=mouseIsDown(0),d=this.dragActivate?c:mouseWasPressed(0);this.canBeHover&&(d||b||!c&&!isTouchDevice)&&!uiSystem.hoverObject&&this.isMouseOverlapping()&&(uiSystem.hoverObject=this);if(this.isHoverObject()){if(!this.disabled){if(d&&this.interactive){if(!this.dragActivate||!a||mouseWasPressed(0))this.onPress();this.soundPress&&this.soundPress.play();if(uiSystem.activeObject&&!b)uiSystem.activeObject.onRelease();uiSystem.activeObject=this}!c&&this.isActiveObject()&&this.interactive&&(this.onClick(),this.soundClick&&this.soundClick.play())}d&&inputClearKey(0,0,0,1,0)}b&&(!c||this.dragActivate&&!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.disabled?this.disabledColor:this.interactive?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,this.gradientColor)}}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}onUpdate(){}onEnter(){}onLeave(){}onPress(){}onRelease(){}onClick(){}onChange(){}}class UIText extends UIObject{constructor(a,b,c="",d="center",e=uiSystem.defaultFont){super(a,b);ASSERT(isString(c),"ui text must be a string");ASSERT(["left","center","right"].includes(d),"ui text align must be left, center, or right");ASSERT(isString(e),"ui text font must be a string");this.text=c;this.align=d;this.font=e;this.lineWidth=0;this.canBeHover=!1}render(){const a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,this.lineWidth,this.lineColor,this.align,this.font,this.fontStyle,!0,this.textShadow)}}class UITile extends UIObject{constructor(a,b,c,d=WHITE,e=0,f=!1){super(a,b);ASSERT(c instanceof TileInfo,"ui tile tileInfo must be a TileInfo");ASSERT(isColor(d),"ui tile color must be a color");ASSERT(isNumber(e),"ui tile angle must be a number");this.tileInfo=c;this.angle=e;this.mirror=f;this.color=d.copy()}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);ASSERT(isString(c),"ui button must be a string");ASSERT(isColor(d),"ui button color must be a color");this.text=c;this.color=d.copy();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,this.fontStyle,!0,this.textShadow)}}class UICheckbox extends UIObject{constructor(a,b,c=!1,d="",e=uiSystem.defaultButtonColor){super(a,b);ASSERT(isString(d),"ui checkbox must be a string");ASSERT(isColor(e),"ui checkbox color must be a color");this.checked=c;this.text=d;this.color=e.copy();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,this.fontStyle,!1,this.textShadow)}}class UIScrollbar extends UIObject{constructor(a,b,c=.5,d="",e=uiSystem.defaultButtonColor,f=WHITE){super(a,b);ASSERT(isNumber(c),"ui scrollbar value must be a number");ASSERT(isString(d),"ui scrollbar must be a string");ASSERT(isColor(e),"ui scrollbar color must be a color");ASSERT(isColor(f),"ui scrollbar handleColor must be a color");this.value=c;this.handleColor=f.copy();this.text=d;this.color=e.copy();this.interactive=!0}update(){super.update();if(this.isActiveObject()&&this.interactive){const c=this.size.x>this.size.y;var a=c?this.pos.x:this.pos.y,b=(c?this.size.x:this.size.y)-(c?this.size.y:this.size.x);const d=a-b/2;a+=b/2;b=this.value;const e=uiSystem.screenToNative(mousePosScreen);this.value=c?percent(e.x,d,a):percent(e.y,a,d);this.value===b||this.onChange()}}render(){super.render();var a=this.size.x>this.size.y,b=a?this.size.y:this.size.x,c=a?this.pos.x:this.pos.y;const d=(a?this.size.x:this.size.y)-b;var e=c-d/2;c+=d/2;a=a?vec2(lerp(e,c,this.value),this.pos.y):vec2(this.pos.x,lerp(c,e,this.value));e=this.disabled?this.disabledColor:this.handleColor;uiSystem.drawRect(a,vec2(b),e,this.lineWidth,this.lineColor,this.cornerRadius,this.gradientColor);b=this.getTextSize();uiSystem.drawText(this.text,this.pos,b,this.textColor,0,void 0,this.align,this.font,this.fontStyle,!0,this.textShadow)}}class UIVideo extends UIObject{constructor(a,b,c,d=!1,e=!1,f=1){super(a,b||vec2());ASSERT(isString(c),"video src must be a string");ASSERT(isNumber(f),"video volume must be a number");this.color=BLACK;this.cornerRadius=0;this.volume=f;this.video=document.createElement("video");this.video.loop=e;this.video.volume=clamp(f*soundVolume);this.video.muted=!soundEnable;this.video.style.display="none";this.video.src=c;document.body.appendChild(this.video);d&&this.play()}play(){const a=this.video.play();a?.catch(()=>{});return a}pause(){this.video.pause()}stop(){this.video.pause();this.video.currentTime=0}isLoadng(){return this.video.readyState<this.video.HAVE_CURRENT_DATA}isPaused(){return this.video.paused}isPlaying(){return!this.isPaused()&&!this.hasEnded()&&!this.isLoadng()}hasEnded(){return this.video.ended}setVolume(a){this.volume=a;this.video.volume=clamp(a*soundVolume)}setPlaybackRate(a){this.video.playbackRate=a}getCurrentTime(){return this.video.currentTime||0}getDuration(){return this.video.duration||0}getVideoSize(){return vec2(this.video.videoWidth,this.video.videoHeight)}setTime(a){this.video.currentTime=clamp(a,0,this.getDuration())}update(){super.update();this.video.volume=clamp(this.volume*soundVolume)}render(){super.render();if(!this.isLoadng()){var a=uiSystem.uiContext,b=this.size;a.save();a.translate(this.pos.x,this.pos.y);a.drawImage(this.video,-b.x/2,-b.y/2,b.x,b.y);a.restore()}}destroy(){this.destroyed||(this.video.pause(),this.video.remove(),super.destroy())}}let box2d,box2dDebug=!1;function box2dSetDebug(a){box2dDebug=a}class Box2dObject extends EngineObject{constructor(a=vec2(),b=vec2(),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;box2d.objects.push(this);this.edgeLists=[];this.edgeLoops=[]}destroy(){this.destroyed||(ASSERT(this.body,"Box2dObject has no body to destroy"),box2d.world.DestroyBody(this.body),super.destroy())}updatePhysics(){}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=BLACK,c=.1,d){this.getFixtureList().forEach(e=>{box2d.castObjectType(e.GetShape()).GetType()!==box2d.instance.b2Shape.e_edge&&box2d.drawFixture(e,this.pos,this.angle,a,b,c,d)});this.edgeLists.forEach(e=>drawLineList(e,c,b,!1,this.pos,this.angle));this.edgeLoops.forEach(e=>drawLineList(e,c,b,!0,this.pos,this.angle))}beginContact(a){}endContact(a){}addShape(a,b=1,c=.2,d=0,e=!1){ASSERT(isNumber(b),"density must be a number");ASSERT(isNumber(c),"friction must be a number");ASSERT(isNumber(d),"restitution must be a number");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){ASSERT(isVector2(a),"size must be a Vector2");ASSERT(0<a.x&&0<a.y,"size must be positive");ASSERT(isVector2(b),"offset must be a Vector2");ASSERT(isNumber(c),"angle must be a number");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(isArray(a),"points must be an array");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){ASSERT(isNumber(a)&&0<a,"diameter must be a positive number");ASSERT(isNumber(b)&&2<b,"sides must be a positive number greater than 2");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){ASSERT(isNumber(a)&&0<a,"diameter must be a positive number");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){ASSERT(isNumber(a)&&0<a,"diameter must be a positive number");ASSERT(isVector2(b),"offset must be a Vector2");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){ASSERT(isVector2(a),"point1 must be a Vector2");ASSERT(isVector2(b),"point2 must be a Vector2");const g=new box2d.instance.b2EdgeShape;g.Set(box2d.vec2dTo(a),box2d.vec2dTo(b));return this.addShape(g,c,d,e,f)}addEdgeList(a,b,c,d,e){ASSERT(isArray(a),"points must be an array");const f=[],g=[];for(let k=0;k<a.length-1;++k){var h=new box2d.instance.b2EdgeShape;a[k-1]&&h.set_m_vertex0(box2d.vec2dTo(a[k-1]));a[k+0]&&h.set_m_vertex1(box2d.vec2dTo(a[k+0]));a[k+1]&&h.set_m_vertex2(box2d.vec2dTo(a[k+1]));a[k+2]&&h.set_m_vertex3(box2d.vec2dTo(a[k+2]));h=this.addShape(h,b,c,d,e);f.push(h);g.push(a[k].copy())}g.push(a[a.length-1].copy());this.edgeLists.push(g);return f}addEdgeLoop(a,b,c,d,e){ASSERT(isArray(a),"points must be an array");const f=[],g=[];for(let k=0;k<a.length;++k){var h=new box2d.instance.b2EdgeShape;h.set_m_vertex0(box2d.vec2dTo(a[mod(k-1,a.length)]));h.set_m_vertex1(box2d.vec2dTo(a[mod(k+0,a.length)]));h.set_m_vertex2(box2d.vec2dTo(a[mod(k+1,a.length)]));h.set_m_vertex3(box2d.vec2dTo(a[mod(k+2,a.length)]));h=this.addShape(h,b,c,d,e);f.push(h);k<a.length&&g.push(a[k].copy())}this.edgeLoops.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()}getSpeed(){return this.getLinearVelocity().length()}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 Box2dStaticObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeStatic,f)}}class Box2dKiematicObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeKinematic,f)}}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),n=b.worldToLocal(f),l=new box2d.instance.b2PulleyJointDef;l.set_bodyA(a.body);l.set_bodyB(b.body);l.set_groundAnchorA(box2d.vec2dTo(c));l.set_groundAnchorB(box2d.vec2dTo(d));l.set_localAnchorA(box2d.vec2dTo(k));l.set_localAnchorB(box2d.vec2dTo(n));l.set_ratio(g);l.set_lengthA(c.distance(e));l.set_lengthB(d.distance(f));l.set_collideConnected(h);super(l)}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.objects=[];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){a=box2d.instance.wrapPointer(a,box2d.instance.b2Vec2);return box2d.vec2From(a)}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(){if(!paused){box2d.step();box2d.objects=box2d.objects.filter(a=>!a.destroyed);for(const a of box2d.objects)a.body&&(a.pos=box2d.vec2From(a.body.GetPosition()),a.angle=-a.body.GetAngle())}},function(){(box2dDebug||debugPhysics)&&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,n,l){const m=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=n?-1:1,q=n?-h:h;drawTile(a,p,m,d,h,!1,f,k,n,l);for(var t=4;t--;){var u=t%2,w=b.multiply(vec2(u?1===t?1:-1:0,u?0:t?-1:1));u=vec2(u?e:p.x,u?p.y:e);const x=m.offset(c.size.multiply(vec2(1===t?1:3===t?-1:0,0===t?-r:2===t?r:0)));drawTile(a.add(w.rotate(q)),u,x,d,h,!1,f,k,n,l)}for(e=4;e--;)t=1<e,w=e&&3>e,p=b.multiply(vec2(t?-1:1,w?-1:1)),t=m.offset(c.size.multiply(vec2(t?-1:1,w?r:-r))),drawTile(a.add(p.rotate(q)),g,t,d,h,!1,f,k,n,l)}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,n,l){const m=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=n?-1:1;const t=n?-h:h;drawTile(a,q,r,d,h,!1,f,k,n,l);for(r=4;r--;){const w=h+r*PI/2;var u=r%2;const x=b.multiply(vec2(u?1===r?1:-1:0,u?0:r?-c:c));u=vec2(u?q.y:q.x,e);drawTile(a.add(x.rotate(t)),u,p,d,w,!1,f,k,n,l)}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(t)),g,m,d,p,!1,f,k,n,l)}
|
|
4
|
+
const engineName="LittleJS",engineVersion="1.15.3",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 pluginList=[];class EnginePlugin{constructor(a,b,c,d){this.update=a;this.render=b;this.glContextLost=c;this.glContextRestored=d}}function engineAddPlugin(a,b,c,d){ASSERT(!pluginList.find(f=>f.update===a&&f.render===b&&f.glContextLost===c&&f.glContextRestored===d));const e=new EnginePlugin(a,b,c,d);pluginList.push(e)}async function engineInit(a,b,c,d,e,f=[],g=document.body){function h(l=0){function m(){if(!headlessMode){q||k();mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);overlayContext.imageSmoothingEnabled=mainContext.imageSmoothingEnabled=!tilesPixelated;glPreRender();d();engineObjects.sort((u,w)=>u.renderOrder-w.renderOrder);for(var t of engineObjects)t.destroyed||t.render();e();pluginList.forEach(u=>u.render?.());touchGamepadRender();debugRender();glFlush();debugVideoCaptureUpdate();showWatermark&&!debugVideoCaptureIsActive()&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",t=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(t,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(t,mainCanvas.width-2,2));drawCount=0}}var p=l-frameTimeLastMS;frameTimeLastMS=l;if(debug||showWatermark)averageFPS=lerp(averageFPS,1e3/(p||1),.05);l=debug&&keyIsDown("Equal");const r=debug&&keyIsDown("Minus");debug&&(p*=l?10:r?.1:1);timeReal+=p/1e3;frameTimeBufferMS+=paused?0:p;l||(frameTimeBufferMS=min(frameTimeBufferMS,50));let q=!1;if(paused){q=!0;k();inputUpdate();pluginList.forEach(t=>t.update?.());for(const t of engineObjects)t.parent||t.updateTransforms();debugUpdate();c();inputUpdatePost()}else{p=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(p=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,q=!0,k(),inputUpdate(),b(),pluginList.forEach(t=>t.update?.()),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost(),debugVideoCaptureIsActive()&&m();frameTimeBufferMS+=p}debugVideoCaptureIsActive()||m();requestAnimationFrame(h)}function k(){if(!headlessMode){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const l=innerWidth/innerHeight,m=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=l<m?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=l<m?"":"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 n(){await a();h()}ASSERT(!mainContext,"engine already initialized");ASSERT(isArray(f),"pass in images as array");a||=()=>{};b||=()=>{};c||=()=>{};d||=()=>{};e||=()=>{};if(headlessMode)return n();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((l,m)=>new Promise(p=>{ASSERT(isString(l),"imageSources must be an array of strings");const r=new Image;r.onerror=r.onload=()=>{const q=new TextureInfo(r);textureInfos[m]=q;p()};r.crossOrigin="anonymous";r.src=l}));f.length||g.push(new Promise(l=>{const m=new TextureInfo(new Image);textureInfos[0]=m;l()}));showSplashScreen&&g.push(new Promise(l=>{function m(){inputClear();drawEngineSplashScreen(p+=.01);1<p?l():setTimeout(m,16)}let p=0;console.log(`${engineName} Engine v${engineVersion}`);m()}));await Promise.all(g);return n()}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)if(!b.parent){b.update();b.updatePhysics();for(const c of b.children)a(c);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)e.isOverlapping(a,b)&&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*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,n,l,m,p)=>{b.beginPath();b.rect(k,n,l,p?m*h:m);(b.fillStyle=p)?b.fill():b.stroke()};f=(k,n,l,m=0,p=2*PI,r,q)=>{const t=(m+p)/2;m=h*(p-m)/2;b.beginPath();q&&b.lineTo(k,n);b.arc(k,n,l,t-m,t+m);(b.fillStyle=r)?b.fill():b.stroke()};e=(k=0,n=0)=>hsl([.98,.3,.57,.14][k%4]-10,.8,[0,.3,.5,.8,.9][n]).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,n=41-g/2;k<f.length;++k)b.fillStyle=e(k,2),d=b.measureText(f[k]).width,b[c?"strokeText":"fillText"](f[k],n+d/2,55.5,17*h),n+=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 LOG(){}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(){}function debugProtectConstant(a){return a}const PI=Math.PI,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,min=Math.min,max=Math.max,sign=Math.sign,hypot=Math.hypot,log2=Math.log2,sin=Math.sin,cos=Math.cos,tan=Math.tan,atan2=Math.atan2;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**ceil(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-cos(d+c*a*2*PI))}function formatTime(a){const b=0>a?"-":"";a=abs(a)|0;return b+(a/60|0)+":"+(10>a%60?"0":"")+a%60}async function fetchJSON(a){const b=await fetch(a);if(!b.ok)throw Error(`Failed to fetch JSON from ${a}: ${b.status} ${b.statusText}`);return b.json()}function isNumber(a){return"number"===typeof a&&!isNaN(a)}function isString(a){return void 0!==a&&null!==a&&"string"===typeof a.toString()}function isArray(a){return Array.isArray(a)}function lineTest(a,b,c,d){ASSERT(isVector2(a),"posStart must be a vec2");ASSERT(isVector2(b),"posEnd must be a vec2");ASSERT("function"===typeof c,"testFunction must be a function");ASSERT(!d||isVector2(d),"normal must be a vec2");var e=b.x-a.x,f=b.y-a.y;if(b=hypot(e,f)){var g=a.floor();e/=b;var h=f/b;f=sign(e);var k=sign(h),n=e?abs(1/e):Infinity,l=h?abs(1/h):Infinity,m=0<f?g.x+1:g.x,p=0<k?g.y+1:g.y,r=0;m=e?(m-a.x)/e:Infinity;var q=h?(p-a.y)/h:Infinity;for(p=n<l;r<b;){if(c(g))return a=vec2(a.x+e*r,a.y+h*r),p&&0>f&&(a.x-=1e-9),0>k&&(a.y-=1e-9),d&&(p?d.set(-f,0):d.set(0,-k)),a;(p=m<q)?(g.x+=f,r=m,m+=n):(g.y+=k,r=q,q+=l)}}}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return 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 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))}randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return c?a.lerp(b,this.float()):new Color(this.float(a.r,b.r),this.float(a.g,b.g),this.float(a.b,b.b),this.float(a.a,b.a))}mutateColor(a,b=.05,c=0){ASSERT_NUMBER_VALID(b);ASSERT_NUMBER_VALID(c);return new Color(a.r+this.float(b,-b),a.g+this.float(b,-b),a.b+this.float(b,-b),a.a+this.float(c,-c)).clamp()}}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 atan2(this.x,this.y)}setAngle(a=0,b=1){ASSERT_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);this.x=b*sin(a);this.y=b*cos(a);return this}rotate(a){ASSERT_NUMBER_VALID(a);const b=cos(-a);a=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.");this.x=a%2?a-1?-b:b:0;this.y=a%2?0:a?-b:b;return this}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}abs(){return new Vector2(abs(this.x),abs(this.y))}floor(){return new Vector2(floor(this.x),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);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 n=e-f;k=.5<g?n/(2-e-f):n/(e+f);a===e?h=(b-c)/n+(b<c?6:0):b===e?h=(c-a)/n+2:c===e&&(h=(a-b)/n+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){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(isString(a),"Color hex code must be a string");ASSERT("#"===a[0],"Color hex code must start 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=debugProtectConstant(rgb()),CLEAR_WHITE=debugProtectConstant(rgb(1,1,1,0)),BLACK=debugProtectConstant(rgb(0,0,0)),CLEAR_BLACK=debugProtectConstant(rgb(0,0,0,0)),GRAY=debugProtectConstant(rgb(.5,.5,.5)),RED=debugProtectConstant(rgb(1,0,0)),ORANGE=debugProtectConstant(rgb(1,.5,0)),YELLOW=debugProtectConstant(rgb(1,1,0)),GREEN=debugProtectConstant(rgb(0,1,0)),CYAN=debugProtectConstant(rgb(0,1,1)),BLUE=debugProtectConstant(rgb(0,0,1)),PURPLE=debugProtectConstant(rgb(.5,0,1)),MAGENTA=debugProtectConstant(rgb(1,0,1));class Timer{constructor(a,b=!1){ASSERT(void 0===a||isNumber(a),"Constructed Timer is invalid.",a);this.useRealTime=b;b=this.getGlobalTime();this.time=void 0===a?void 0:b+a;this.setTime=a}set(a=0){ASSERT(isNumber(a),"Timer is invalid.",a);this.time=this.getGlobalTime()+a;this.setTime=a}setUseRealTime(a=!0){ASSERT(!this.isSet(),"Cannot change global time setting while timer is set.");this.useRealTime=a}unset(){this.time=void 0}isSet(){return void 0!==this.time}active(){return this.getGlobalTime()<this.time}elapsed(){return this.getGlobalTime()>=this.time}get(){return this.isSet()?this.getGlobalTime()-this.time:0}getPercent(){return this.isSet()?1-percent(this.time-this.getGlobalTime(),0,this.setTime):0}getSetTime(){return this.isSet()?this.setTime:0}getGlobalTime(){return this.useRealTime?timeReal:time}toString(){return this.isSet()?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,touchGamepadCenterButton=!0,touchGamepadAnalog=!0,touchGamepadButtonCount=4,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.copy()}function setCameraAngle(a){cameraAngle=a}function setCameraScale(a){cameraScale=a}function setCanvasColorTiles(a){canvasColorTiles=a}function setCanvasClearColor(a){canvasClearColor=a.copy()}function setCanvasMaxSize(a){canvasMaxSize=a.copy()}function setCanvasFixedSize(a){canvasFixedSize=a.copy()}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){a&&!glCanBeEnabled?console.warn("Can not enable WebGL if it was disabled on start."):(glEnable=a,glCanvas&&(glCanvas.style.display=a?"":"none"))}function setGLCircleSides(a){glCircleSides=a}function setTileSizeDefault(a){tileSizeDefault=a.copy()}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.copy()}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 setTouchGamepadCenterButton(a){touchGamepadCenterButton=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.copy()}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=WHITE,f=0){ASSERT(isVector2(a),"object pos must be a vec2");ASSERT(isVector2(b),"object size must 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()}updatePhysics(){ASSERT(!this.parent);this.clampSpeed&&(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed));const 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(!this.isOverlappingObject(e))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)){c=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);if(d=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this)){f=floor(a.y-this.size.y/2+1)+this.size.y/2+.001;if(.1>f-this.pos.y&&!tileCollisionTest(vec2(this.pos.x,f),this.size,this)){this.pos.y=f;debugPhysics&&debugRect(this.pos,this.size,"#ff0");return}this.pos.x=a.x;this.velocity.x*=-this.restitution}if(c||!d)c=max(this.restitution,e.restitution),this.velocity.y*=-c,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);debugPhysics&&debugRect(this.pos,this.size,"#f00")}}}update(){}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}getUp(a=1){return vec2().setAngle(this.angle,a)}getRight(a=1){return vec2().setAngle(this.angle+PI/2,a)}getAliveTime(){return time-this.spawnTime}getSpeed(){return this.velocity.length()}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));ASSERT(a instanceof EngineObject,"child must be an EngineObject");ASSERT(a!==this,"cannot add self as child");this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent===this&&this.children.includes(a));ASSERT(a instanceof EngineObject,"child must be an EngineObject");const b=this.children.indexOf(a);ASSERT(0<=b,"child not found in children array");0<=b&&this.children.splice(b,1);a.parent=0}isOverlappingObject(a){return this.isOverlapping(a.pos,a.size)}isOverlapping(a,b=vec2()){return isOverlapping(this.pos,this.size,a,b)}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){this.pos=new Vector2;this.size=a.size.copy();this.textureInfo=a;this.bleedScale=this.padding=0;return this}}class TextureInfo{constructor(a,b=!0){this.size=(this.image=a)?vec2(a.width,a.height):vec2();this.sizeInverse=a?vec2(1/a.width,1/a.height):vec2();this.glTexture=void 0;b&&this.createWebGLTexture()}createWebGLTexture(){glRegisterTextureInfo(this)}destroyWebGLTexture(){glUnregisterTextureInfo(this)}hasWebGL(){return!!this.glTexture}}function drawTile(a,b=new Vector2(1),c,d=WHITE,e=0,f,g,h=glEnable,k,n){ASSERT(isVector2(a),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(d),"color is invalid");ASSERT(isNumber(e),"angle must be a number");ASSERT(!g||isColor(g),"additiveColor must be a color");ASSERT(!n||!h,"context only supported in canvas 2D mode");const l=c&&c.textureInfo,m=c?c.bleedScale:0;if(h&&glEnable)if(ASSERT(!!glContext,"WebGL is not enabled!"),k&&([a,b,e]=screenToWorldTransform(a,b,e)),l){var p=l.sizeInverse;h=c.pos.x*p.x;k=c.pos.y*p.y;n=c.size.x*p.x;const r=c.size.y*p.y;glSetTexture(l.glTexture);if(m){const q=p.x*m;p=p.y*m;glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+q,k+p,h-q+n,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+n,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(l)drawImageColor(r,l.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1,d,g,m);else{const q=g?d.add(g):d;r.fillStyle=q.toString();r.fillRect(-.5,-.5,1,1)}},k,n)}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),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(c)&&isColor(d),"color is invalid");ASSERT(isNumber(e),"angle must be a number");ASSERT(!h||!f,"context only supported in canvas 2D mode");if(f&&glEnable){ASSERT(!!glContext,"WebGL is not enabled!");g&&(a=screenToWorld(a),b=b.scale(1/cameraScale),e+=cameraAngle);f=[];g=[];h=b.x/2;b=b.y/2;const k=c.rgbaInt(),n=d.rgbaInt(),l=cos(-e);e=sin(-e);for(let m=4;m--;){const p=m&1?h:-h,r=m&2?b:-b,q=m&2?k:n;f.push(vec2(a.x+(p*l-r*e),a.y+(p*e+r*l)));g.push(q)}glDrawColoredPoints(f,g)}else++drawCount,b=new Vector2(b.x,-b.y),drawCanvas2D(a,b,e,!1,k=>{const n=k.createLinearGradient(0,-.5,0,.5);n.addColorStop(0,c.toString());n.addColorStop(1,d.toString());k.fillStyle=n;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(isArray(a),"points must be an array");ASSERT(isNumber(b),"width must be a number");ASSERT(isColor(c),"color is invalid");ASSERT(isVector2(e),"pos must be a vec2");ASSERT(isNumber(f),"angle must be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g&&glEnable?(ASSERT(!!glContext,"WebGL is not enabled!"),g=vec2(1),h&&([e,g,f]=screenToWorldTransform(e,g,f)),glDrawOutlineTransform(a,c.rgbaInt(),b,e.x,e.y,g.x,g.y,f,d)):(++drawCount,drawCanvas2D(e,vec2(1),f,!1,n=>{n.strokeStyle=c.toString();n.lineWidth=b;n.beginPath();for(let l=0;l<a.length;++l){const m=a[l];l?n.lineTo(m.x,m.y):n.moveTo(m.x,m.y)}d&&n.closePath();n.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));h&&(b.y*=-1);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,n){ASSERT(isVector2(b),"size must be a vec2");ASSERT(isNumber(c),"sides must be a number");const l=[],m=b.x/2;b=b.y/2;for(let p=c;p--;){const r=p/c*PI*2;l.push(vec2(sin(r)*m,cos(r)*b))}drawPoly(l,d,e,f,a,g,h,k,n)}function drawPoly(a,b=WHITE,c=0,d=BLACK,e=vec2(),f=0,g=glEnable,h=!1,k){ASSERT(isVector2(e),"pos must be a vec2");ASSERT(isArray(a),"points must be an array");ASSERT(isColor(b)&&isColor(d),"color is invalid");ASSERT(isNumber(c),"lineWidth must be a number");ASSERT(isNumber(f),"angle must be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g&&glEnable?(ASSERT(!!glContext,"WebGL is not enabled!"),g=vec2(1),h&&([e,g,f]=screenToWorldTransform(e,g,f)),glDrawPointsTransform(a,b.rgbaInt(),e.x,e.y,g.x,g.y,f),0<c&&glDrawOutlineTransform(a,d.rgbaInt(),c,e.x,e.y,g.x,g.y,f)):drawCanvas2D(e,vec2(1),f,!1,n=>{n.fillStyle=b.toString();n.beginPath();for(const l of a)n.lineTo(l.x,l.y);n.closePath();n.fill();c&&(n.strokeStyle=d.toString(),n.lineWidth=c,n.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),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(c)&&isColor(f),"color is invalid");ASSERT(isNumber(d),"angle must be a number");ASSERT(isNumber(e),"lineWidth must be a number");ASSERT(0<=e&&e<b.x&&e<b.y,"invalid lineWidth");ASSERT(!k||!g,"context only supported in canvas 2D mode");g&&glEnable?drawRegularPoly(a,b,glCircleSides,c,e,f,d,g,h,k):drawCanvas2D(a,vec2(1),d,!1,n=>{n.fillStyle=c.toString();n.beginPath();n.ellipse(0,0,b.x/2,b.y/2,0,0,9);n.fill();e&&(n.strokeStyle=f.toString(),n.lineWidth=e,n.stroke())},h,k)}function drawCircle(a,b=1,c=WHITE,d=0,e=BLACK,f=glEnable,g=!1,h){ASSERT(isNumber(b),"size must 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){ASSERT(isVector2(a),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isNumber(c),"angle must be a number");ASSERT("function"===typeof e,"drawFunction must be a function");f||([a,b,c]=worldToScreenTransform(a,b,c));g.save();g.translate(a.x+.5,a.y+.5);g.rotate(c);g.scale(d?-b.x:b.x,-b.y);e(g);g.restore()}function drawText(a,b,c=1,d,e=0,f,g,h,k,n,l=0,m=drawContext){b=worldToScreen(b);c*=cameraScale;e*=cameraScale;l-=cameraAngle;drawTextScreen(a,b,c,d,e,f,g,h,k,n,-1*l,m)}function drawTextOverlay(a,b,c=1,d,e=0,f,g,h,k,n,l=0){drawText(a,b,c,d,e,f,g,h,k,n,l,overlayContext)}function drawTextScreen(a,b,c=1,d=WHITE,e=0,f=BLACK,g="center",h=fontDefault,k="",n,l=0,m=overlayContext){ASSERT(isString(a),"text must be a string");ASSERT(isVector2(b),"pos must be a vec2");ASSERT(isNumber(c),"size must be a number");ASSERT(isColor(d),"color must be a color");ASSERT(isNumber(e),"lineWidth must be a number");ASSERT(isColor(f),"lineColor must be a color");ASSERT(["left","center","right"].includes(g),"align must be left, center, or right");ASSERT(isString(h),"font must be a string");ASSERT(isString(k),"fontStyle must be a string");ASSERT(isNumber(l),"angle must be a number");m.fillStyle=d.toString();m.strokeStyle=f.toString();m.lineWidth=e;m.textAlign=g;m.font=k+" "+c+"px "+h;m.textBaseline="middle";a=(a+"").split("\n");d=b.y-(a.length-1)*c/2;m.save();m.translate(b.x,d);m.rotate(-l);let p=0;a.forEach(r=>{e&&m.strokeText(r,0,p,n);m.fillText(r,0,p,n);p+=c});m.restore()}function screenToWorld(a){let b=(a.x-mainCanvasSize.x/2+.5)/cameraScale;a=(a.y-mainCanvasSize.y/2+.5)/-cameraScale;if(cameraAngle){const c=cos(-cameraAngle),d=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=cos(cameraAngle),d=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 screenToWorldDelta(a){let b=a.x/cameraScale;a=a.y/-cameraScale;if(cameraAngle){const c=cos(-cameraAngle),d=sin(-cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b,a)}function worldToScreenDelta(a){let b=a.x;a=a.y;if(cameraAngle){const c=cos(cameraAngle),d=sin(cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b*cameraScale,a*-cameraScale)}function screenToWorldTransform(a,b,c=0){return[screenToWorld(a),b.scale(1/cameraScale),c+cameraAngle]}function worldToScreenTransform(a,b,c=0){return[worldToScreen(a),b.scale(cameraScale),c-cameraAngle]}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,n,l,m,p=0){function r(u){return 1<=u.r&&1<=u.g&&1<=u.b}e=max(1,e|0);f=max(1,f|0);const q=e-2*p,t=f-2*p;if(!canvasColorTiles||(m?r(l.add(m))&&0>=m.a:r(l)))a.globalAlpha=l.a,a.drawImage(b,c+p,d+p,q,t,g,h,k,n),a.globalAlpha=1;else if(workCanvas.width=e,workCanvas.height=f,workContext.drawImage(b,c|0,d|0,e,f,0,0,e,f),b=workContext.getImageData(0,0,e,f),c=b.data,!m||0>=m.r&&0>=m.g&&0>=m.b&&0>=m.a){for(m=0;m<c.length;m+=4)c[m]*=l.r,c[m+1]*=l.g,c[m+2]*=l.b;workContext.putImageData(b,0,0);a.globalAlpha=l.a;a.drawImage(workCanvas,p,p,q,t,g,h,k,n);a.globalAlpha=1}else{l=[l.r,l.g,l.b,l.a];m=[255*m.r,255*m.g,255*m.b,255*m.a];for(d=0;d<c.length;++d)c[d]=c[d]*l[d&3]+m[d&3]|0;workContext.putImageData(b,0,0);a.drawImage(workCanvas,p,p,q,t,g,h,k,n)}}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)){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=!0,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,n)=>{const l=d?k.length*f.x*c/2|0:0;for(let r=k.length;r--;){var m=k[r].charCodeAt(0);if(32>m||127<m)m=127;var p=m-32;m=p%h;p=p/h|0;const q=b.add(vec2(r,n).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,q.x-l,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,mouseInWindow=!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=screenToWorldDelta(mouseDeltaScreen),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){if(!isTouchDevice||!touchInputEnable){soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioContext.resume();isUsingGamepad=!1;inputData[0][b.button]=3;var c=mousePosScreen;mousePosScreen=mouseEventToScreen(vec2(b.x,b.y));mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(c));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){mouseInWindow=!0;const c=mousePosScreen;mousePosScreen=mouseEventToScreen(vec2(b.x,b.y));b=pointerLockIsActive()?vec2(b.movementX,b.movementY):mousePosScreen.subtract(c);mouseDeltaScreen=mouseDeltaScreen.add(b)}),document.addEventListener("mouseleave",function(){mouseInWindow=!1}),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(){var a=f=>{const g=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;return vec2(g(f.x),g(-f.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice){if(touchGamepadTimer.isSet()){var b=gamepadStickData[0]||(gamepadStickData[0]=[]);b[0]=vec2();touchGamepadAnalog?b[0]=a(touchGamepadStick):.3<touchGamepadStick.lengthSquared()&&(b[0].x=round(touchGamepadStick.x),b[0].y=-round(touchGamepadStick.y),b[0]=b[0].clampLength());a=inputData[1]||(inputData[1]=[]);for(b=10;b--;){var c=gamepadIsDown(b,0);a[b]=touchGamepadButtons[b]?c?1:3:c?4:0}}}else if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){var d=b[c];const f=inputData[c+1]||(inputData[c+1]=[]),g=gamepadStickData[c]||(gamepadStickData[c]=[]);if(d){for(var e=0;e<d.axes.length-1;e+=2)g[e>>1]=a(vec2(d.axes[e],d.axes[e+1]));for(e=d.buttons.length;e--;){const h=d.buttons[e],k=gamepadIsDown(e,c);f[e]=h.pressed?k?1:3:k?4:0;(!h.value||.9<h.value)&&!c&&h.pressed&&(isUsingGamepad=!0)}gamepadDirectionEmulateStick&&(d=vec2((gamepadIsDown(15,c)&&1)-(gamepadIsDown(14,c)&&1),(gamepadIsDown(12,c)&&1)-(gamepadIsDown(13,c)&&1)),d.lengthSquared()&&(g[0]=d.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 touchGamepadButtonCenter(){const a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);2>=touchGamepadButtonCount&&(a.x+=touchGamepadSize/2);return a}function touchInputInit(){function a(c){if(touchInputEnable){if(touchGamepadEnable)a:{touchGamepadStick=vec2();touchGamepadButtons=[];isUsingGamepad=!0;if(c.touches.length&&(touchGamepadTimer.set(),touchGamepadCenterButton&&!b&&paused)){touchGamepadButtons[9]=1;break a}var d=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),e=touchGamepadButtonCenter(),f=mainCanvasSize.scale(.5);for(const h of c.touches){var g=mouseEventToScreen(vec2(h.clientX,h.clientY));if(d.distance(g)<touchGamepadSize)touchGamepadStick=g.subtract(d).scale(2/touchGamepadSize).clampLength();else if(e.distance(g)<touchGamepadSize){let k=e.subtract(g).direction();k=mod(k+2,4);1===touchGamepadButtonCount?k=0:2===touchGamepadButtonCount&&(g=e.subtract(g),k=-g.x<g.y?1:0);k=3===k?2:2===k?3:k;k<touchGamepadButtonCount&&(touchGamepadButtons[k]=1)}else touchGamepadCenterButton&&!b&&f.distance(g)<touchGamepadSize&&(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.cancelable&&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=touchGamepadButtonCenter();c=1<touchGamepadButtonCount?touchGamepadSize/4:touchGamepadSize/2;for(d=0;d<touchGamepadButtonCount;d++){var e=mod(d-1,4);let f=2<touchGamepadButtonCount?e:min(e,touchGamepadButtonCount-1);f=3===f?2:2===f?3:f;e=a.add(vec2().setDirection(e,touchGamepadSize/2));b.fillStyle=touchGamepadButtons[f]?"#fff":"#000";b.beginPath();b.arc(e.x,e.y,c,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&&(ASSERT(!a||isArray(a),"zzfxSound is invalid"),ASSERT(isNumber(b),"range must be a number"),ASSERT(isNumber(c),"taper must be a number"),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){ASSERT(!a||isVector2(a),"pos must be a vec2");ASSERT(isNumber(b),"volume must be a number");ASSERT(isNumber(c),"pitch must be a number");ASSERT(isNumber(d),"randomnessScale must be a number");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=0,b,c){ASSERT(isNumber(a),"semitoneOffset must be a number");a=getNoteFrequency(a,1);return this.play(b,c,a,0)}getDuration(){return this.sampleChannels&&this.sampleRate?this.sampleChannels[0].length/this.sampleRate:0}isLoaded(){return 1===this.loadedPercent}}class SoundWave extends Sound{constructor(a,b=0,c,d,e){super(void 0,c,d);soundEnable&&!headlessMode&&(ASSERT(!a||isString(a),"filename must be a string"),ASSERT(isNumber(b),"randomness must be a number"),this.onloadCallback=e,this.randomness=b,a&&this.loadSound(a))}async loadSound(a){var b=await fetch(a);if(!b.ok)throw Error(`Failed to load sound from ${a}: ${b.status} ${b.statusText}`);a=await b.arrayBuffer();a=await audioContext.decodeAudioData(a);b=a.numberOfChannels;const 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(this)}}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):(this.startTime=void 0,this.pausedTime=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.rate?this.sound.getDuration()/this.rate:0}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){if(audioIsRunning()){var n=audioContext.createBuffer(a.length,a[0].length,f),l=audioContext.createBufferSource();a.forEach((m,p)=>n.getChannelData(p).set(m));l.buffer=n;l.playbackRate.value=c;l.loop=e;g=g||audioContext.createGain();g.gain.value=b;g.connect(audioMasterGain);a=new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)});l.connect(a).connect(g);k&&l.addEventListener("ended",()=>k(l));l.start(0,h*c);return l}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,n=0,l=0,m=0,p=0,r=0,q=0,t=0,u=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=cos(M),N=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;u*=v;n*=500*y/v**3;q*=y/v;l*=y/v;m*=v;p=p*v|0;for(v=d+x+e+f+u|0;A<v;K[A++]=C*a)++H%(100*t|0)||(C=g?1<g?2<g?3<g?4<g?F/y%1<h/2?1:-1:sin(F**3):max(min(tan(F),1),-1):1-(2*F/y%2+2)%2:1-4*abs(round(F/y)-F/y):sin(F),C=(p?1-B+B*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-u?(v-A-u)/f*w:0),C=u?C/2+(u>A?0:(A<v-u?1:(v-A)/u)*K[A-u|0]/2/a):C,z&&(C=S=P*I+L*(I=Q)+P*(Q=C)-N*R-M*(R=S))),O=(c+=k+=n)*cos(q*G++),F+=O+O*r*sin(A**5),E&&++E>m&&(c+=l,b+=l,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,e=!0){for(const f of tileCollisionLayers)if(!e||f.isSolid){const g=f.collisionRaycast(a,b,c,d);if(g)return g}}function tileLayersLoad(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 l=h;l--;){const m=a.layers[l];ASSERT(m.data&&m.data.length);ASSERT(g.area()===m.data.length);var k=c-(h-1-l);k=new TileCollisionLayer(vec2(),g,b,k);f[l]=k;const p=m.tintcolor?(new Color).setHex(m.tintcolor):m.color||WHITE;ASSERT(isColor(p),"layer color is not a color");for(let r=g.x;r--;)for(let q=g.y;q--;){const t=vec2(r,g.y-1-q);var n=m.data[r+q*g.x];n&&(n=new TileLayerData(n-1,0,!1,p),k.setData(t,n),l===d&&k.setCollisionData(t,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)){ASSERT(isVector2(e),"canvasSize must be a Vector2");super(a,b,void 0,c,WHITE,d);this.canvas=headlessMode?void 0:new OffscreenCanvas(e.x,e.y);this.context=this.canvas?.getContext("2d");this.textureInfo=new TextureInfo(this.canvas,!1);this.refreshWebGL=!1;this.mass=this.gravityScale=this.friction=this.restitution=0}destroy(){this.destroyed||(this.textureInfo.destroyWebGLTexture(),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&&this.textureInfo.hasWebGL();k&&this.refreshWebGL&&(this.textureInfo.createWebGLTexture(),this.refreshWebGL=!1);const n=(new TileInfo).setFullImage(this.textureInfo);drawTile(a,b,n,d,c,e,f,k,g,h)}drawCanvas2D(a,b,c,d,e){if(this.context){var 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.toString(),g.fillRect(-.5,-.5,1,1))})}drawRect(a,b,c,d){this.drawTile(a,b,void 0,c,d)}useWebGL(a=!0,b=!1){!b&&a&&this.textureInfo.hasWebGL()?this.refreshWebGL=!0:a?this.textureInfo.createWebGLTexture():this.textureInfo.destroyWebGLTexture()}}class TileLayer extends CanvasLayer{constructor(a,b,c=tile(),d=0){const e=c?b.multiply(c.size):b;super(a,b,0,d,e);this.tileInfo=c;this.data=[];for(a=this.size.area();a--;)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){ASSERT(isVector2(a),"layerPos must be a Vector2");ASSERT(b instanceof TileLayerData,"data must be a TileLayerData");a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){ASSERT(isVector2(a),"layerPos must be a Vector2");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!");this.refreshWebGL&&(this.textureInfo.createWebGLTexture(),this.refreshWebGL=!1);const a=(new TileInfo).setFullImage(this.textureInfo),b=this.drawSize||this.size,c=this.pos.add(b.scale(.5)),d=glEnable&&this.textureInfo.hasWebGL();drawTile(c,b,a,WHITE,0,!1,CLEAR_BLACK,d)}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.useWebGL()}redrawStart(a=!1){if(this.context){this.savedRenderSettings=[drawCanvas,drawContext,mainCanvasSize,cameraPos,cameraScale];drawCanvas=this.canvas;drawContext=this.context;cameraPos=this.size.scale(.5);var b=this.tileInfo?this.tileInfo.size:vec2(1);cameraScale=b.x;mainCanvasSize=this.size.multiply(b);a&&(drawCanvas.width=mainCanvasSize.x,drawCanvas.height=mainCanvasSize.y);this.context.imageSmoothingEnabled=!tilesPixelated;glPreRender()}}redrawEnd(){this.context&&(ASSERT(drawContext===this.context,"must call redrawStart() before drawing tiles"),glCopyToContext(drawContext),[drawCanvas,drawContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings)}drawTileData(a,b=!0){if(this.context){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){super(a,b.floor(),c,d);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");0<=a&&tileCollisionLayers.splice(a,1);super.destroy()}}initCollision(a){ASSERT(isVector2(a),"size must be a Vector2");this.size=a.floor();this.collisionData=[];this.collisionData.length=a.area();this.collisionData.fill(0)}setCollisionData(a,b=1){ASSERT(isVector2(a),"gridPos must be a Vector2");const c=(a.y|0)*this.size.x+a.x|0;a.arrayCheck(this.size)&&(this.collisionData[c]=b)}getCollisionData(a){ASSERT(isVector2(a),"gridPos must be a Vector2");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){ASSERT(isVector2(a)&&isVector2(b),"pos and size must be Vector2s");ASSERT(!c||c instanceof EngineObject,"object must be an EngineObject");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+this.pos.x,f+this.pos.y))))return!0}return!1}collisionRaycast(a,b,c,d){ASSERT(isVector2(a)&&isVector2(b),"positions must be Vector2s");ASSERT(!c||c instanceof EngineObject,"object must be an EngineObject");const e=new Vector2;debugRaycast&&debugLine(a,b,"#00f",.02);if(b=lineTest(a,b,f=>{e.set(f.x-this.pos.x,f.y-this.pos.y);const g=this.getCollisionData(e);return g&&(!c||c.collideWithTile(g,f))},d)){const f=b.floor().add(vec2(.5));debugRaycast&&debugRect(f,vec2(1),"#f008");debugRaycast&&debugLine(a,b,"#f00",.02);debugRaycast&&debugPoint(b,"#0f0");debugRaycast&&d&&debugLine(b,b.add(d),"#ff0",.02);return b}}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=WHITE,k=WHITE,n=CLEAR_WHITE,l=CLEAR_WHITE,m=.5,p=.1,r=1,q=.1,t=.05,u=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 instanceof Vector2?c.copy():c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h.copy();this.colorStartB=k.copy();this.colorEndA=n.copy();this.colorEndB=l.copy();this.randomColorLinear=G;this.particleTime=m;this.sizeStart=p;this.sizeEnd=r;this.speed=q;this.angleSpeed=t;this.damping=u;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.velocityInheritance=this.emitTimeBuffer=0;this.previousAngle=this.angle;this.previousPos=this.pos.copy()}updatePhysics(){}update(){if(this.velocityInheritance){var a=this.velocityInheritance;this.velocity.x=a*(this.pos.x-this.previousPos.x);this.velocity.y=a*(this.pos.y-this.previousPos.y);this.angleVelocity=a*(this.angle-this.previousAngle);this.previousAngle=this.angle;this.previousPos.x=this.pos.x;this.previousPos.y=this.pos.y}if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(this.emitRate&&particleEmitRateScale)for(a=1/this.emitRate/particleEmitRateScale,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=m=>m+m*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 n=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a=new Particle(a,this.tileInfo,b,n,l,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&&0<this.velocityInheritance&&(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,n,l,m,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEnd=e;this.lifeTime=f;this.sizeStart=g;this.sizeEnd=h;this.fadeRate=k;this.additive=n;this.trailScale=l;this.localSpaceEmitter=m;this.destroyCallback=p;this.clampSpeed=!1}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)}0<this.lifeTime&&time-this.spawnTime>this.lifeTime&&(a=this.colorEnd,this.color.set(a.r,a.g,a.b,a.a),this.size.set(this.sizeEnd,this.sizeEnd),this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}render(){var a=0<this.lifeTime?min((time-this.spawnTime)/this.lifeTime,1):1,b=1-a;const c=vec2(b*this.sizeStart+a*this.sizeEnd);this.color.r=b*this.colorStart.r+a*this.colorEnd.r;this.color.g=b*this.colorStart.g+a*this.colorEnd.g;this.color.b=b*this.colorStart.b+a*this.colorEnd.b;this.color.a=b*this.colorStart.a+a*this.colorEnd.a;b=this.fadeRate/2;this.color.a*=a<b?a/b:a>1-b?(1-a)/b:1;this.additive&&setBlendMode(!0);a=this.pos;b=this.angle;if(this.localSpaceEmitter){var d=this.localSpaceEmitter.angle,e=cos(d);d=sin(d);a=this.localSpaceEmitter.pos.add(new Vector2(a.x*e-a.y*d,a.x*d+a.y*e));b+=this.localSpaceEmitter.angle}if(this.trailScale){if(e=this.localSpaceEmitter?this.velocity.rotate(-this.localSpaceEmitter.angle):this.velocity,d=e.length())c.y=max(c.x,d*this.trailScale),b=atan2(e.x,e.y),drawTile(a,c,this.tileInfo,this.color,b,this.mirror)}else drawTile(a,c,this.tileInfo,this.color,b,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(a,c,"#f005",0,b)}}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;var f=hsl(0,0,.9);b.save();b.beginPath();b.fillStyle=f.toString();b.strokeStyle=BLACK.toString();b.lineWidth=3;b.rect(e,a,c,d);b.fill();b.stroke();b.clip();f=vec2(.1,.05).scale(d);const 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,void 0,c);e.y=a+d-2*f.y-k/2;drawTextScreen(this.description,e,k,BLACK,0,void 0,"left",void 0,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,glTextureInfos,glCanBeEnabled=!0;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(){function a(){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 b=new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);glPositionData=new Float32Array(b);glColorData=new Uint32Array(b);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();b=new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,b,glContext.STATIC_DRAW)}glTextureInfos=new Set;!glEnable||headlessMode?glCanBeEnabled=!1:(glCanvas=document.createElement("canvas"),(glContext=glCanvas.getContext("webgl2",{antialias:glAntialias}))?(mainCanvas.parentElement.appendChild(glCanvas),a(),glCanvas.addEventListener("webglcontextlost",b=>{glEnable=!1;glCanvas.style.display="none";b.preventDefault();LOG("WebGL context lost! Switching to Canvas2d rendering.");for(const c of glTextureInfos)c.glTexture=void 0;glActiveTexture=void 0;pluginList.forEach(c=>c.glContextLost?.())}),glCanvas.addEventListener("webglcontextrestored",()=>{glEnable=!0;glCanvas.style.display="";LOG("WebGL context restored, reinitializing...");a();for(const b of glTextureInfos)b.glTexture=glCreateTexture(b.image);pluginList.forEach(b=>b.glContextRestored?.())})):(console.warn("WebGL2 not supported, falling back to 2D canvas rendering!"),glCanvas=glContext=void 0,glCanBeEnabled=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=cos(cameraAngle),d=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 glRegisterTextureInfo(a){headlessMode||(glTextureInfos.add(a),glContext&&(a.glTexture?glSetTextureData(a.glTexture,a.image):a.glTexture=glCreateTexture(a.image)))}function glUnregisterTextureInfo(a){if(!headlessMode){glTextureInfos.delete(a);var b=a.glTexture;a.glTexture=void 0;glDeleteTexture(b)}}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,n=-1,l=0){(glBatchCount>=gl_MAX_INSTANCES||glBatchAdditive!==glAdditive)&&glFlush();glSetInstancedMode();glPolyMode=!1;let m=glBatchCount++*gl_INDICES_PER_INSTANCE;glPositionData[m++]=a;glPositionData[m++]=b;glPositionData[m++]=c;glPositionData[m++]=d;glPositionData[m++]=f;glPositionData[m++]=g;glPositionData[m++]=h;glPositionData[m++]=k;glColorData[m++]=n;glColorData[m++]=l;glPositionData[m++]=e}function glDrawPointsTransform(a,b,c,d,e,f,g,h=!0){const k=[];for(const n of a){a=n.x*e;const l=n.y*f,m=sin(-g),p=cos(-g);k.push(vec2(c+p*a-m*l,d+m*a+p*l))}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)],n=h.x-g.x,l=h.y-g.y,m=(n*n+l*l)**.5;g=k.x-h.x;const r=k.y-h.y;k=(g*g+r*r)**.5;1e-6>m&&1e-6>k||(l=1e-6<m?-l/m:0,m=1e-6<m?n/m:0,n=l+(1e-6<k?-r/k:0),g=m+(1e-6<k?g/k:0),k=(n*n+g*g)**.5,1e-6>k?(n=l,g=m):(n/=k,g/=k,l=l*n+m*g,1e-6<l&&(l=min(1/l,b),n*=l,g*=l)),l=vec2(h.x-n*d,h.y-g*d),h=vec2(h.x+n*d,h.y+g*d),e.push(l),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,t,u)=>(t.x-q.x)*(u.y-q.y)-(t.y-q.y)*(u.x-q.x);0>(q=>{let t=0;for(let u=q.length;u--;)t+=q[u].cross(q[(u+1)%q.length]);return t})(a)&&(a=a.reverse());var c=(q,t,u,w)=>{const x=b(t,u,q);u=b(u,w,q);q=b(w,t,q);return!((-1e-9>x?1:0)+(-1e-9>u?1:0)+(-1e-9>q?1:0)&&(1e-9<x?1:0)+(1e-9<u?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 n=d[(k+d.length-1)%d.length],l=d[k];const q=d[(k+1)%d.length],t=a[n],u=a[l],w=a[q];if(1e-9>b(t,u,w))continue;let x=!1;for(let B=0;B<d.length;B++){const z=d[B];if(z!==n&&z!==l&&z!==q&&(x=c(a[z],t,u,w)))break}if(!x){e.push([n,l,q]);d.splice(k,1);h=!0;break}}if(!h){h=-1;k=Infinity;for(n=0;n<d.length;n++)l=abs(b(a[d[(n+d.length-1)%d.length]],a[d[n]],a[d[(n+1)%d.length]])),l<k&&(k=l,h=n);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[m,p,r]=e[0];c.push(a[m],a[p],a[r]);for(d=1;d<e.length;d++){const[q,t,u]=e[d];c.push(a[r],a[q]);c.push(a[q],a[t],a[u]);r=u}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&&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&&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&&LOG("newgrounds call failed",e);return}debugMedals&&LOG(b.responseText);return b.responseText&&JSON.parse(b.responseText)}}let postProcess;class PostProcessPlugin{constructor(a,b=!1,c=!0){function d(){headlessMode||(glEnable?(postProcess.texture=glCreateTexture(),postProcess.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.;}")):console.warn("PostProcessPlugin: WebGL not enabled!"))}ASSERT(!postProcess,"Post process already initialized");postProcess=this;a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}";this.texture=this.shader=void 0;d();engineAddPlugin(void 0,function(){if(!headlessMode&&glEnable){glFlush();if(c||b)mainContext.drawImage(glCanvas,0,0),b&&(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);(c||b)&&glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,mainCanvas);var e=glContext.getAttribLocation(postProcess.shader,"p");glContext.enableVertexAttribArray(e);glContext.vertexAttribPointer(e,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)}},function(){postProcess.shader=void 0;postProcess.texture=void 0;LOG("PostProcessPlugin: WebGL context lost")},function(){d();LOG("PostProcessPlugin: WebGL context restored")})}}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,n,l,m,p,r,q,t,u,w=0,x,B=[],z=[],v=[],y=0,D=0,G=1,J={},H=audioDefaultSampleRate/d*60>>2;for(;G;y++)B=[G=m=t=0],c.forEach((E,K)=>{l=b[E][y]||[0,0,0];G|=b[E][y]&&1;x=t+(b[E][0].length-2-(m?0:1))*H;u=K===c.length-1;e=2;for(g=t;e<l.length+u;m=++e){k=l[e];p=e===l.length+u-1&&u||r!==(l[0]||0)||k|0;for(f=0;f<H&&m;f++>H-99&&p&&1>q?q+=1/99:0)n=(1-q)*B[w++]/2||0,z[g]=(z[g]||0)-n*D+n,v[g]=(v[g++]||0)+n*D+n;k&&(q=k%1,D=l[1]||0,k|=0)&&(B=J[[r=l[w=0]||0,k]]=J[[r,k]]||(h=[...a[r]],h[2]=(h[2]||220)*2**(k/12-1),0<k?zzfxG(...h):[]))}t=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.defaultGradientColor=void 0;this.defaultLineWidth=4;this.defaultCornerRadius=0;this.defaultTextScale=.8;this.defaultFont=fontDefault;this.defaultSoundClick=this.defaultSoundRelease=this.defaultSoundPress=void 0;this.defaultShadowColor=CLEAR_BLACK;this.defaultShadowBlur=5;this.defaultShadowOffset=vec2(5);this.uiObjects=[];this.uiContext=a;this.lastHoverObject=this.hoverObject=this.activeObject=void 0;this.nativeHeight=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.lastHoverObject=uiSystem.hoverObject;uiSystem.hoverObject=void 0;for(let d=uiSystem.uiObjects.length;d--;){const e=uiSystem.uiObjects[d];e.parent||c(e)}uiSystem.uiObjects=uiSystem.uiObjects.filter(d=>!d.destroyed)},function(){function b(d){if(d.visible){d.parent&&(d.pos=d.localPos.add(d.parent.pos));d.render();for(const e of d.children)b(e)}}const c=uiSystem.uiContext;c.save();if(uiSystem.nativeHeight){const d=mainCanvasSize.y/uiSystem.nativeHeight;c.translate(-d*mainCanvasSize.x/2,0);c.scale(d,d);c.translate(mainCanvasSize.x/2/d,0)}uiSystem.uiObjects.forEach(d=>d.parent||b(d));c.restore()})}drawRect(a,b,c=WHITE,d=0,e=BLACK,f=0,g,h=BLACK,k=0,n=vec2()){ASSERT(isVector2(a),"pos must be a vec2");ASSERT(isVector2(b),"size must be a vec2");ASSERT(isColor(c),"color must be a color");ASSERT(isNumber(d),"lineWidth must be a number");ASSERT(isColor(e),"lineColor must be a color");ASSERT(isNumber(f),"cornerRadius must be a number");const l=uiSystem.uiContext;if(g){const m=l.createLinearGradient(a.x,a.y-b.y/2,a.x,a.y+b.y/2);c=c.toString();m.addColorStop(0,c);m.addColorStop(.5,g.toString());m.addColorStop(1,c);l.fillStyle=m}else l.fillStyle=c.toString();(k||n.x||n.y)&&0<h.a&&(l.shadowColor=h.toString(),l.shadowBlur=k,l.shadowOffsetX=n.x,l.shadowOffsetY=n.y);l.beginPath();f&&l.roundRect?l.roundRect(a.x-b.x/2,a.y-b.y/2,b.x,b.y,f):l.rect(a.x-b.x/2,a.y-b.y/2,b.x,b.y);l.fill();l.shadowColor="#0000";d&&(l.strokeStyle=e.toString(),l.lineWidth=d,l.stroke())}drawLine(a,b,c=uiSystem.defaultLineWidth,d=uiSystem.defaultLineColor){ASSERT(isVector2(a),"posA must be a vec2");ASSERT(isVector2(b),"posB must be a vec2");ASSERT(isNumber(c),"lineWidth must be a number");ASSERT(isColor(d),"lineColor must be a color");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="",n=!0,l){l&&drawTextScreen(a,b.add(l),c.y,BLACK,e,f,g,h,k,n?c.x:void 0,0,uiSystem.uiContext);drawTextScreen(a,b,c.y,d,e,f,g,h,k,n?c.x:void 0,0,uiSystem.uiContext)}setupDragAndDrop(a,b,c,d){function e(f,g){document.addEventListener(g,function(h){h.preventDefault();f&&f(h)})}e(a,"drop");e(b,"dragenter");e(c,"dragleave");e(d,"dragover")}screenToNative(a){if(!uiSystem.nativeHeight)return a;const b=mainCanvasSize.y/uiSystem.nativeHeight,c=1/b;a=a.copy();a.x+=b*mainCanvasSize.x/2;a.x*=c;a.y*=c;a.x-=c*mainCanvasSize.x/2;return a}destroyObjects(){for(const a of this.uiObjects)a.parent||a.destroy();this.uiObjects=this.uiObjects.filter(a=>!a.destroyed)}}class UIObject{constructor(a=vec2(),b=vec2()){ASSERT(isVector2(a),"ui object pos must be a vec2");ASSERT(isVector2(b),"ui object size must be a vec2");this.localPos=a.copy();this.pos=a.copy();this.size=b.copy();this.color=uiSystem.defaultColor.copy();this.text=this.activeColor=void 0;this.disabledColor=uiSystem.defaultDisabledColor.copy();this.disabled=!1;this.textColor=uiSystem.defaultTextColor.copy();this.hoverColor=uiSystem.defaultHoverColor.copy();this.lineColor=uiSystem.defaultLineColor.copy();this.gradientColor=uiSystem.defaultGradientColor?uiSystem.defaultGradientColor.copy():void 0;this.lineWidth=uiSystem.defaultLineWidth;this.cornerRadius=uiSystem.defaultCornerRadius;this.font=uiSystem.defaultFont;this.textHeight=this.textWidth=this.fontStyle=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;this.canBeHover=!0;this.shadowColor=uiSystem.defaultShadowColor?.copy();this.shadowBlur=uiSystem.defaultShadowBlur;this.shadowOffset=uiSystem.defaultShadowOffset.copy();uiSystem.uiObjects.push(this);this.textShadow=void 0}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}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.parent=0,a.destroy()}}isMouseOverlapping(){if(!mouseInWindow)return!1;const a=isTouchDevice?this.size.add(vec2(this.extraTouchSize||0)):this.size,b=uiSystem.screenToNative(mousePosScreen);return isOverlapping(this.pos,a,b)}update(){this.onUpdate();const a=uiSystem.lastHoverObject===this,b=this.isActiveObject(),c=mouseIsDown(0),d=this.dragActivate?c:mouseWasPressed(0);this.canBeHover&&(d||b||!c&&!isTouchDevice)&&!uiSystem.hoverObject&&this.isMouseOverlapping()&&(uiSystem.hoverObject=this);if(this.isHoverObject()){if(!this.disabled){if(d&&this.interactive){if(!this.dragActivate||!a||mouseWasPressed(0))this.onPress();this.soundPress&&this.soundPress.play();if(uiSystem.activeObject&&!b)uiSystem.activeObject.onRelease();uiSystem.activeObject=this}!c&&this.isActiveObject()&&this.interactive&&(this.onClick(),this.soundClick&&this.soundClick.play())}d&&inputClearKey(0,0,0,1,0)}b&&(!c||this.dragActivate&&!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.disabled?this.disabledColor:this.interactive?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,this.gradientColor,this.shadowColor,this.shadowBlur,this.shadowOffset)}}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}onUpdate(){}onEnter(){}onLeave(){}onPress(){}onRelease(){}onClick(){}onChange(){}}class UIText extends UIObject{constructor(a,b,c="",d="center",e=uiSystem.defaultFont){super(a,b);ASSERT(isString(c),"ui text must be a string");ASSERT(["left","center","right"].includes(d),"ui text align must be left, center, or right");ASSERT(isString(e),"ui text font must be a string");this.text=c;this.align=d;this.font=e;this.lineWidth=0;this.canBeHover=!1}render(){const a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,this.lineWidth,this.lineColor,this.align,this.font,this.fontStyle,!0,this.textShadow)}}class UITile extends UIObject{constructor(a,b,c,d=WHITE,e=0,f=!1){super(a,b);ASSERT(c instanceof TileInfo,"ui tile tileInfo must be a TileInfo");ASSERT(isColor(d),"ui tile color must be a color");ASSERT(isNumber(e),"ui tile angle must be a number");this.tileInfo=c;this.angle=e;this.mirror=f;this.color=d.copy()}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);ASSERT(isString(c),"ui button must be a string");ASSERT(isColor(d),"ui button color must be a color");this.text=c;this.color=d.copy();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,this.fontStyle,!0,this.textShadow)}}class UICheckbox extends UIObject{constructor(a,b,c=!1,d="",e=uiSystem.defaultButtonColor){super(a,b);ASSERT(isString(d),"ui checkbox must be a string");ASSERT(isColor(e),"ui checkbox color must be a color");this.checked=c;this.text=d;this.color=e.copy();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,this.fontStyle,!1,this.textShadow)}}class UIScrollbar extends UIObject{constructor(a,b,c=.5,d="",e=uiSystem.defaultButtonColor,f=WHITE){super(a,b);ASSERT(isNumber(c),"ui scrollbar value must be a number");ASSERT(isString(d),"ui scrollbar must be a string");ASSERT(isColor(e),"ui scrollbar color must be a color");ASSERT(isColor(f),"ui scrollbar handleColor must be a color");this.value=c;this.handleColor=f.copy();this.text=d;this.color=e.copy();this.interactive=!0}update(){super.update();if(this.isActiveObject()&&this.interactive){const c=this.size.x>this.size.y;var a=c?this.pos.x:this.pos.y,b=(c?this.size.x:this.size.y)-(c?this.size.y:this.size.x);const d=a-b/2;a+=b/2;b=this.value;const e=uiSystem.screenToNative(mousePosScreen);this.value=c?percent(e.x,d,a):percent(e.y,a,d);this.value===b||this.onChange()}}render(){super.render();var a=this.size.x>this.size.y,b=a?this.size.y:this.size.x,c=a?this.pos.x:this.pos.y;const d=(a?this.size.x:this.size.y)-b;var e=c-d/2;c+=d/2;a=a?vec2(lerp(e,c,this.value),this.pos.y):vec2(this.pos.x,lerp(c,e,this.value));e=this.disabled?this.disabledColor:this.handleColor;uiSystem.drawRect(a,vec2(b),e,this.lineWidth,this.lineColor,this.cornerRadius,this.gradientColor);b=this.getTextSize();uiSystem.drawText(this.text,this.pos,b,this.textColor,0,void 0,this.align,this.font,this.fontStyle,!0,this.textShadow)}}class UIVideo extends UIObject{constructor(a,b,c,d=!1,e=!1,f=1){super(a,b||vec2());ASSERT(isString(c),"video src must be a string");ASSERT(isNumber(f),"video volume must be a number");this.color=BLACK;this.cornerRadius=0;this.volume=f;this.video=document.createElement("video");this.video.loop=e;this.video.volume=clamp(f*soundVolume);this.video.muted=!soundEnable;this.video.style.display="none";this.video.src=c;document.body.appendChild(this.video);d&&this.play()}play(){const a=this.video.play();a?.catch(()=>{});return a}pause(){this.video.pause()}stop(){this.video.pause();this.video.currentTime=0}isLoadng(){return this.video.readyState<this.video.HAVE_CURRENT_DATA}isPaused(){return this.video.paused}isPlaying(){return!this.isPaused()&&!this.hasEnded()&&!this.isLoadng()}hasEnded(){return this.video.ended}setVolume(a){this.volume=a;this.video.volume=clamp(a*soundVolume)}setPlaybackRate(a){this.video.playbackRate=a}getCurrentTime(){return this.video.currentTime||0}getDuration(){return this.video.duration||0}getVideoSize(){return vec2(this.video.videoWidth,this.video.videoHeight)}setTime(a){this.video.currentTime=clamp(a,0,this.getDuration())}update(){super.update();this.video.volume=clamp(this.volume*soundVolume)}render(){super.render();if(!this.isLoadng()){var a=uiSystem.uiContext,b=this.size;a.save();a.translate(this.pos.x,this.pos.y);a.drawImage(this.video,-b.x/2,-b.y/2,b.x,b.y);a.restore()}}destroy(){this.destroyed||(this.video.pause(),this.video.remove(),super.destroy())}}let box2d,box2dDebug=!1;function box2dSetDebug(a){box2dDebug=a}class Box2dObject extends EngineObject{constructor(a=vec2(),b=vec2(),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;box2d.objects.push(this);this.edgeLists=[];this.edgeLoops=[]}destroy(){this.destroyed||(ASSERT(this.body,"Box2dObject has no body to destroy"),box2d.world.DestroyBody(this.body),super.destroy())}updatePhysics(){}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=BLACK,c=.1,d){this.getFixtureList().forEach(e=>{box2d.castObjectType(e.GetShape()).GetType()!==box2d.instance.b2Shape.e_edge&&box2d.drawFixture(e,this.pos,this.angle,a,b,c,d)});this.edgeLists.forEach(e=>drawLineList(e,c,b,!1,this.pos,this.angle));this.edgeLoops.forEach(e=>drawLineList(e,c,b,!0,this.pos,this.angle))}beginContact(a){}endContact(a){}addShape(a,b=1,c=.2,d=0,e=!1){ASSERT(isNumber(b),"density must be a number");ASSERT(isNumber(c),"friction must be a number");ASSERT(isNumber(d),"restitution must be a number");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){ASSERT(isVector2(a),"size must be a Vector2");ASSERT(0<a.x&&0<a.y,"size must be positive");ASSERT(isVector2(b),"offset must be a Vector2");ASSERT(isNumber(c),"angle must be a number");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(isArray(a),"points must be an array");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){ASSERT(isNumber(a)&&0<a,"diameter must be a positive number");ASSERT(isNumber(b)&&2<b,"sides must be a positive number greater than 2");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){ASSERT(isNumber(a)&&0<a,"diameter must be a positive number");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){ASSERT(isNumber(a)&&0<a,"diameter must be a positive number");ASSERT(isVector2(b),"offset must be a Vector2");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){ASSERT(isVector2(a),"point1 must be a Vector2");ASSERT(isVector2(b),"point2 must be a Vector2");const g=new box2d.instance.b2EdgeShape;g.Set(box2d.vec2dTo(a),box2d.vec2dTo(b));return this.addShape(g,c,d,e,f)}addEdgeList(a,b,c,d,e){ASSERT(isArray(a),"points must be an array");const f=[],g=[];for(let k=0;k<a.length-1;++k){var h=new box2d.instance.b2EdgeShape;a[k-1]&&h.set_m_vertex0(box2d.vec2dTo(a[k-1]));a[k+0]&&h.set_m_vertex1(box2d.vec2dTo(a[k+0]));a[k+1]&&h.set_m_vertex2(box2d.vec2dTo(a[k+1]));a[k+2]&&h.set_m_vertex3(box2d.vec2dTo(a[k+2]));h=this.addShape(h,b,c,d,e);f.push(h);g.push(a[k].copy())}g.push(a[a.length-1].copy());this.edgeLists.push(g);return f}addEdgeLoop(a,b,c,d,e){ASSERT(isArray(a),"points must be an array");const f=[],g=[];for(let k=0;k<a.length;++k){var h=new box2d.instance.b2EdgeShape;h.set_m_vertex0(box2d.vec2dTo(a[mod(k-1,a.length)]));h.set_m_vertex1(box2d.vec2dTo(a[mod(k+0,a.length)]));h.set_m_vertex2(box2d.vec2dTo(a[mod(k+1,a.length)]));h.set_m_vertex3(box2d.vec2dTo(a[mod(k+2,a.length)]));h=this.addShape(h,b,c,d,e);f.push(h);k<a.length&&g.push(a[k].copy())}this.edgeLoops.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()}getSpeed(){return this.getLinearVelocity().length()}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 Box2dStaticObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeStatic,f)}}class Box2dKiematicObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeKinematic,f)}}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),n=b.worldToLocal(f),l=new box2d.instance.b2PulleyJointDef;l.set_bodyA(a.body);l.set_bodyB(b.body);l.set_groundAnchorA(box2d.vec2dTo(c));l.set_groundAnchorB(box2d.vec2dTo(d));l.set_localAnchorA(box2d.vec2dTo(k));l.set_localAnchorB(box2d.vec2dTo(n));l.set_ratio(g);l.set_lengthA(c.distance(e));l.set_lengthB(d.distance(f));l.set_collideConnected(h);super(l)}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.objects=[];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){a=box2d.instance.wrapPointer(a,box2d.instance.b2Vec2);return box2d.vec2From(a)}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(){if(!paused){box2d.step();box2d.objects=box2d.objects.filter(a=>!a.destroyed);for(const a of box2d.objects)a.body&&(a.pos=box2d.vec2From(a.body.GetPosition()),a.angle=-a.body.GetAngle())}},function(){(box2dDebug||debugPhysics)&&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,n,l){const m=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=n?-1:1,q=n?-h:h;drawTile(a,p,m,d,h,!1,f,k,n,l);for(var t=4;t--;){var u=t%2,w=b.multiply(vec2(u?1===t?1:-1:0,u?0:t?-1:1));u=vec2(u?e:p.x,u?p.y:e);const x=m.offset(c.size.multiply(vec2(1===t?1:3===t?-1:0,0===t?-r:2===t?r:0)));drawTile(a.add(w.rotate(q)),u,x,d,h,!1,f,k,n,l)}for(e=4;e--;)t=1<e,w=e&&3>e,p=b.multiply(vec2(t?-1:1,w?-1:1)),t=m.offset(c.size.multiply(vec2(t?-1:1,w?r:-r))),drawTile(a.add(p.rotate(q)),g,t,d,h,!1,f,k,n,l)}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,n,l){const m=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=n?-1:1;const t=n?-h:h;drawTile(a,q,r,d,h,!1,f,k,n,l);for(r=4;r--;){const w=h+r*PI/2;var u=r%2;const x=b.multiply(vec2(u?1===r?1:-1:0,u?0:r?-c:c));u=vec2(u?q.y:q.x,e);drawTile(a.add(x.rotate(t)),u,p,d,w,!1,f,k,n,l)}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(t)),g,m,d,p,!1,f,k,n,l)}
|