littlejsengine 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +38 -16
  2. package/{engine/index.d.ts → build/littlejs.d.ts} +1 -1
  3. package/{engine/engine.all.module.js → build/littlejs.esm.js} +5 -5
  4. package/build/littlejs.esm.min.js +1 -0
  5. package/{engine/engine.all.js → build/littlejs.js} +5 -5
  6. package/build/littlejs.min.js +1 -0
  7. package/{engine/engine.all.release.js → build/littlejs.release.js} +5 -5
  8. package/examples/breakout/index.html +3 -2
  9. package/examples/electron/build.bat +52 -0
  10. package/{electron → examples/electron}/electron.js +18 -21
  11. package/{game.js → examples/electron/game.js} +1 -1
  12. package/examples/electron/index.html +2 -0
  13. package/examples/electron/package.json +20 -0
  14. package/examples/empty/game.js +1 -1
  15. package/examples/empty/index.html +2 -2
  16. package/examples/module/game.js +1 -1
  17. package/examples/module/index.html +2 -1
  18. package/examples/particles/index.html +3 -2
  19. package/examples/platformer/index.html +3 -2
  20. package/examples/puzzle/index.html +3 -2
  21. package/{build.bat → examples/starter/build.bat} +14 -15
  22. package/examples/starter/game.js +111 -0
  23. package/examples/starter/index.html +27 -0
  24. package/examples/starter/tiles.png +0 -0
  25. package/examples/stress/index.html +3 -2
  26. package/examples/typescript/game.js +1 -1
  27. package/examples/typescript/game.ts +1 -1
  28. package/examples/typescript/index.html +2 -1
  29. package/package.json +2 -2
  30. package/{engine → src}/engine.js +1 -1
  31. package/src/engineBuild.bat +130 -0
  32. package/{engine → src}/engineInput.js +3 -3
  33. package/{engine → src}/engineMedals.js +1 -1
  34. package/electron/electronBuild.bat +0 -32
  35. package/electron/electronSetup.bat +0 -2
  36. package/electron/package.json +0 -21
  37. package/engine/engine.all.min.js +0 -1
  38. package/engine/engine.all.module.min.js +0 -1
  39. package/engine/engineBuild.bat +0 -127
  40. package/index.html +0 -26
  41. /package/{tiles.png → examples/electron/tiles.png} +0 -0
  42. /package/{favicon.png → examples/favicon.png} +0 -0
  43. /package/{engine → src}/engineAudio.js +0 -0
  44. /package/{engine → src}/engineDebug.js +0 -0
  45. /package/{engine → src}/engineDraw.js +0 -0
  46. /package/{engine → src}/engineExport.js +0 -0
  47. /package/{engine → src}/engineFont.png +0 -0
  48. /package/{engine → src}/engineObject.js +0 -0
  49. /package/{engine → src}/engineParticles.js +0 -0
  50. /package/{engine → src}/engineRelease.js +0 -0
  51. /package/{engine → src}/engineSettings.js +0 -0
  52. /package/{engine → src}/engineTileLayer.js +0 -0
  53. /package/{engine → src}/engineUtilities.js +0 -0
  54. /package/{engine → src}/engineWebGL.js +0 -0
@@ -1 +0,0 @@
1
- let showWatermark=0,godMode=0;const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*randInt(2)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const setRandSeed=a=>randSeed=a,randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y),isVector2=a=>!isNaN(a.x)&&!isNaN(a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(isVector2(a));return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(isVector2(a));return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(isVector2(a));return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(isVector2(a));return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(!isVector2(a));return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){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){ASSERT(isVector2(a));return this.x*a.x+this.y*a.y}cross(a){ASSERT(isVector2(a));return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return abs(this.x*this.y)}lerp(a,b){ASSERT(isVector2(a));return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){if(debug)return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}const colorRGBA=(a,b,c,d)=>new Color(a,b,c,d),colorHSLA=(a,b,c,d)=>(new Color).setHSLA(a,b,c,d);class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,k)=>(k=(k%1+1)%1)<1/6?f+6*(g-f)*k:.5>k?g:k<2/3?f+(g-f)*(2/3-k)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}getHSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=Math.max(a,b,c),f=Math.min(a,b,c),g=(e+f)/2;let k=0,h=0;if(e!=f){let l=e-f;h=.5<g?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,h,g,d]}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(a=1){const b=c=>(16>(c=255*c|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){this.r=clamp(parseInt(a.slice(1,3),16)/255);this.g=clamp(parseInt(a.slice(3,5),16)/255);this.b=clamp(parseInt(a.slice(5,7),16)/255);this.a=7<a.length?clamp(parseInt(a.slice(7,9),16)/255):1;return this}rgbaInt(){const a=255*clamp(this.r)|0,b=(255*clamp(this.g)|0)<<8,c=(255*clamp(this.b)|0)<<16,d=(255*clamp(this.a)|0)<<24;return a+b+c+d}}class Timer{constructor(a){this.time=void 0==a?void 0:time+a;this.setTime=a}set(a=0){this.time=time+a;this.setTime=a}unset(){this.time=void 0}isSet(){return void 0!=this.time}active(){return time<=this.time}elapsed(){return time>this.time}get(){return this.isSet()?time-this.time:0}getPercent(){return this.isSet()?percent(this.time-time,this.setTime,0):0}toString(){if(debug)return this.unset()?"unset":Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after")}valueOf(){return this.get()}}"use strict";let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",glEnable=1,glOverlay=1,tileSizeDefault=vec2(16),tileFixBleedScale=.3,enablePhysicsSolver=1,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadAnalog=1,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=1,soundEnable=1,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock;"use strict";const engineName="LittleJS",engineVersion="1.5.2",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0;function setPaused(a){paused=a}function engineInit(a,b,c,d,e,f){function g(m=0){var n=m-k;k=m;if(debug||showWatermark)l=lerp(.05,l,1e3/(n||1));m=debug&&keyIsDown(107);const p=debug&&keyIsDown(109);debug&&(n*=m?5:p?.2:1);timeReal+=n/1e3;h+=!paused*n;m||(h=min(h,50));canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,n=innerWidth/innerHeight,m=mainCanvas.width/mainCanvas.height,(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=n<m?"100%":"",(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=n<m?"":"100%"):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y));overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{n=0;0>h&&-9<h&&(n=h,h=0);for(;0<=h;h-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();h+=n}enginePreRender();d();engineObjects.sort((r,w)=>r.renderOrder-w.renderOrder);for(var q of engineObjects)q.destroyed||q.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",q=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+l.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(q,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(q,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)}tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none";document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");debugInit();glEnable&&glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");(glCanvas||mainCanvas).style=mainCanvas.style=overlayCanvas.style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";a();touchGamepadCreate();g()};let k=0,h,l;f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=vec2(1),c=-1,d=tileSizeDefault,e=0,f,g=0){ASSERT(isVector2(a)&&isVector2(b));this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=g;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.velocity.y+=gravity*this.gravityScale,this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y*=this.damping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),enablePhysicsSolver&&this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide)if(!(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this||!isOverlapping(this.pos,this.size,d.pos,d.size)||!this.collideWithObject(d)|!d.collideWithObject(this)))if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00")}else{c=this.size.add(d.size);e=2*(a.y-d.pos.y)>c.y+gravity;var f=2*abs(a.y-d.pos.y)<c.y,g=2*abs(a.x-d.pos.x)<c.x;if(e|g|!f)if(this.pos.y=d.pos.y+(c.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-this.elasticity;else if(d.mass){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const k=this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass),h=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass),l=max(this.elasticity,d.elasticity);this.velocity.y=lerp(l,g,k);d.velocity.y=lerp(l,g,h)}!e&f&&(this.pos.x=d.pos.x+(c.x/2+.001)*sign(a.x-d.pos.x),d.mass?(c=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),e=this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),g=max(this.elasticity,d.elasticity),this.velocity.x=lerp(g,c,e),d.velocity.x=lerp(g,c,f)):this.velocity.x*=-this.elasticity);debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)&&(c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this),d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this),c|!d&&(this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y),d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity))}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=1,b=1,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){if(debug){let a="type = "+this.constructor.name;if(this.pos.x||this.pos.y)a+="\npos = "+this.pos;if(this.velocity.x||this.velocity.y)a+="\nvelocity = "+this.velocity;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.angle&&(a+="\nangle = "+this.angle.toFixed(3));this.color&&(a+="\ncolor = "+this.color);return a}}}"use strict";let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const tileImage=new Image;let tileImageSize,tileImageFixBleed,drawCount;const screenToWorld=a=>{ASSERT(mainCanvasSize.x&&mainCanvasSize.y,"mainCanvasSize is invalid");return a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos)},worldToScreen=a=>{ASSERT(mainCanvasSize.x&&mainCanvasSize.y,"mainCanvasSize is invalid");return a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5))};function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,g,k=new Color(0,0,0,0),h=glEnable){showWatermark&&++drawCount;if(glEnable&&h)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var l=tileImageSize.x/d.x|0;h=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,n=c%l*h;l=(c/l|0)*m;glDraw(a.x,a.y,g?-b.x:b.x,b.y,f,n+tileImageFixBleed.x,l+tileImageFixBleed.y,n-tileImageFixBleed.x+h,l-tileImageFixBleed.y+m,e.rgbaInt(),k.rgbaInt())}else drawCanvas2D(a,b,f,g,m=>{if(0>c)m.fillStyle=e,m.fillRect(-.5,-.5,1,1);else{var n=tileImageSize.x/d.x|0;const p=c%n*d.x+tileFixBleedScale;n=(c/n|0)*d.y+tileFixBleedScale;const q=d.x-2*tileFixBleedScale,r=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,p,n,q,r,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,g,k,h){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,g,k,h)}function drawRectScreenSpace(a,b,c,d,e){drawTileScreenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y+.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",k=fontDefault,h=overlayContext){h.fillStyle=d;h.lineWidth=e;h.strokeStyle=f;h.textAlign=g;h.font=c+"px "+k;h.textBaseline="middle";h.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&h.strokeText(l,b.x,b.y);h.fillText(l,b.x,b.y);b.y+=c})}function drawText(a,b,c=1,d,e=0,f,g,k){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,k,mainContext)}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){engineFontImage||((engineFontImage=new Image).src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((h,l)=>{const m=d?h.length*f.x*c/2|0:0;for(let q=h.length;q--;){var n=h[q].charCodeAt();if(32>n||127<n)n=127;var p=this.startTileIndex+n-32;n=p%k;p=p/k|0;const r=b.add(vec2(q,l).multiply(g));e.drawImage(this.image,n*f.x,p*f.y,f.x,f.y,r.x-m,r.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0,preventDefaultInput=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){isTouchDevice||document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKeyCode(a.keyCode)]=3),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKeyCode(a.keyCode)]=4)};const remapKeyCode=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return vec2(mainCanvas.width,mainCanvas.height).multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=k=>.3<k?percent(k,.3,.8):-.3>k?-percent(-k,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],g[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b=onmousedown,c=onmouseup;onmousedown=onmouseup=()=>0;ontouchstart=d=>{zzfx(0);ontouchstart=ontouchmove=ontouchend=e=>{e.button=0;const f=e.touches.length;f?(e.x=e.touches[0].clientX,e.y=e.touches[0].clientY,a?onmousemove(e):b(e)):a&&c(e);a=f;return!0};return ontouchstart(d)}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function touchGamepadCreate(){touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons=[],touchGamepadStick=vec2(),ontouchstart=a=>{zzfx(0);ontouchstart=ontouchmove=ontouchend=b=>{touchGamepadStick=vec2();touchGamepadButtons=[];if(b.touches.length&&(isUsingGamepad=1,touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}const c=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),d=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),e=mainCanvasSize.scale(.5);for(const f of b.touches)b=mouseToScreen(vec2(f.clientX,f.clientY)),b.distance(c)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=b.subtract(c).scale(2/touchGamepadSize).clampLength():(b=b.subtract(c).angle(),touchGamepadStick.setAngle((4*b/PI+8.5|0)*PI/4)):b.distance(d)<touchGamepadSize?(b=b.subtract(d).direction(),touchGamepadButtons[b]=1):b.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)};return ontouchstart(a)})}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer,4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";overlayContext.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)overlayContext.arc(a.x,a.y,touchGamepadSize/2,0,9),overlayContext.fill();else for(var b=10;b--;){var c=b*PI/4;overlayContext.arc(a.x,a.y,.6*touchGamepadSize,c+PI/8,c+PI/8);b%2&&overlayContext.arc(a.x,a.y,.33*touchGamepadSize,c,c);1==b&&overlayContext.fill()}overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(b=4;b--;)c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a,b=1){if(soundEnable)return this.source=playSamples(this.cachedSamples,a,1,0,b)}stop(){this.source&&this.source.stop();this.source=0}isPlaying(){return this.source}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||=new AudioContext,audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),g=audioContext.createBufferSource();a.forEach((k,h)=>f.getChannelData(h).set(k));g.buffer=f;g.playbackRate.value=c;g.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);g.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);g.start();return g}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,k=1,h=0,l=0,m=0,n=0,p=0,q=0,r=0,w=0,u=0,B=1,z=0,C=0){let v=2*PI,F=h*=500*v/zzfxR/zzfxR,A=[];b=c*=(1+b*rand(-1,1))*v/zzfxR;let x=0,D=0,t=0,y=1,G=0,I=0,E=0,J,H;d=d*zzfxR+9;z*=zzfxR;e*=zzfxR;f*=zzfxR;u*=zzfxR;l*=500*v/zzfxR**3;r*=v/zzfxR;m*=v/zzfxR;n*=zzfxR;p=p*zzfxR|0;for(H=d+z+e+f+u|0;t<H;A[t++]=E)++I%(100*w|0)||(E=g?1<g?2<g?3<g?Math.sin((x%v)**3):max(min(Math.tan(x),1),-1):1-(2*x/v%2+2)%2:1-4*abs(Math.round(x/v)-x/v):Math.sin(x),E=(p?1-C+C*Math.sin(v*t/p):1)*sign(E)*abs(E)**k*a*soundVolume*(t<d?t/d:t<d+z?1-(t-d)/z*(1-B):t<d+z+e?B:t<H-u?(H-t-u)/f*B:0),E=u?E/2+(u>t?0:(t<H-u?1:(H-t)/u)*A[t-u|0]/2):E),J=(c+=h+=l)*Math.cos(r*D++),x+=J-J*q*(1-1e9*(Math.sin(t)+1)%2),y&&++y>n&&(c+=m,b+=m,y=0),!p||++G%p||(c=b,h=F,y=y||1);return A}function zzfxM(a,b,c,d=125){let e,f,g,k,h,l,m,n,p,q,r,w,u,B=0,z,C=[],v=[],F=[],A=0,x=0,D=1,t={},y=zzfxR/d*60>>2;for(;D;A++)C=[D=n=w=0],c.forEach((G,I)=>{m=b[G][A]||[0,0,0];D|=!!b[G][A];z=w+(b[G][0].length-2-!n)*y;u=I==c.length-1;e=2;for(g=w;e<m.length+u;n=++e){h=m[e];p=e==m.length+u-1&&u||q!=(m[0]||0)|h|0;for(f=0;f<y&&n;f++>y-99&&p?r+=(1>r)/99:0)l=(1-r)*C[B++]/2||0,v[g]=(v[g]||0)-l*x+l,F[g]=(F[g++]||0)+l*x+l;h&&(r=h%1,x=m[1]||0,h|=0)&&(C=t[[q=m[B=0]||0,h]]=t[[q,h]]||(k=[...a[q]],k[2]*=2**((h-12)/12),0<h?zzfxG(...k):[]))}w=z});return[v,F]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){var d=(b=b.floor()).subtract(a=a.floor());const e=abs(d.x),f=-abs(d.y),g=sign(d.x);d=sign(d.y);for(let h=a.x,l=a.y,m=e+f;;){var k=getTileCollisionData(vec2(h,l));if(k&&(c?c.collideWithTileRaycast(k,new Vector2(h,l)):0<k))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(h+.5,l+.5),"#ff0",1),new Vector2(h+.5,l+.5);if(h==b.x&l==b.y)break;k=2*m;k>=f&&(m+=f,h+=g);k<=e&&(m+=e,l+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;a&&(mainCanvas.width=this.size.x*this.tileSize.x,mainCanvas.height=this.size.y*this.tileSize.y);enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glEnable&&glCopyToContext(mainContext,1);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,g){this.drawCanvas2D(a,b,f,g,k=>{if(0>c)k.fillStyle=e,k.fillRect(-.5,-.5,1,1);else{const h=tileImage.width/d.x;k.globalAlpha=e.a;k.drawImage(tileImage,c%h*d.x,(c/h|0)*d.y,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g=-1,k=tileSizeDefault,h=new Color,l=new Color,m=new Color(1,1,1,0),n=new Color(1,1,1,0),p=.5,q=.1,r=1,w=.1,u=.05,B=1,z=1,C=0,v=PI,F=.1,A=.2,x,D,t=1,y=D?1e9:0,G){super(a,new Vector2,g,k,b,void 0,y);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h;this.colorStartB=l;this.colorEndA=m;this.colorEndB=n;this.randomColorLinear=t;this.particleTime=p;this.sizeStart=q;this.sizeEnd=r;this.speed=w;this.angleSpeed=u;this.damping=B;this.angleDamping=z;this.gravityScale=C;this.particleConeAngle=v;this.fadeRate=F;this.randomness=A;this.collideTiles=x;this.additive=D;this.localSpace=G;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime|this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(this.emitSize/2),b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);a=new Particle(a,this.tileIndex,this.tileSize,b);const c=this.randomness;var d=m=>m+m*rand(c,-c);b=d(this.particleTime);const e=d(this.sizeStart),f=d(this.sizeEnd),g=d(this.speed);d=d(this.angleSpeed)*randSign();var k=rand(this.emitConeAngle,-this.emitConeAngle);const h=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a.colorStart=h;a.colorEndDelta=l.subtract(h);a.velocity=(new Vector2).setAngle(k,g);a.angleVelocity=d;a.lifeTime=b;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=randInt(2);a.localSpaceEmitter=this.localSpace&&this;a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);let d=this.pos;var e=this.angle;this.localSpaceEmitter&&(d=this.localSpaceEmitter.pos.add(d.rotate(-this.localSpaceEmitter.angle)),e+=this.localSpaceEmitter.angle);if(this.trailScale){var f=this.velocity;this.localSpaceEmitter&&(f=f.rotate(-this.localSpaceEmitter.angle));e=f.length();f=f.scale(1/e);const g=e*this.trailScale;b.y=max(b.x,g);e=f.angle();drawTile(d.add(f.multiply(vec2(0,-g/2))),b,this.tileIndex,this.tileSize,c,e,this.mirror)}else drawTile(d,b,this.tileIndex,this.tileSize,c,e,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(d,b,"#f005",0,e);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=localStorage[b.storageKey()]|0)}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;e&&((this.image=new Image).src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=overlayCanvas.width-c;a*=-medalDisplaySize.y;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9);b.strokeStyle=new Color(0,0,0);b.lineWidth=3;b.fill(b.rect(d,a,c,medalDisplaySize.y));b.stroke();b.clip();this.renderIcon(vec2(d+15+medalDisplayIconSize/2,a+medalDisplaySize.y/2));c=vec2(d+medalDisplayIconSize+30,a+28);drawTextScreen(this.name,c,38,new Color(0,0,0),0,0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,0,"left");b.restore()}renderIcon(a,b=medalDisplayIconSize){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,new Color(0,0,0))}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}let newgrounds;function newgroundsInit(a,b){newgrounds=new Newgrounds(a,b)}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=this.CryptoJS());if(this.session_id=new URL(location.href).searchParams.get("ngio_session_id")){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image=new Image,a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,1),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},1)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},1)}getScores(a,b=0,c=0,d=0,e=10){return this.call("ScoreBoard.getScores",{id:a,user:b,social:c,skip:d,limit:e})}logView(){return this.call("App.logView",{host:this.host},1)}call(a,b=0,c=0){a={component:a,parameters:b};if(this.cipher){b=this.cryptoJS;var d=b.enc.Base64.parse(this.cipher);const e=b.lib.WordArray.random(16);d=b.AES.encrypt(JSON.stringify(a),d,{iv:e});a.secure=b.enc.Base64.stringify(e.concat(d.ciphertext));a.parameters=0}b={app_id:this.app_id,session_id:this.session_id,call:a};a=new FormData;a.append("input",JSON.stringify(b));b=new XMLHttpRequest;b.open("POST","https://newgrounds.io/gateway_v3.php",!debugMedals&&c);b.send(a);debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}CryptoJS(){return eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0))}}"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glArrayBuffer,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec4 v,d,e;void main(){gl_Position=m*vec4(p,1,1);v=vec4(t,p);d=c;e=a;}","precision highp float;varying vec4 v,d,e;uniform sampler2D s;void main(){gl_FragColor=texture2D(s,v.xy)*d+e;}");const a=new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);glArrayBuffer=glContext.createBuffer();glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glBatchCount=0}function glSetBlendMode(a){glAdditive=a}function glSetTexture(a=glTileTexture){a!=glActiveTexture&&glFlush();glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a)}function glCompileShader(a,b){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}function glCreateProgram(a,b){const c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}function glCreateTexture(a){const b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);a&&a.width&&glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);a=cavasPixelated?gl_NEAREST:gl_LINEAR;glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}function glPreRender(){glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glContext.clear(gl_COLOR_BUFFER_BIT);glContext.useProgram(glShader);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_VERTEX_BUFFER_SIZE,gl_DYNAMIC_DRAW);glSetBlendMode();let a=0;var b=(d,e,f,g,k=0)=>{d=glContext.getAttribLocation(glShader,d);glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,k,gl_VERTEX_BYTE_STRIDE,a);a+=g*f};b("p",gl_FLOAT,4,2);b("t",gl_FLOAT,4,2);b("c",gl_UNSIGNED_BYTE,1,4,1);b("a",gl_UNSIGNED_BYTE,1,4,1);b=2*cameraScale/mainCanvas.width;const c=2*cameraScale/mainCanvas.height;glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([b,0,0,0,0,c,0,0,1,1,-1,1,-1-b*cameraPos.x,-1-c*cameraPos.y,0,0]))}function glFlush(){if(glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){if(glBatchCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,g,k,h,l,m=0){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var n=Math.cos(e)/2,p=Math.sin(e)/2;e=n*c;n*=d;c*=p;d*=p;for(let q=6,r=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;q--;){p=q-4&&1<q;const w=q-5&&q-2&&q-1;glPositionData[r++]=a+(p?-e:e)+(w?d:-d);glPositionData[r++]=b+(w?n:-n)+(p?c:-c);glPositionData[r++]=p?f:k;glPositionData[r++]=w?g:h;glColorData[r++]=l;glColorData[r++]=m}}let glPostShader,glPostArrayBuffer,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b){ASSERT(!glPostShader);a||="void mainImage(out vec4 c,vec2 p){c=texture2D(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("precision highp float;attribute vec2 p;void main(){gl_Position=vec4(p,1,1);}","precision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;\n"+a+"\nvoid main(){mainImage(gl_FragColor,gl_FragCoord.xy);gl_FragColor.a=1.;}");glPostArrayBuffer=glContext.createBuffer();glPostTexture=glCreateTexture();glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden"}function glRenderPostProcess(){if(glPostShader){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glPostIncludeOverlay&&(mainContext.drawImage(overlayCanvas,0,0),overlayCanvas.width=mainCanvas.width);glContext.useProgram(glPostShader);glContext.disable(gl_BLEND);glContext.bindBuffer(gl_ARRAY_BUFFER,glPostArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,new Float32Array([-3,1,1,-3,1,1]),gl_STATIC_DRAW);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,!0);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glPostTexture);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,mainCanvas);var a=glContext.getAttribLocation(glPostShader,"p");glContext.enableVertexAttribArray(a);glContext.vertexAttribPointer(a,2,gl_FLOAT,0,8,0);glContext.uniform1i(glContext.getUniformLocation(glPostShader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(glPostShader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(glPostShader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(gl_TRIANGLES,0,3)}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_BYTE=5120,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_TEXTURE0=33984,gl_TEXTURE1=33985,gl_ARRAY_BUFFER=34962,gl_STATIC_DRAW=35044,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_UNPACK_FLIP_Y_WEBGL=37440,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24,gl_VERTEX_BUFFER_SIZE=gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE;
@@ -1 +0,0 @@
1
- let showWatermark=0,godMode=0;const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*randInt(2)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const setRandSeed=a=>randSeed=a,randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y),isVector2=a=>!isNaN(a.x)&&!isNaN(a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(isVector2(a));return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(isVector2(a));return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(isVector2(a));return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(isVector2(a));return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(!isVector2(a));return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){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){ASSERT(isVector2(a));return this.x*a.x+this.y*a.y}cross(a){ASSERT(isVector2(a));return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return abs(this.x*this.y)}lerp(a,b){ASSERT(isVector2(a));return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){if(debug)return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}const colorRGBA=(a,b,c,d)=>new Color(a,b,c,d),colorHSLA=(a,b,c,d)=>(new Color).setHSLA(a,b,c,d);class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,k)=>(k=(k%1+1)%1)<1/6?f+6*(g-f)*k:.5>k?g:k<2/3?f+(g-f)*(2/3-k)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}getHSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=Math.max(a,b,c),f=Math.min(a,b,c),g=(e+f)/2;let k=0,h=0;if(e!=f){let l=e-f;h=.5<g?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,h,g,d]}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(a=1){const b=c=>(16>(c=255*c|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){this.r=clamp(parseInt(a.slice(1,3),16)/255);this.g=clamp(parseInt(a.slice(3,5),16)/255);this.b=clamp(parseInt(a.slice(5,7),16)/255);this.a=7<a.length?clamp(parseInt(a.slice(7,9),16)/255):1;return this}rgbaInt(){const a=255*clamp(this.r)|0,b=(255*clamp(this.g)|0)<<8,c=(255*clamp(this.b)|0)<<16,d=(255*clamp(this.a)|0)<<24;return a+b+c+d}}class Timer{constructor(a){this.time=void 0==a?void 0:time+a;this.setTime=a}set(a=0){this.time=time+a;this.setTime=a}unset(){this.time=void 0}isSet(){return void 0!=this.time}active(){return time<=this.time}elapsed(){return time>this.time}get(){return this.isSet()?time-this.time:0}getPercent(){return this.isSet()?percent(this.time-time,this.setTime,0):0}toString(){if(debug)return this.unset()?"unset":Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after")}valueOf(){return this.get()}}"use strict";let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",glEnable=1,glOverlay=1,tileSizeDefault=vec2(16),tileFixBleedScale=.3,enablePhysicsSolver=1,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadAnalog=1,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=1,soundEnable=1,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock;"use strict";const engineName="LittleJS",engineVersion="1.5.2",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0;function setPaused(a){paused=a}function engineInit(a,b,c,d,e,f){function g(m=0){var n=m-k;k=m;if(debug||showWatermark)l=lerp(.05,l,1e3/(n||1));m=debug&&keyIsDown(107);const p=debug&&keyIsDown(109);debug&&(n*=m?5:p?.2:1);timeReal+=n/1e3;h+=!paused*n;m||(h=min(h,50));canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,n=innerWidth/innerHeight,m=mainCanvas.width/mainCanvas.height,(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=n<m?"100%":"",(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=n<m?"":"100%"):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y));overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{n=0;0>h&&-9<h&&(n=h,h=0);for(;0<=h;h-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();h+=n}enginePreRender();d();engineObjects.sort((r,w)=>r.renderOrder-w.renderOrder);for(var q of engineObjects)q.destroyed||q.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",q=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+l.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(q,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(q,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)}tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none";document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");debugInit();glEnable&&glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");(glCanvas||mainCanvas).style=mainCanvas.style=overlayCanvas.style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";a();touchGamepadCreate();g()};let k=0,h,l;f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=vec2(1),c=-1,d=tileSizeDefault,e=0,f,g=0){ASSERT(isVector2(a)&&isVector2(b));this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=g;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.velocity.y+=gravity*this.gravityScale,this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y*=this.damping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),enablePhysicsSolver&&this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide)if(!(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this||!isOverlapping(this.pos,this.size,d.pos,d.size)||!this.collideWithObject(d)|!d.collideWithObject(this)))if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00")}else{c=this.size.add(d.size);e=2*(a.y-d.pos.y)>c.y+gravity;var f=2*abs(a.y-d.pos.y)<c.y,g=2*abs(a.x-d.pos.x)<c.x;if(e|g|!f)if(this.pos.y=d.pos.y+(c.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-this.elasticity;else if(d.mass){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const k=this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass),h=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass),l=max(this.elasticity,d.elasticity);this.velocity.y=lerp(l,g,k);d.velocity.y=lerp(l,g,h)}!e&f&&(this.pos.x=d.pos.x+(c.x/2+.001)*sign(a.x-d.pos.x),d.mass?(c=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),e=this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),g=max(this.elasticity,d.elasticity),this.velocity.x=lerp(g,c,e),d.velocity.x=lerp(g,c,f)):this.velocity.x*=-this.elasticity);debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)&&(c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this),d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this),c|!d&&(this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y),d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity))}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=1,b=1,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){if(debug){let a="type = "+this.constructor.name;if(this.pos.x||this.pos.y)a+="\npos = "+this.pos;if(this.velocity.x||this.velocity.y)a+="\nvelocity = "+this.velocity;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.angle&&(a+="\nangle = "+this.angle.toFixed(3));this.color&&(a+="\ncolor = "+this.color);return a}}}"use strict";let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const tileImage=new Image;let tileImageSize,tileImageFixBleed,drawCount;const screenToWorld=a=>{ASSERT(mainCanvasSize.x&&mainCanvasSize.y,"mainCanvasSize is invalid");return a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos)},worldToScreen=a=>{ASSERT(mainCanvasSize.x&&mainCanvasSize.y,"mainCanvasSize is invalid");return a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5))};function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,g,k=new Color(0,0,0,0),h=glEnable){showWatermark&&++drawCount;if(glEnable&&h)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var l=tileImageSize.x/d.x|0;h=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,n=c%l*h;l=(c/l|0)*m;glDraw(a.x,a.y,g?-b.x:b.x,b.y,f,n+tileImageFixBleed.x,l+tileImageFixBleed.y,n-tileImageFixBleed.x+h,l-tileImageFixBleed.y+m,e.rgbaInt(),k.rgbaInt())}else drawCanvas2D(a,b,f,g,m=>{if(0>c)m.fillStyle=e,m.fillRect(-.5,-.5,1,1);else{var n=tileImageSize.x/d.x|0;const p=c%n*d.x+tileFixBleedScale;n=(c/n|0)*d.y+tileFixBleedScale;const q=d.x-2*tileFixBleedScale,r=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,p,n,q,r,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,g,k,h){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,g,k,h)}function drawRectScreenSpace(a,b,c,d,e){drawTileScreenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y+.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",k=fontDefault,h=overlayContext){h.fillStyle=d;h.lineWidth=e;h.strokeStyle=f;h.textAlign=g;h.font=c+"px "+k;h.textBaseline="middle";h.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&h.strokeText(l,b.x,b.y);h.fillText(l,b.x,b.y);b.y+=c})}function drawText(a,b,c=1,d,e=0,f,g,k){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,k,mainContext)}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){engineFontImage||((engineFontImage=new Image).src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((h,l)=>{const m=d?h.length*f.x*c/2|0:0;for(let q=h.length;q--;){var n=h[q].charCodeAt();if(32>n||127<n)n=127;var p=this.startTileIndex+n-32;n=p%k;p=p/k|0;const r=b.add(vec2(q,l).multiply(g));e.drawImage(this.image,n*f.x,p*f.y,f.x,f.y,r.x-m,r.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0,preventDefaultInput=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){isTouchDevice||document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKeyCode(a.keyCode)]=3),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKeyCode(a.keyCode)]=4)};const remapKeyCode=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return vec2(mainCanvas.width,mainCanvas.height).multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=k=>.3<k?percent(k,.3,.8):-.3>k?-percent(-k,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],g[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b=onmousedown,c=onmouseup;onmousedown=onmouseup=()=>0;ontouchstart=d=>{zzfx(0);ontouchstart=ontouchmove=ontouchend=e=>{e.button=0;const f=e.touches.length;f?(e.x=e.touches[0].clientX,e.y=e.touches[0].clientY,a?onmousemove(e):b(e)):a&&c(e);a=f;return!0};return ontouchstart(d)}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function touchGamepadCreate(){touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons=[],touchGamepadStick=vec2(),ontouchstart=a=>{zzfx(0);ontouchstart=ontouchmove=ontouchend=b=>{touchGamepadStick=vec2();touchGamepadButtons=[];if(b.touches.length&&(isUsingGamepad=1,touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}const c=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),d=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),e=mainCanvasSize.scale(.5);for(const f of b.touches)b=mouseToScreen(vec2(f.clientX,f.clientY)),b.distance(c)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=b.subtract(c).scale(2/touchGamepadSize).clampLength():(b=b.subtract(c).angle(),touchGamepadStick.setAngle((4*b/PI+8.5|0)*PI/4)):b.distance(d)<touchGamepadSize?(b=b.subtract(d).direction(),touchGamepadButtons[b]=1):b.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)};return ontouchstart(a)})}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer,4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";overlayContext.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)overlayContext.arc(a.x,a.y,touchGamepadSize/2,0,9),overlayContext.fill();else for(var b=10;b--;){var c=b*PI/4;overlayContext.arc(a.x,a.y,.6*touchGamepadSize,c+PI/8,c+PI/8);b%2&&overlayContext.arc(a.x,a.y,.33*touchGamepadSize,c,c);1==b&&overlayContext.fill()}overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(b=4;b--;)c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a,b=1){if(soundEnable)return this.source=playSamples(this.cachedSamples,a,1,0,b)}stop(){this.source&&this.source.stop();this.source=0}isPlaying(){return this.source}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||=new AudioContext,audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),g=audioContext.createBufferSource();a.forEach((k,h)=>f.getChannelData(h).set(k));g.buffer=f;g.playbackRate.value=c;g.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);g.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);g.start();return g}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,k=1,h=0,l=0,m=0,n=0,p=0,q=0,r=0,w=0,u=0,B=1,z=0,C=0){let v=2*PI,F=h*=500*v/zzfxR/zzfxR,A=[];b=c*=(1+b*rand(-1,1))*v/zzfxR;let x=0,D=0,t=0,y=1,G=0,I=0,E=0,J,H;d=d*zzfxR+9;z*=zzfxR;e*=zzfxR;f*=zzfxR;u*=zzfxR;l*=500*v/zzfxR**3;r*=v/zzfxR;m*=v/zzfxR;n*=zzfxR;p=p*zzfxR|0;for(H=d+z+e+f+u|0;t<H;A[t++]=E)++I%(100*w|0)||(E=g?1<g?2<g?3<g?Math.sin((x%v)**3):max(min(Math.tan(x),1),-1):1-(2*x/v%2+2)%2:1-4*abs(Math.round(x/v)-x/v):Math.sin(x),E=(p?1-C+C*Math.sin(v*t/p):1)*sign(E)*abs(E)**k*a*soundVolume*(t<d?t/d:t<d+z?1-(t-d)/z*(1-B):t<d+z+e?B:t<H-u?(H-t-u)/f*B:0),E=u?E/2+(u>t?0:(t<H-u?1:(H-t)/u)*A[t-u|0]/2):E),J=(c+=h+=l)*Math.cos(r*D++),x+=J-J*q*(1-1e9*(Math.sin(t)+1)%2),y&&++y>n&&(c+=m,b+=m,y=0),!p||++G%p||(c=b,h=F,y=y||1);return A}function zzfxM(a,b,c,d=125){let e,f,g,k,h,l,m,n,p,q,r,w,u,B=0,z,C=[],v=[],F=[],A=0,x=0,D=1,t={},y=zzfxR/d*60>>2;for(;D;A++)C=[D=n=w=0],c.forEach((G,I)=>{m=b[G][A]||[0,0,0];D|=!!b[G][A];z=w+(b[G][0].length-2-!n)*y;u=I==c.length-1;e=2;for(g=w;e<m.length+u;n=++e){h=m[e];p=e==m.length+u-1&&u||q!=(m[0]||0)|h|0;for(f=0;f<y&&n;f++>y-99&&p?r+=(1>r)/99:0)l=(1-r)*C[B++]/2||0,v[g]=(v[g]||0)-l*x+l,F[g]=(F[g++]||0)+l*x+l;h&&(r=h%1,x=m[1]||0,h|=0)&&(C=t[[q=m[B=0]||0,h]]=t[[q,h]]||(k=[...a[q]],k[2]*=2**((h-12)/12),0<h?zzfxG(...k):[]))}w=z});return[v,F]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){var d=(b=b.floor()).subtract(a=a.floor());const e=abs(d.x),f=-abs(d.y),g=sign(d.x);d=sign(d.y);for(let h=a.x,l=a.y,m=e+f;;){var k=getTileCollisionData(vec2(h,l));if(k&&(c?c.collideWithTileRaycast(k,new Vector2(h,l)):0<k))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(h+.5,l+.5),"#ff0",1),new Vector2(h+.5,l+.5);if(h==b.x&l==b.y)break;k=2*m;k>=f&&(m+=f,h+=g);k<=e&&(m+=e,l+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;a&&(mainCanvas.width=this.size.x*this.tileSize.x,mainCanvas.height=this.size.y*this.tileSize.y);enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glEnable&&glCopyToContext(mainContext,1);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,g){this.drawCanvas2D(a,b,f,g,k=>{if(0>c)k.fillStyle=e,k.fillRect(-.5,-.5,1,1);else{const h=tileImage.width/d.x;k.globalAlpha=e.a;k.drawImage(tileImage,c%h*d.x,(c/h|0)*d.y,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g=-1,k=tileSizeDefault,h=new Color,l=new Color,m=new Color(1,1,1,0),n=new Color(1,1,1,0),p=.5,q=.1,r=1,w=.1,u=.05,B=1,z=1,C=0,v=PI,F=.1,A=.2,x,D,t=1,y=D?1e9:0,G){super(a,new Vector2,g,k,b,void 0,y);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h;this.colorStartB=l;this.colorEndA=m;this.colorEndB=n;this.randomColorLinear=t;this.particleTime=p;this.sizeStart=q;this.sizeEnd=r;this.speed=w;this.angleSpeed=u;this.damping=B;this.angleDamping=z;this.gravityScale=C;this.particleConeAngle=v;this.fadeRate=F;this.randomness=A;this.collideTiles=x;this.additive=D;this.localSpace=G;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime|this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(this.emitSize/2),b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);a=new Particle(a,this.tileIndex,this.tileSize,b);const c=this.randomness;var d=m=>m+m*rand(c,-c);b=d(this.particleTime);const e=d(this.sizeStart),f=d(this.sizeEnd),g=d(this.speed);d=d(this.angleSpeed)*randSign();var k=rand(this.emitConeAngle,-this.emitConeAngle);const h=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a.colorStart=h;a.colorEndDelta=l.subtract(h);a.velocity=(new Vector2).setAngle(k,g);a.angleVelocity=d;a.lifeTime=b;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=randInt(2);a.localSpaceEmitter=this.localSpace&&this;a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);let d=this.pos;var e=this.angle;this.localSpaceEmitter&&(d=this.localSpaceEmitter.pos.add(d.rotate(-this.localSpaceEmitter.angle)),e+=this.localSpaceEmitter.angle);if(this.trailScale){var f=this.velocity;this.localSpaceEmitter&&(f=f.rotate(-this.localSpaceEmitter.angle));e=f.length();f=f.scale(1/e);const g=e*this.trailScale;b.y=max(b.x,g);e=f.angle();drawTile(d.add(f.multiply(vec2(0,-g/2))),b,this.tileIndex,this.tileSize,c,e,this.mirror)}else drawTile(d,b,this.tileIndex,this.tileSize,c,e,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(d,b,"#f005",0,e);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=localStorage[b.storageKey()]|0)}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;e&&((this.image=new Image).src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=overlayCanvas.width-c;a*=-medalDisplaySize.y;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9);b.strokeStyle=new Color(0,0,0);b.lineWidth=3;b.fill(b.rect(d,a,c,medalDisplaySize.y));b.stroke();b.clip();this.renderIcon(vec2(d+15+medalDisplayIconSize/2,a+medalDisplaySize.y/2));c=vec2(d+medalDisplayIconSize+30,a+28);drawTextScreen(this.name,c,38,new Color(0,0,0),0,0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,0,"left");b.restore()}renderIcon(a,b=medalDisplayIconSize){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,new Color(0,0,0))}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}let newgrounds;function newgroundsInit(a,b){newgrounds=new Newgrounds(a,b)}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=this.CryptoJS());if(this.session_id=new URL(location.href).searchParams.get("ngio_session_id")){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image=new Image,a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,1),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},1)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},1)}getScores(a,b=0,c=0,d=0,e=10){return this.call("ScoreBoard.getScores",{id:a,user:b,social:c,skip:d,limit:e})}logView(){return this.call("App.logView",{host:this.host},1)}call(a,b=0,c=0){a={component:a,parameters:b};if(this.cipher){b=this.cryptoJS;var d=b.enc.Base64.parse(this.cipher);const e=b.lib.WordArray.random(16);d=b.AES.encrypt(JSON.stringify(a),d,{iv:e});a.secure=b.enc.Base64.stringify(e.concat(d.ciphertext));a.parameters=0}b={app_id:this.app_id,session_id:this.session_id,call:a};a=new FormData;a.append("input",JSON.stringify(b));b=new XMLHttpRequest;b.open("POST","https://newgrounds.io/gateway_v3.php",!debugMedals&&c);b.send(a);debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}CryptoJS(){return eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0))}}"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glArrayBuffer,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec4 v,d,e;void main(){gl_Position=m*vec4(p,1,1);v=vec4(t,p);d=c;e=a;}","precision highp float;varying vec4 v,d,e;uniform sampler2D s;void main(){gl_FragColor=texture2D(s,v.xy)*d+e;}");const a=new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);glArrayBuffer=glContext.createBuffer();glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glBatchCount=0}function glSetBlendMode(a){glAdditive=a}function glSetTexture(a=glTileTexture){a!=glActiveTexture&&glFlush();glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a)}function glCompileShader(a,b){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}function glCreateProgram(a,b){const c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}function glCreateTexture(a){const b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);a&&a.width&&glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);a=cavasPixelated?gl_NEAREST:gl_LINEAR;glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}function glPreRender(){glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glContext.clear(gl_COLOR_BUFFER_BIT);glContext.useProgram(glShader);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_VERTEX_BUFFER_SIZE,gl_DYNAMIC_DRAW);glSetBlendMode();let a=0;var b=(d,e,f,g,k=0)=>{d=glContext.getAttribLocation(glShader,d);glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,k,gl_VERTEX_BYTE_STRIDE,a);a+=g*f};b("p",gl_FLOAT,4,2);b("t",gl_FLOAT,4,2);b("c",gl_UNSIGNED_BYTE,1,4,1);b("a",gl_UNSIGNED_BYTE,1,4,1);b=2*cameraScale/mainCanvas.width;const c=2*cameraScale/mainCanvas.height;glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([b,0,0,0,0,c,0,0,1,1,-1,1,-1-b*cameraPos.x,-1-c*cameraPos.y,0,0]))}function glFlush(){if(glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){if(glBatchCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,g,k,h,l,m=0){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var n=Math.cos(e)/2,p=Math.sin(e)/2;e=n*c;n*=d;c*=p;d*=p;for(let q=6,r=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;q--;){p=q-4&&1<q;const w=q-5&&q-2&&q-1;glPositionData[r++]=a+(p?-e:e)+(w?d:-d);glPositionData[r++]=b+(w?n:-n)+(p?c:-c);glPositionData[r++]=p?f:k;glPositionData[r++]=w?g:h;glColorData[r++]=l;glColorData[r++]=m}}let glPostShader,glPostArrayBuffer,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b){ASSERT(!glPostShader);a||="void mainImage(out vec4 c,vec2 p){c=texture2D(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("precision highp float;attribute vec2 p;void main(){gl_Position=vec4(p,1,1);}","precision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;\n"+a+"\nvoid main(){mainImage(gl_FragColor,gl_FragCoord.xy);gl_FragColor.a=1.;}");glPostArrayBuffer=glContext.createBuffer();glPostTexture=glCreateTexture();glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden"}function glRenderPostProcess(){if(glPostShader){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glPostIncludeOverlay&&(mainContext.drawImage(overlayCanvas,0,0),overlayCanvas.width=mainCanvas.width);glContext.useProgram(glPostShader);glContext.disable(gl_BLEND);glContext.bindBuffer(gl_ARRAY_BUFFER,glPostArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,new Float32Array([-3,1,1,-3,1,1]),gl_STATIC_DRAW);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,!0);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glPostTexture);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,mainCanvas);var a=glContext.getAttribLocation(glPostShader,"p");glContext.enableVertexAttribArray(a);glContext.vertexAttribPointer(a,2,gl_FLOAT,0,8,0);glContext.uniform1i(glContext.getUniformLocation(glPostShader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(glPostShader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(glPostShader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(gl_TRIANGLES,0,3)}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_BYTE=5120,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_TEXTURE0=33984,gl_TEXTURE1=33985,gl_ARRAY_BUFFER=34962,gl_STATIC_DRAW=35044,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_UNPACK_FLIP_Y_WEBGL=37440,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24,gl_VERTEX_BUFFER_SIZE=gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE;const setCameraPos=pos=>cameraPos=pos;const setCameraScale=scale=>cameraScale=scale;const setCanvasMaxSize=size=>canvasMaxSize=size;const setCanvasFixedSize=size=>canvasFixedSize=size;const setCavasPixelated=pixelated=>cavasPixelated=pixelated;const setFontDefault=font=>fontDefault=font;const setGlEnable=enable=>glEnable=enable;const setGlOverlay=overlay=>glOverlay=overlay;const setTileSizeDefault=size=>tileSizeDefault=size;const setTileFixBleedScale=scale=>tileFixBleedScale=scale;const setEnablePhysicsSolver=enable=>enablePhysicsSolver=enable;const setObjectDefaultMass=mass=>objectDefaultMass=mass;const setObjectDefaultDamping=damp=>objectDefaultDamping=damp;const setObjectDefaultAngleDamping=damp=>objectDefaultAngleDamping=damp;const setObjectDefaultElasticity=elasticity=>objectDefaultElasticity=elasticity;const setObjectDefaultFriction=friction=>objectDefaultFriction=friction;const setObjectMaxSpeed=speed=>objectMaxSpeed=speed;const setGravity=g=>gravity=g;const setParticleEmitRateScale=scale=>particleEmitRateScale=scale;const setGamepadsEnable=enable=>gamepadsEnable=enable;const setGamepadDirectionEmulateStick=enable=>gamepadDirectionEmulateStick=enable;const setInputWASDEmulateDirection=enable=>inputWASDEmulateDirection=enable;const setTouchGamepadEnable=enable=>touchGamepadEnable=enable;const setTouchGamepadAnalog=analog=>touchGamepadAnalog=analog;const setTouchGamepadSize=size=>touchGamepadSize=size;const setTouchGamepadAlpha=alpha=>touchGamepadAlpha=alpha;const setVibrateEnable=enable=>vibrateEnable=enable;const setSoundEnable=enable=>soundEnable=enable;const setSoundVolume=volume=>soundVolume=volume;const setSoundDefaultRange=range=>soundDefaultRange=range;const setSoundDefaultTaper=taper=>soundDefaultTaper=taper;const setMedalDisplayTime=time=>medalDisplayTime=time;const setMedalDisplaySlideTime=time=>medalDisplaySlideTime=time;const setMedalDisplaySize=size=>medalDisplaySize=size;const setMedalDisplayIconSize=size=>medalDisplayIconSize=size;const setMedalsPreventUnlock=prevent=>medalsPreventUnlock=prevent;const setShowWatermark=show=>showWatermark=show;const setGodMode=enable=>godMode=enable;export{setCameraPos,setCameraScale,setCanvasMaxSize,setCanvasFixedSize,setCavasPixelated,setFontDefault,setGlEnable,setGlOverlay,setTileSizeDefault,setTileFixBleedScale,setEnablePhysicsSolver,setObjectDefaultMass,setObjectDefaultDamping,setObjectDefaultAngleDamping,setObjectDefaultElasticity,setObjectDefaultFriction,setObjectMaxSpeed,setGravity,setParticleEmitRateScale,setGamepadsEnable,setGamepadDirectionEmulateStick,setInputWASDEmulateDirection,setTouchGamepadEnable,setTouchGamepadAnalog,setTouchGamepadSize,setTouchGamepadAlpha,setVibrateEnable,setSoundEnable,setSoundVolume,setSoundDefaultRange,setSoundDefaultTaper,setMedalDisplayTime,setMedalDisplaySlideTime,setMedalDisplaySize,setMedalDisplayIconSize,setMedalsPreventUnlock,setShowWatermark,setGodMode,canvasMaxSize,canvasFixedSize,cavasPixelated,fontDefault,tileSizeDefault,tileFixBleedScale,enablePhysicsSolver,objectDefaultMass,objectDefaultDamping,objectDefaultAngleDamping,objectDefaultElasticity,objectDefaultFriction,objectMaxSpeed,gravity,particleEmitRateScale,cameraPos,cameraScale,glEnable,glOverlay,gamepadsEnable,gamepadDirectionEmulateStick,inputWASDEmulateDirection,touchGamepadEnable,touchGamepadAnalog,touchGamepadSize,touchGamepadAlpha,vibrateEnable,soundEnable,soundVolume,soundDefaultRange,soundDefaultTaper,medalDisplayTime,medalDisplaySlideTime,medalDisplaySize,medalDisplayIconSize,debug,showWatermark,godMode,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,PI,abs,min,max,sign,mod,clamp,percent,lerp,smoothStep,nearestPowerOfTwo,isOverlapping,wave,formatTime,rand,randInt,randSign,randInCircle,randVector,randColor,randSeed,setRandSeed,randSeeded,Vector2,Color,Timer,vec2,colorRGBA,colorHSLA,EngineObject,tileImage,mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize,screenToWorld,worldToScreen,drawTile,drawRect,drawTileScreenSpace,drawRectScreenSpace,drawLine,drawCanvas2D,setBlendMode,drawTextScreen,drawText,engineFontImage,FontImage,isFullscreen,toggleFullscreen,keyIsDown,keyWasPressed,keyWasReleased,clearInput,mouseIsDown,mouseWasPressed,mouseWasReleased,mousePos,mousePosScreen,mouseWheel,isUsingGamepad,preventDefaultInput,gamepadIsDown,gamepadWasPressed,gamepadWasReleased,gamepadStick,mouseToScreen,gamepadsUpdate,vibrate,vibrateStop,isTouchDevice,Sound,Music,playAudioFile,speak,speakStop,getNoteFrequency,audioContext,playSamples,zzfx,tileCollision,tileCollisionSize,initTileCollision,setTileCollisionData,getTileCollisionData,tileCollisionTest,tileCollisionRaycast,TileLayerData,TileLayer,ParticleEmitter,Particle,medals,medalsPreventUnlock,medalsInit,newgroundsInit,Medal,Newgrounds,glCanvas,glContext,glSetBlendMode,glSetTexture,glCompileShader,glCreateProgram,glCreateTexture,glInitPostProcess,engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback};
@@ -1,127 +0,0 @@
1
- rem Simple build script for LittleJS Engine by Frank Force
2
- rem minfies and combines index.html and index.js and zips the result
3
-
4
- rem --- BUILD ENGINE DEBUG ---
5
-
6
- set OUTPUT_FILENAME=engine.all.js
7
-
8
- rem remove old files
9
- del %OUTPUT_FILENAME%
10
-
11
- rem combine code
12
- type engineDebug.js >> %OUTPUT_FILENAME%
13
- echo.>> %OUTPUT_FILENAME%
14
- type engineUtilities.js >> %OUTPUT_FILENAME%
15
- echo.>> %OUTPUT_FILENAME%
16
- type engineSettings.js >> %OUTPUT_FILENAME%
17
- echo.>> %OUTPUT_FILENAME%
18
- type engineObject.js >> %OUTPUT_FILENAME%
19
- echo.>> %OUTPUT_FILENAME%
20
- type engineDraw.js >> %OUTPUT_FILENAME%
21
- echo.>> %OUTPUT_FILENAME%
22
- type engineInput.js >> %OUTPUT_FILENAME%
23
- echo.>> %OUTPUT_FILENAME%
24
- type engineAudio.js >> %OUTPUT_FILENAME%
25
- echo.>> %OUTPUT_FILENAME%
26
- type engineTileLayer.js >> %OUTPUT_FILENAME%
27
- echo.>> %OUTPUT_FILENAME%
28
- type engineParticles.js >> %OUTPUT_FILENAME%
29
- echo.>> %OUTPUT_FILENAME%
30
- type engineMedals.js >> %OUTPUT_FILENAME%
31
- echo.>> %OUTPUT_FILENAME%
32
- type engineWebGL.js >> %OUTPUT_FILENAME%
33
- echo.>> %OUTPUT_FILENAME%
34
- type engine.js >> %OUTPUT_FILENAME%
35
- echo.>> %OUTPUT_FILENAME%
36
-
37
- rem --- BUILD ENGINE RELEASE ---
38
-
39
- set OUTPUT_FILENAME=engine.all.release.js
40
-
41
- rem remove old files
42
- del %OUTPUT_FILENAME%
43
-
44
- rem combine code
45
- type engineRelease.js >> %OUTPUT_FILENAME%
46
- echo.>> %OUTPUT_FILENAME%
47
- type engineUtilities.js >> %OUTPUT_FILENAME%
48
- echo.>> %OUTPUT_FILENAME%
49
- type engineSettings.js >> %OUTPUT_FILENAME%
50
- echo.>> %OUTPUT_FILENAME%
51
- type engine.js >> %OUTPUT_FILENAME%
52
- echo.>> %OUTPUT_FILENAME%
53
- type engineObject.js >> %OUTPUT_FILENAME%
54
- echo.>> %OUTPUT_FILENAME%
55
- type engineDraw.js >> %OUTPUT_FILENAME%
56
- echo.>> %OUTPUT_FILENAME%
57
- type engineInput.js >> %OUTPUT_FILENAME%
58
- echo.>> %OUTPUT_FILENAME%
59
- type engineAudio.js >> %OUTPUT_FILENAME%
60
- echo.>> %OUTPUT_FILENAME%
61
- type engineTileLayer.js >> %OUTPUT_FILENAME%
62
- echo.>> %OUTPUT_FILENAME%
63
- type engineParticles.js >> %OUTPUT_FILENAME%
64
- echo.>> %OUTPUT_FILENAME%
65
- type engineMedals.js >> %OUTPUT_FILENAME%
66
- echo.>> %OUTPUT_FILENAME%
67
- type engineWebGL.js >> %OUTPUT_FILENAME%
68
- echo.>> %OUTPUT_FILENAME%
69
-
70
- rem --- BUILD ENGINE MINIFIED ---
71
-
72
- set OUTPUT_FILENAME=engine.all.min.js
73
-
74
- rem remove old files
75
- del %OUTPUT_FILENAME%
76
-
77
- rem start with release build
78
- copy engine.all.release.js %OUTPUT_FILENAME%
79
-
80
- rem check code with closure
81
- move %OUTPUT_FILENAME% %OUTPUT_FILENAME%.temp
82
- call npx google-closure-compiler --js=%OUTPUT_FILENAME%.temp --js_output_file=%OUTPUT_FILENAME% --language_out=ECMASCRIPT_2021 --warning_level=VERBOSE --jscomp_off=*
83
- del %OUTPUT_FILENAME%.temp
84
- if %ERRORLEVEL% NEQ 0 (
85
- pause
86
- exit /b %ERRORLEVEL%
87
- )
88
-
89
- rem lightly minify with uglify
90
- call npx uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
91
- if %ERRORLEVEL% NEQ 0 (
92
- pause
93
- exit /b %ERRORLEVEL%
94
- )
95
-
96
- rem --- BUILD ENGINE MODULE ---
97
-
98
- set OUTPUT_FILENAME=engine.all.module.js
99
- del %OUTPUT_FILENAME%
100
- type engine.all.js >> %OUTPUT_FILENAME%
101
- echo.>> %OUTPUT_FILENAME%
102
- type engineExport.js >> %OUTPUT_FILENAME%
103
- echo.>> %OUTPUT_FILENAME%
104
-
105
- rem --- BUILD ENGINE MODULE RELEASE ---
106
-
107
- set OUTPUT_FILENAME=engine.all.module.min.js
108
- del %OUTPUT_FILENAME%
109
- type engine.all.min.js >> %OUTPUT_FILENAME%
110
- echo.>> %OUTPUT_FILENAME%
111
- type engineExport.js >> %OUTPUT_FILENAME%
112
- echo.>> %OUTPUT_FILENAME%
113
-
114
- rem lightly minify with uglify
115
- call npx uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
116
- if %ERRORLEVEL% NEQ 0 (
117
- pause
118
- exit /b %ERRORLEVEL%
119
- )
120
-
121
- rem --- BUILD TYPESCRIPT DEFINITIONS ---
122
-
123
- call npx tsc engine.all.module.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
124
- if %ERRORLEVEL% NEQ 0 (
125
- pause
126
- exit /b %ERRORLEVEL%
127
- )
package/index.html DELETED
@@ -1,26 +0,0 @@
1
- <html><head>
2
- <meta name=viewport content=width=device-width,height=device-height,initial-scale=1,maximum-scale=1>
3
- <meta name=apple-mobile-web-app-capable content=yes>
4
- <meta name=mobile-web-app-capable content=yes>
5
- <link rel=icon type=image/png href=favicon.png>
6
- </head><body>
7
-
8
- <!-- LittleJS engine scripts -->
9
- <script src=engine/engineDebug.js?125></script>
10
- <script src=engine/engineUtilities.js?125></script>
11
- <script src=engine/engineSettings.js?125></script>
12
- <script src=engine/engineObject.js?125></script>
13
- <script src=engine/engineDraw.js?125></script>
14
- <script src=engine/engineInput.js?125></script>
15
- <script src=engine/engineAudio.js?125></script>
16
- <script src=engine/engineTileLayer.js?125></script>
17
- <script src=engine/engineParticles.js?125></script>
18
- <script src=engine/engineMedals.js?125></script>
19
- <script src=engine/engineWebGL.js?125></script>
20
- <script src=engine/engine.js?125></script>
21
-
22
- <!-- You can also include all engine scripts like this... -->
23
- <!-- <script src=engine/engine.all.js></script> -->
24
-
25
- <!-- Add your game scripts here -->
26
- <script src=game.js?125></script>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes