littlejsengine 1.2.9 → 1.3.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.
package/README.md CHANGED
@@ -41,7 +41,7 @@ To easily include LittleJS in your game, you can use one of the 3 pre-built js f
41
41
  - [engine.all.release.js](https://github.com/KilledByAPixel/LittleJS/blob/main/engine/engine.all.release.js) - The engine optimized for release builds
42
42
  - [engine.all.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/engine/engine.all.min.js) - The engine in release mode and minified
43
43
 
44
- The hello world example includes a batch file [build.bat](https://github.com/KilledByAPixel/LittleJS/blob/main/build.bat) that compresses everything into a tiny zip file using Google Closure, UglifyJS, Roadroller, and ECT.
44
+ The hello world example includes a batch file [build.bat](https://github.com/KilledByAPixel/LittleJS/blob/main/build.bat) that compresses everything into a tiny zip file using Google Closure, UglifyJS, Roadroller, and ECT. You must run buildSetup.bat to install the necessary npm dependencies.
45
45
 
46
46
  ## Games Made With LittleJS
47
47
 
package/build.bat CHANGED
@@ -1,6 +1,6 @@
1
1
  rem Simple build script for LittleJS by Frank Force
2
2
  rem Minfies and combines index.html and index.js and zips the result
3
- rem See the readme for a list of required dependencies.
3
+ rem Run buildSetup.bat to install required dependencies.
4
4
 
5
5
  set NAME=game
6
6
  set BUILD_FOLDER=build
@@ -34,7 +34,7 @@ copy ..\tiles.png tiles.png
34
34
 
35
35
  rem minify code with closure
36
36
  move %BUILD_FILENAME% %BUILD_FILENAME%.temp
37
- call google-closure-compiler --js %BUILD_FILENAME%.temp --js_output_file %BUILD_FILENAME% --compilation_level ADVANCED --language_out ECMASCRIPT_2019 --warning_level VERBOSE --jscomp_off * --assume_function_wrapper
37
+ call npx google-closure-compiler --js=%BUILD_FILENAME%.temp --js_output_file=%BUILD_FILENAME% --compilation_level=ADVANCED --language_out=ECMASCRIPT_2019 --warning_level=VERBOSE --jscomp_off=* --assume_function_wrapper
38
38
  if %ERRORLEVEL% NEQ 0 (
39
39
  pause
40
40
  exit /b %ERRORLEVEL%
@@ -42,7 +42,7 @@ if %ERRORLEVEL% NEQ 0 (
42
42
  del %BUILD_FILENAME%.temp
43
43
 
44
44
  rem more minification with uglify or terser (they both do about the same)
45
- call uglifyjs -o %BUILD_FILENAME% --compress --mangle -- %BUILD_FILENAME%
45
+ call npx uglifyjs -o %BUILD_FILENAME% --compress --mangle -- %BUILD_FILENAME%
46
46
  rem call terser -o %BUILD_FILENAME% --compress --mangle -- %BUILD_FILENAME%
47
47
  if %ERRORLEVEL% NEQ 0 (
48
48
  pause
@@ -51,7 +51,7 @@ if %ERRORLEVEL% NEQ 0 (
51
51
 
52
52
  rem roadroaller compresses the code better then zip
53
53
  copy %BUILD_FILENAME% roadroller_%BUILD_FILENAME%
54
- call roadroller roadroller_%BUILD_FILENAME% -o roadroller_%BUILD_FILENAME%
54
+ call npx roadroller roadroller_%BUILD_FILENAME% -o roadroller_%BUILD_FILENAME%
55
55
  if %ERRORLEVEL% NEQ 0 (
56
56
  pause
57
57
  exit /b %ERRORLEVEL%
@@ -64,7 +64,7 @@ type roadroller_%BUILD_FILENAME% >> index.html
64
64
  echo ^</script^> >> index.html
65
65
 
66
66
  rem zip the result, ect is recommended
67
- call ect -9 -strip -zip ..\%NAME%.zip index.html tiles.png
67
+ call ..\node_modules\ect-bin\vendor\win32\ect.exe -9 -strip -zip ..\%NAME%.zip index.html tiles.png
68
68
  if %ERRORLEVEL% NEQ 0 (
69
69
  pause
70
70
  exit /b %ERRORLEVEL%
package/buildSetup.bat ADDED
@@ -0,0 +1,7 @@
1
+ rem Run this file to install the necessary npm depencies.
2
+
3
+ call npm install google-closure-compiler
4
+ call npm install uglify-js
5
+ call npm install roadroller
6
+ call npm install ect-bin
7
+ call npm install typescript
@@ -4056,7 +4056,7 @@ gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2; // vec2 * 2 + (char * 4) * 2
4056
4056
  const engineName = 'LittleJS';
4057
4057
 
4058
4058
  /** Version of engine */
4059
- const engineVersion = '1.2.8';
4059
+ const engineVersion = '1.3.0';
4060
4060
 
4061
4061
  /** Frames per second to update objects
4062
4062
  * @default */
@@ -1 +1 @@
1
- const debug=0,showWatermark=0,godMode=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*(rand(2)|0)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(void 0!=a.x);return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(void 0!=a.x);return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(void 0!=a.x);return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(void 0!=a.x);return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(void 0==a.x);return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(void 0!=a.x);return this.x*a.x+this.y*a.y}cross(a){ASSERT(void 0!=a.x);return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return this.x*this.y}lerp(a,b){ASSERT(void 0!=a.x);return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>(h=(h%1+1)%1)<1/6?f+6*(g-f)*h:.5>h?g:h<2/3?f+(g-f)*(2/3-h)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return`rgb(${255*this.r|0},${255*this.g|0},${255*this.b|0},${this.a})`}rgbaInt(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return(255*this.r|0)+(255*this.g<<8)+(255*this.b<<16)+(255*this.a<<24)}hex(){const a=b=>(16>(b=255*b|0)?"0":"")+b.toString(16);return"#"+a(this.r)+a(this.g)+a(this.b)}setHex(a){this.r=parseInt(a.slice(1,3),16)/255;this.g=parseInt(a.slice(3,5),16)/255;this.b=parseInt(a.slice(5,7),16)/255;this.a=1;ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b);return this}}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(){return this.unset()?"unset":Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after")}}"use strict";let canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",tileSizeDefault=vec2(16),tileFixBleedScale=.3,objectDefaultSize=vec2(1),objectDefaultMass=1,objectDefaultDamping=.99,objectDefaultAngleDamping=.99,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,cameraPos=vec2(),cameraScale=max(tileSizeDefault.x,tileSizeDefault.y),glEnable=1,glOverlay=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadAnalog=1,touchGamepadSize=80,touchGamepadAlpha=.3,vibrateEnable=1,soundVolume=.5,soundEnable=1,soundDefaultRange=30,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplayWidth=640,medalDisplayHeight=80,medalDisplayIconSize=50;"use strict";const engineName="LittleJS",engineVersion="1.2.8",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0,frameTimeLastMS=0,frameTimeBufferMS=0,tileImageSize,tileImageFixBleed,averageFPS,drawCount;const styleBody="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none",styleCanvas="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";function engineInit(a,b,c,d,e,f){tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style=styleBody;document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");mainCanvas.style=styleCanvas;debugInit();glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");overlayCanvas.style=styleCanvas;a();touchGamepadCreate();g()};const g=(h=0)=>{var k=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS||0,1e3/(k||1));debug&&(k*=keyIsDown(107)?5:keyIsDown(109)?.2:1);timeReal+=k/1e3;frameTimeBufferMS=min(frameTimeBufferMS+!paused*k,50);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{h=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(h=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=h}canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,h=innerWidth/innerHeight,k=mainCanvas.width/mainCanvas.height,mainCanvas.style.width=overlayCanvas.style.width=h<k?"100%":"",mainCanvas.style.height=overlayCanvas.style.height=h<k?"":"100%",glCanvas&&(glCanvas.style.width=mainCanvas.style.width,glCanvas.style.height=mainCanvas.style.height)):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y));enginePreRender();d();engineObjects.sort((m,p)=>m.renderOrder-p.renderOrder);for(var n of engineObjects)n.destroyed||n.render();e();medalsRender();touchGamepadRender();debugRender();glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",n=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+" "+(glEnable?"GL":"2D"),overlayContext.fillText(n,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(n,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)};f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(overlayCanvas.width=mainCanvas.width,overlayCanvas.height=mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glPreRender(mainCanvas.width,mainCanvas.height,cameraPos.x,cameraPos.y,cameraScale)}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=objectDefaultSize,c=-1,d=tileSizeDefault,e=0,f,g=0){ASSERT(a&&void 0!=a.x&&void 0!=b.x);this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=g;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y=this.damping*this.velocity.y+gravity*this.gravityScale,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide)if(!(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this||!isOverlapping(this.pos,this.size,d.pos,d.size)||!this.collideWithObject(d)|!d.collideWithObject(this)))if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00")}else{c=this.size.add(d.size);e=2*(a.y-d.pos.y)>c.y+gravity;var f=2*abs(a.y-d.pos.y)<c.y,g=2*abs(a.x-d.pos.x)<c.x;if(e||g||!f)if(this.pos.y=d.pos.y+(c.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-this.elasticity;else if(d.mass){const h=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass),k=this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass),n=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass),m=max(this.elasticity,d.elasticity);this.velocity.y=lerp(m,h,k);d.velocity.y=lerp(m,h,n)}e||!f&&g||(this.pos.x=d.pos.x+(c.x/2+.001)*sign(a.x-d.pos.x),d.mass?(c=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),e=this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),g=max(this.elasticity,d.elasticity),this.velocity.x=lerp(g,c,e),d.velocity.x=lerp(g,c,f)):this.velocity.x*=-this.elasticity);debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}if(this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)){c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this);if(c||!d)this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y;d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity)}}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=0,b=0,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){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";const tileImage=new Image;let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const screenToWorld=a=>a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos),worldToScreen=a=>a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,g,h=new Color(0,0,0,0),k=glEnable){showWatermark&&++drawCount;if(glEnable&&k)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var n=tileImageSize.x/d.x|0;k=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,p=c%n*k;n=(c/n|0)*m;glDraw(a.x,a.y,g?-b.x:b.x,b.y,f,p+tileImageFixBleed.x,n+tileImageFixBleed.y,p-tileImageFixBleed.x+k,n-tileImageFixBleed.y+m,e.rgbaInt(),h.rgbaInt())}else drawCanvas2D(a,b,f,g,m=>{if(0>c)m.fillStyle=e,m.fillRect(-.5,-.5,1,1);else{var p=tileImageSize.x/d.x|0;const l=c%p*d.x+tileFixBleedScale;p=(c/p|0)*d.y+tileFixBleedScale;const u=d.x-2*tileFixBleedScale,v=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,l,p,u,v,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,g,h,k){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,g,h,k)}function drawRectScreenSpace(a,b,c,d,e){drawTileSrceenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),0,0,e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y-.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",h=fontDefault){overlayContext.fillStyle=d;overlayContext.lineWidth=e*=cameraScale;overlayContext.strokeStyle=f;overlayContext.textAlign=g;overlayContext.font=c+"px "+h;overlayContext.textBaseline="middle";b=b.copy();a.split("\n").forEach(k=>{e&&overlayContext.strokeText(k,b.x,b.y);overlayContext.fillText(k,b.x,b.y);b.y+=c})}function drawText(a,b,c=1,d,e,f,g,h){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e,f,g,h)}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){a||engineFontImage||(engineFontImage=new Image,engineFontImage.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;a.split("\n").forEach((k,n)=>{const m=d?k.length*f.x*c/2|0:0;for(let u=k.length;u--;){var p=k[u].charCodeAt();if(32>p||127<p)p=127;var l=this.startTileIndex+p-32;p=l%h;l=l/h|0;const v=b.add(vec2(u,n).multiply(g));e.drawImage(this.image,p*f.x,l*f.y,f.x,f.y,v.x-m,v.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen?document.exitFullscreen():document.mozCancelFullScreen&&document.mozCancelFullScreen():document.body.webkitRequestFullScreen?document.body.webkitRequestFullScreen():document.body.mozRequestFullScreen&&document.body.mozRequestFullScreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1?1:0,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKeyCode(a.keyCode)]=3),debug||a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKeyCode(a.keyCode)]=4)};const remapKeyCode=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return mainCanvasSize.multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],g[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&Navigator.vibrate&&Navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b;ontouchstart=ontouchmove=ontouchend=c=>{c.button=0;const d=c.touches.length;d?(b||zzfx(0,b=1),c.x=c.touches[0].clientX,c.y=c.touches[0].clientY,a?onmousemove(c):onmousedown(c)):a&&onmouseup(c);a=d;return!c.cancelable}}let touchGamepadTimer=new Timer,touchGamepadButtons=[],touchGamepadStick=vec2();function touchGamepadCreate(){touchGamepadEnable&&isTouchDevice&&(ontouchstart=ontouchmove=ontouchend=a=>{if(touchGamepadEnable){touchGamepadStick=vec2();touchGamepadButtons=[];if(a.touches.length&&(touchGamepadTimer.isSet()||zzfx(0),isUsingGamepad=1,touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}var b=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),c=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),d=mainCanvasSize.scale(.5);for(const e of a.touches)a=mouseToScreen(vec2(e.clientX,e.clientY)),a.distance(b)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=a.subtract(b).scale(2/touchGamepadSize).clampLength():(a=a.subtract(b).angle(),touchGamepadStick.setAngle((4*a/PI+8.5|0)*PI/4)):a.distance(c)<touchGamepadSize?(a=a.subtract(c).direction(),touchGamepadButtons[a]=1):a.distance(d)<touchGamepadSize&&(touchGamepadButtons[9]=1)}})}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";overlayContext.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)overlayContext.arc(a.x,a.y,touchGamepadSize/2,0,9),overlayContext.fill();else for(var b=10;b--;){var c=b*PI/4;overlayContext.arc(a.x,a.y,.6*touchGamepadSize,c+PI/8,c+PI/8);b%2&&overlayContext.arc(a.x,a.y,.33*touchGamepadSize,c,c);1==b&&overlayContext.fill()}overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(b=4;b--;)c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e=0;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c=1){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a=1,b=1){if(soundEnable)return playSamples(this.cachedSamples,a,1,0,b)}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||(audioContext=new(window.AudioContext||webkitAudioContext)),audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),g=audioContext.createBufferSource();a.forEach((h,k)=>f.getChannelData(k).set(h));g.buffer=f;g.playbackRate.value=c;g.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);(window.StereoPannerNode?g.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})):g).connect(a);g.start();return g}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,n=0,m=0,p=0,l=0,u=0,v=0,A=0,r=0,B=1,y=0,C=0){let t=2*PI,F=k*=500*t/zzfxR/zzfxR,z=[];b=c*=(1+b*rand(-1,1))*t/zzfxR;let w=0,D=0,q=0,x=1,H=0,I=0,E=0,J,G;d=d*zzfxR+9;y*=zzfxR;e*=zzfxR;f*=zzfxR;r*=zzfxR;n*=500*t/zzfxR**3;v*=t/zzfxR;m*=t/zzfxR;p*=zzfxR;l=l*zzfxR|0;for(G=d+y+e+f+r|0;q<G;z[q++]=E)++I%(100*A|0)||(E=g?1<g?2<g?3<g?Math.sin((w%t)**3):Math.max(Math.min(Math.tan(w),1),-1):1-(2*w/t%2+2)%2:1-4*abs(Math.round(w/t)-w/t):Math.sin(w),E=(l?1-C+C*Math.sin(t*q/l):1)*(0<E?1:-1)*abs(E)**h*a*soundVolume*(q<d?q/d:q<d+y?1-(q-d)/y*(1-B):q<d+y+e?B:q<G-r?(G-q-r)/f*B:0),E=r?E/2+(r>q?0:(q<G-r?1:(G-q)/r)*z[q-r|0]/2):E),J=(c+=k+=n)*Math.cos(v*D++),w+=J-J*u*(1-1e9*(Math.sin(q)+1)%2),x&&++x>p&&(c+=m,b+=m,x=0),!l||++H%l||(c=b,k=F,x=x||1);return z}function zzfxM(a,b,c,d=125){let e,f,g,h,k,n,m,p,l,u,v,A,r,B=0,y,C=[],t=[],F=[],z=0,w=0,D=1,q={},x=zzfxR/d*60>>2;for(;D;z++)C=[D=p=A=0],c.forEach((H,I)=>{m=b[H][z]||[0,0,0];D|=!!b[H][z];y=A+(b[H][0].length-2-!p)*x;r=I==c.length-1;f=2;for(h=A;f<m.length+r;p=++f){k=m[f];l=f==m.length+r-1&&r||u!=(m[0]||0)|k|0;for(g=0;g<x&&p;g++>x-99&&l?v+=(1>v)/99:0)n=(1-v)*C[B++]/2||0,t[h]=(t[h]||0)-n*w+n,F[h]=(F[h++]||0)+n*w+n;k&&(v=k%1,w=m[1]||0,k|=0)&&(C=q[[u=m[B=0]||0,k]]=q[[u,k]]||(e=[...a[u]],e[2]*=2**((k-12)/12),0<k?zzfxG(...e):[]))}A=y});return[t,F]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){a=a.floor();b=b.floor();var d=b.subtract(a);const e=abs(d.x),f=-abs(d.y),g=sign(d.x);d=sign(d.y);let h=e+f;for(let n=a.x,m=a.y;;){var k=getTileCollisionData(vec2(n,m));if(k&&(c?c.collideWithTileRaycast(k,new Vector2(n,m)):0<k))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(n+.5,m+.5),"#ff0",1),new Vector2(n+.5,m+.5);if(n==b.x&m==b.y)break;k=2*h;k>=f&&(h+=f,n+=g);k<=e&&(h+=e,m+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){a&&(this.canvas.width=this.size.x*this.tileSize.x,this.canvas.height=this.size.y*this.tileSize.y);this.savedRenderSettings=[mainCanvas,mainContext,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glCopyToContext(mainContext,1);[mainCanvas,mainContext,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,g){this.drawCanvas2D(a,b,f,g,h=>{if(0>c)h.fillStyle=e,h.fillRect(-.5,-.5,1,1);else{const k=tileImage.width/d.x;h.globalAlpha=e.a;h.drawImage(tileImage,c%k*d.x,(c/k|0)*d.x,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g=-1,h=tileSizeDefault,k=new Color,n=new Color,m=new Color(1,1,1,0),p=new Color(1,1,1,0),l=.5,u=.1,v=1,A=.1,r=.05,B=1,y=1,C=0,t=PI,F=.1,z=.2,w,D,q=1,x=D?1e9:0){super(a,new Vector2,g,h,b,void 0,x);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=k;this.colorStartB=n;this.colorEndA=m;this.colorEndB=p;this.randomColorLinear=q;this.particleTime=l;this.sizeStart=u;this.sizeEnd=v;this.speed=A;this.angleSpeed=r;this.damping=B;this.angleDamping=y;this.gravityScale=C;this.particleConeAngle=t;this.fadeRate=F;this.randomness=z;this.collideTiles=w;this.additive=D;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(.5*this.emitSize);a=new Particle(this.pos.add(a),this.tileIndex,this.tileSize,this.angle+rand(this.particleConeAngle,-this.particleConeAngle));const b=this.randomness;var c=m=>m+m*rand(b,-b);const d=c(this.particleTime),e=c(this.sizeStart),f=c(this.sizeEnd),g=c(this.speed);c=c(this.angleSpeed)*randSign();const h=rand(this.emitConeAngle,-this.emitConeAngle),k=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);a.colorStart=k;a.colorEndDelta=n.subtract(k);a.velocity=(new Vector2).setAngle(this.angle+h,g);a.angleVelocity=c;a.lifeTime=d;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=.5>rand();a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);if(this.trailScale){var d=this.velocity.length();const e=this.velocity.scale(1/d);d*=this.trailScale;b.y=max(b.x,d);this.angle=e.angle();drawTile(this.pos.add(e.multiply(vec2(0,-d/2))),b,this.tileIndex,this.tileSize,c,this.angle,this.mirror)}else drawTile(this.pos,b,this.tileIndex,this.tileSize,c,this.angle,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(this.pos,b,"#f005",0,this.angle);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsPreventUnlock,newgrounds,medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>localStorage[b.storageKey()])}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;this.image=new Image;e&&(this.image.src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id),localStorage["OS13kTrophy,"+this.icon+","+medalsSaveName+","+this.name]=this.description)}render(a=0){const b=overlayContext,c=min(medalDisplayWidth,mainCanvas.width),d=overlayCanvas.width-c;a*=-medalDisplayHeight;b.save();b.beginPath();b.fillStyle="#ddd";b.fill(b.rect(d,a,c,medalDisplayHeight));b.strokeStyle="#000";b.lineWidth=3;b.stroke();b.clip();this.renderIcon(d+15+medalDisplayIconSize/2,a+medalDisplayHeight/2);b.textAlign="left";b.font="38px "+fontDefault;b.fillText(this.name,d+medalDisplayIconSize+30,a+28);b.font="24px "+fontDefault;b.fillText(this.description,d+medalDisplayIconSize+30,a+60);b.restore()}renderIcon(a,b,c=medalDisplayIconSize){const d=overlayContext;d.fillStyle="#000";d.textAlign="center";d.textBaseline="middle";d.font=.7*c+"px "+fontDefault;this.image.src?d.drawImage(this.image,a-c/2,b-c/2,c,c):d.fillText(this.icon,a,b)}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=CryptoJS());this.session_id=new URL(window.location.href).searchParams.get("ngio_session_id")||0;if(0!=this.session_id){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);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)}}const CryptoJS=()=>eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0));"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){if(glEnable){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glCanvas.style=styleCanvas;glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec2 v;varying vec4 d,e;void main(){gl_Position=m*vec4(p,1,1);v=t;d=c;e=a;}","precision highp float;varying vec2 v;varying vec4 d,e;uniform sampler2D s;void main(){gl_FragColor=texture2D(s,v)*d+e;}");var a=new ArrayBuffer(gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE);glCreateBuffer(gl_ARRAY_BUFFER,a.byteLength,gl_DYNAMIC_DRAW);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);var b=glBatchCount=0;a=(c,d,e,f,g=0)=>{c=glContext.getAttribLocation(glShader,c);glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,g,gl_VERTEX_BYTE_STRIDE,b);b+=f*e};a("p",gl_FLOAT,4,2);a("t",gl_FLOAT,4,2);a("c",gl_UNSIGNED_BYTE,1,4,1);a("a",gl_UNSIGNED_BYTE,1,4,1)}}function glSetBlendMode(a){glEnable&&(glAdditive=a)}function glSetTexture(a=glTileTexture){glEnable&&(a!=glActiveTexture&&glFlush(),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a))}function glCompileShader(a,b){if(glEnable){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glEnable){var c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}}function glCreateBuffer(a,b,c){if(glEnable){var d=glContext.createBuffer();glContext.bindBuffer(a,d);glContext.bufferData(a,b,c);return d}}function glCreateTexture(a){if(glEnable&&a&&a.width){var b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}}function glPreRender(a,b,c,d,e){glEnable&&(glContext.viewport(0,0,glCanvas.width=a,glCanvas.height=b),glContext.clear(gl_COLOR_BUFFER_BIT),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture),glContext.useProgram(glShader),glSetBlendMode(),a=2*e/a,b=2*e/b,glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([a,0,0,0,0,b,0,0,1,1,-1,1,-1-a*c,-1-b*d,0,0])))}function glFlush(){if(glEnable&&glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){glEnable&&glBatchCount&&(glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0))}function glDraw(a,b,c,d,e,f,g,h,k,n=4294967295,m=0){if(glEnable){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var p=Math.cos(e)/2,l=Math.sin(e)/2;e=p*c;p*=d;c*=l;d*=l;l=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;glPositionData[l++]=a-e-d;glPositionData[l++]=b-p+c;glPositionData[l++]=f;glPositionData[l++]=k;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a+e+d;glPositionData[l++]=b+p-c;glPositionData[l++]=h;glPositionData[l++]=g;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a-e+d;glPositionData[l++]=b+p+c;glPositionData[l++]=f;glPositionData[l++]=g;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a-e-d;glPositionData[l++]=b-p+c;glPositionData[l++]=f;glPositionData[l++]=k;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a+e-d;glPositionData[l++]=b-p-c;glPositionData[l++]=h;glPositionData[l++]=k;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a+e+d;glPositionData[l++]=b+p-c;glPositionData[l++]=h;glPositionData[l++]=g;glColorData[l++]=n;glColorData[l++]=m}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_ARRAY_BUFFER=34962,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24;
1
+ const debug=0,showWatermark=0,godMode=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*(rand(2)|0)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(void 0!=a.x);return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(void 0!=a.x);return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(void 0!=a.x);return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(void 0!=a.x);return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(void 0==a.x);return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(void 0!=a.x);return this.x*a.x+this.y*a.y}cross(a){ASSERT(void 0!=a.x);return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return this.x*this.y}lerp(a,b){ASSERT(void 0!=a.x);return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>(h=(h%1+1)%1)<1/6?f+6*(g-f)*h:.5>h?g:h<2/3?f+(g-f)*(2/3-h)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return`rgb(${255*this.r|0},${255*this.g|0},${255*this.b|0},${this.a})`}rgbaInt(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return(255*this.r|0)+(255*this.g<<8)+(255*this.b<<16)+(255*this.a<<24)}hex(){const a=b=>(16>(b=255*b|0)?"0":"")+b.toString(16);return"#"+a(this.r)+a(this.g)+a(this.b)}setHex(a){this.r=parseInt(a.slice(1,3),16)/255;this.g=parseInt(a.slice(3,5),16)/255;this.b=parseInt(a.slice(5,7),16)/255;this.a=1;ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b);return this}}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(){return this.unset()?"unset":Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after")}}"use strict";let canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",tileSizeDefault=vec2(16),tileFixBleedScale=.3,objectDefaultSize=vec2(1),objectDefaultMass=1,objectDefaultDamping=.99,objectDefaultAngleDamping=.99,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,cameraPos=vec2(),cameraScale=max(tileSizeDefault.x,tileSizeDefault.y),glEnable=1,glOverlay=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadAnalog=1,touchGamepadSize=80,touchGamepadAlpha=.3,vibrateEnable=1,soundVolume=.5,soundEnable=1,soundDefaultRange=30,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplayWidth=640,medalDisplayHeight=80,medalDisplayIconSize=50;"use strict";const engineName="LittleJS",engineVersion="1.3.0",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0,frameTimeLastMS=0,frameTimeBufferMS=0,tileImageSize,tileImageFixBleed,averageFPS,drawCount;const styleBody="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none",styleCanvas="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";function engineInit(a,b,c,d,e,f){tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style=styleBody;document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");mainCanvas.style=styleCanvas;debugInit();glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");overlayCanvas.style=styleCanvas;a();touchGamepadCreate();g()};const g=(h=0)=>{var k=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS||0,1e3/(k||1));debug&&(k*=keyIsDown(107)?5:keyIsDown(109)?.2:1);timeReal+=k/1e3;frameTimeBufferMS=min(frameTimeBufferMS+!paused*k,50);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{h=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(h=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=h}canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,h=innerWidth/innerHeight,k=mainCanvas.width/mainCanvas.height,mainCanvas.style.width=overlayCanvas.style.width=h<k?"100%":"",mainCanvas.style.height=overlayCanvas.style.height=h<k?"":"100%",glCanvas&&(glCanvas.style.width=mainCanvas.style.width,glCanvas.style.height=mainCanvas.style.height)):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y));enginePreRender();d();engineObjects.sort((m,p)=>m.renderOrder-p.renderOrder);for(var n of engineObjects)n.destroyed||n.render();e();medalsRender();touchGamepadRender();debugRender();glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",n=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+" "+(glEnable?"GL":"2D"),overlayContext.fillText(n,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(n,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)};f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(overlayCanvas.width=mainCanvas.width,overlayCanvas.height=mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glPreRender(mainCanvas.width,mainCanvas.height,cameraPos.x,cameraPos.y,cameraScale)}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=objectDefaultSize,c=-1,d=tileSizeDefault,e=0,f,g=0){ASSERT(a&&void 0!=a.x&&void 0!=b.x);this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=g;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y=this.damping*this.velocity.y+gravity*this.gravityScale,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide)if(!(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this||!isOverlapping(this.pos,this.size,d.pos,d.size)||!this.collideWithObject(d)|!d.collideWithObject(this)))if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00")}else{c=this.size.add(d.size);e=2*(a.y-d.pos.y)>c.y+gravity;var f=2*abs(a.y-d.pos.y)<c.y,g=2*abs(a.x-d.pos.x)<c.x;if(e||g||!f)if(this.pos.y=d.pos.y+(c.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-this.elasticity;else if(d.mass){const h=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass),k=this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass),n=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass),m=max(this.elasticity,d.elasticity);this.velocity.y=lerp(m,h,k);d.velocity.y=lerp(m,h,n)}e||!f&&g||(this.pos.x=d.pos.x+(c.x/2+.001)*sign(a.x-d.pos.x),d.mass?(c=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),e=this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),g=max(this.elasticity,d.elasticity),this.velocity.x=lerp(g,c,e),d.velocity.x=lerp(g,c,f)):this.velocity.x*=-this.elasticity);debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}if(this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)){c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this);if(c||!d)this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y;d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity)}}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=0,b=0,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){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";const tileImage=new Image;let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const screenToWorld=a=>a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos),worldToScreen=a=>a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,g,h=new Color(0,0,0,0),k=glEnable){showWatermark&&++drawCount;if(glEnable&&k)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var n=tileImageSize.x/d.x|0;k=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,p=c%n*k;n=(c/n|0)*m;glDraw(a.x,a.y,g?-b.x:b.x,b.y,f,p+tileImageFixBleed.x,n+tileImageFixBleed.y,p-tileImageFixBleed.x+k,n-tileImageFixBleed.y+m,e.rgbaInt(),h.rgbaInt())}else drawCanvas2D(a,b,f,g,m=>{if(0>c)m.fillStyle=e,m.fillRect(-.5,-.5,1,1);else{var p=tileImageSize.x/d.x|0;const l=c%p*d.x+tileFixBleedScale;p=(c/p|0)*d.y+tileFixBleedScale;const u=d.x-2*tileFixBleedScale,v=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,l,p,u,v,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,g,h,k){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,g,h,k)}function drawRectScreenSpace(a,b,c,d,e){drawTileSrceenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),0,0,e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y-.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",h=fontDefault){overlayContext.fillStyle=d;overlayContext.lineWidth=e*=cameraScale;overlayContext.strokeStyle=f;overlayContext.textAlign=g;overlayContext.font=c+"px "+h;overlayContext.textBaseline="middle";b=b.copy();a.split("\n").forEach(k=>{e&&overlayContext.strokeText(k,b.x,b.y);overlayContext.fillText(k,b.x,b.y);b.y+=c})}function drawText(a,b,c=1,d,e,f,g,h){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e,f,g,h)}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){a||engineFontImage||(engineFontImage=new Image,engineFontImage.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;a.split("\n").forEach((k,n)=>{const m=d?k.length*f.x*c/2|0:0;for(let u=k.length;u--;){var p=k[u].charCodeAt();if(32>p||127<p)p=127;var l=this.startTileIndex+p-32;p=l%h;l=l/h|0;const v=b.add(vec2(u,n).multiply(g));e.drawImage(this.image,p*f.x,l*f.y,f.x,f.y,v.x-m,v.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen?document.exitFullscreen():document.mozCancelFullScreen&&document.mozCancelFullScreen():document.body.webkitRequestFullScreen?document.body.webkitRequestFullScreen():document.body.mozRequestFullScreen&&document.body.mozRequestFullScreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1?1:0,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKeyCode(a.keyCode)]=3),debug||a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKeyCode(a.keyCode)]=4)};const remapKeyCode=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return mainCanvasSize.multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],g[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&Navigator.vibrate&&Navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b;ontouchstart=ontouchmove=ontouchend=c=>{c.button=0;const d=c.touches.length;d?(b||zzfx(0,b=1),c.x=c.touches[0].clientX,c.y=c.touches[0].clientY,a?onmousemove(c):onmousedown(c)):a&&onmouseup(c);a=d;return!c.cancelable}}let touchGamepadTimer=new Timer,touchGamepadButtons=[],touchGamepadStick=vec2();function touchGamepadCreate(){touchGamepadEnable&&isTouchDevice&&(ontouchstart=ontouchmove=ontouchend=a=>{if(touchGamepadEnable){touchGamepadStick=vec2();touchGamepadButtons=[];if(a.touches.length&&(touchGamepadTimer.isSet()||zzfx(0),isUsingGamepad=1,touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}var b=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),c=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),d=mainCanvasSize.scale(.5);for(const e of a.touches)a=mouseToScreen(vec2(e.clientX,e.clientY)),a.distance(b)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=a.subtract(b).scale(2/touchGamepadSize).clampLength():(a=a.subtract(b).angle(),touchGamepadStick.setAngle((4*a/PI+8.5|0)*PI/4)):a.distance(c)<touchGamepadSize?(a=a.subtract(c).direction(),touchGamepadButtons[a]=1):a.distance(d)<touchGamepadSize&&(touchGamepadButtons[9]=1)}})}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";overlayContext.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)overlayContext.arc(a.x,a.y,touchGamepadSize/2,0,9),overlayContext.fill();else for(var b=10;b--;){var c=b*PI/4;overlayContext.arc(a.x,a.y,.6*touchGamepadSize,c+PI/8,c+PI/8);b%2&&overlayContext.arc(a.x,a.y,.33*touchGamepadSize,c,c);1==b&&overlayContext.fill()}overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(b=4;b--;)c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e=0;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c=1){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a=1,b=1){if(soundEnable)return playSamples(this.cachedSamples,a,1,0,b)}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||(audioContext=new(window.AudioContext||webkitAudioContext)),audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),g=audioContext.createBufferSource();a.forEach((h,k)=>f.getChannelData(k).set(h));g.buffer=f;g.playbackRate.value=c;g.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);(window.StereoPannerNode?g.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})):g).connect(a);g.start();return g}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,n=0,m=0,p=0,l=0,u=0,v=0,A=0,r=0,B=1,y=0,C=0){let t=2*PI,F=k*=500*t/zzfxR/zzfxR,z=[];b=c*=(1+b*rand(-1,1))*t/zzfxR;let w=0,D=0,q=0,x=1,H=0,I=0,E=0,J,G;d=d*zzfxR+9;y*=zzfxR;e*=zzfxR;f*=zzfxR;r*=zzfxR;n*=500*t/zzfxR**3;v*=t/zzfxR;m*=t/zzfxR;p*=zzfxR;l=l*zzfxR|0;for(G=d+y+e+f+r|0;q<G;z[q++]=E)++I%(100*A|0)||(E=g?1<g?2<g?3<g?Math.sin((w%t)**3):Math.max(Math.min(Math.tan(w),1),-1):1-(2*w/t%2+2)%2:1-4*abs(Math.round(w/t)-w/t):Math.sin(w),E=(l?1-C+C*Math.sin(t*q/l):1)*(0<E?1:-1)*abs(E)**h*a*soundVolume*(q<d?q/d:q<d+y?1-(q-d)/y*(1-B):q<d+y+e?B:q<G-r?(G-q-r)/f*B:0),E=r?E/2+(r>q?0:(q<G-r?1:(G-q)/r)*z[q-r|0]/2):E),J=(c+=k+=n)*Math.cos(v*D++),w+=J-J*u*(1-1e9*(Math.sin(q)+1)%2),x&&++x>p&&(c+=m,b+=m,x=0),!l||++H%l||(c=b,k=F,x=x||1);return z}function zzfxM(a,b,c,d=125){let e,f,g,h,k,n,m,p,l,u,v,A,r,B=0,y,C=[],t=[],F=[],z=0,w=0,D=1,q={},x=zzfxR/d*60>>2;for(;D;z++)C=[D=p=A=0],c.forEach((H,I)=>{m=b[H][z]||[0,0,0];D|=!!b[H][z];y=A+(b[H][0].length-2-!p)*x;r=I==c.length-1;f=2;for(h=A;f<m.length+r;p=++f){k=m[f];l=f==m.length+r-1&&r||u!=(m[0]||0)|k|0;for(g=0;g<x&&p;g++>x-99&&l?v+=(1>v)/99:0)n=(1-v)*C[B++]/2||0,t[h]=(t[h]||0)-n*w+n,F[h]=(F[h++]||0)+n*w+n;k&&(v=k%1,w=m[1]||0,k|=0)&&(C=q[[u=m[B=0]||0,k]]=q[[u,k]]||(e=[...a[u]],e[2]*=2**((k-12)/12),0<k?zzfxG(...e):[]))}A=y});return[t,F]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){a=a.floor();b=b.floor();var d=b.subtract(a);const e=abs(d.x),f=-abs(d.y),g=sign(d.x);d=sign(d.y);let h=e+f;for(let n=a.x,m=a.y;;){var k=getTileCollisionData(vec2(n,m));if(k&&(c?c.collideWithTileRaycast(k,new Vector2(n,m)):0<k))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(n+.5,m+.5),"#ff0",1),new Vector2(n+.5,m+.5);if(n==b.x&m==b.y)break;k=2*h;k>=f&&(h+=f,n+=g);k<=e&&(h+=e,m+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){a&&(this.canvas.width=this.size.x*this.tileSize.x,this.canvas.height=this.size.y*this.tileSize.y);this.savedRenderSettings=[mainCanvas,mainContext,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glCopyToContext(mainContext,1);[mainCanvas,mainContext,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,g){this.drawCanvas2D(a,b,f,g,h=>{if(0>c)h.fillStyle=e,h.fillRect(-.5,-.5,1,1);else{const k=tileImage.width/d.x;h.globalAlpha=e.a;h.drawImage(tileImage,c%k*d.x,(c/k|0)*d.x,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g=-1,h=tileSizeDefault,k=new Color,n=new Color,m=new Color(1,1,1,0),p=new Color(1,1,1,0),l=.5,u=.1,v=1,A=.1,r=.05,B=1,y=1,C=0,t=PI,F=.1,z=.2,w,D,q=1,x=D?1e9:0){super(a,new Vector2,g,h,b,void 0,x);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=k;this.colorStartB=n;this.colorEndA=m;this.colorEndB=p;this.randomColorLinear=q;this.particleTime=l;this.sizeStart=u;this.sizeEnd=v;this.speed=A;this.angleSpeed=r;this.damping=B;this.angleDamping=y;this.gravityScale=C;this.particleConeAngle=t;this.fadeRate=F;this.randomness=z;this.collideTiles=w;this.additive=D;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(.5*this.emitSize);a=new Particle(this.pos.add(a),this.tileIndex,this.tileSize,this.angle+rand(this.particleConeAngle,-this.particleConeAngle));const b=this.randomness;var c=m=>m+m*rand(b,-b);const d=c(this.particleTime),e=c(this.sizeStart),f=c(this.sizeEnd),g=c(this.speed);c=c(this.angleSpeed)*randSign();const h=rand(this.emitConeAngle,-this.emitConeAngle),k=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);a.colorStart=k;a.colorEndDelta=n.subtract(k);a.velocity=(new Vector2).setAngle(this.angle+h,g);a.angleVelocity=c;a.lifeTime=d;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=.5>rand();a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);if(this.trailScale){var d=this.velocity.length();const e=this.velocity.scale(1/d);d*=this.trailScale;b.y=max(b.x,d);this.angle=e.angle();drawTile(this.pos.add(e.multiply(vec2(0,-d/2))),b,this.tileIndex,this.tileSize,c,this.angle,this.mirror)}else drawTile(this.pos,b,this.tileIndex,this.tileSize,c,this.angle,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(this.pos,b,"#f005",0,this.angle);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsPreventUnlock,newgrounds,medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>localStorage[b.storageKey()])}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;this.image=new Image;e&&(this.image.src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id),localStorage["OS13kTrophy,"+this.icon+","+medalsSaveName+","+this.name]=this.description)}render(a=0){const b=overlayContext,c=min(medalDisplayWidth,mainCanvas.width),d=overlayCanvas.width-c;a*=-medalDisplayHeight;b.save();b.beginPath();b.fillStyle="#ddd";b.fill(b.rect(d,a,c,medalDisplayHeight));b.strokeStyle="#000";b.lineWidth=3;b.stroke();b.clip();this.renderIcon(d+15+medalDisplayIconSize/2,a+medalDisplayHeight/2);b.textAlign="left";b.font="38px "+fontDefault;b.fillText(this.name,d+medalDisplayIconSize+30,a+28);b.font="24px "+fontDefault;b.fillText(this.description,d+medalDisplayIconSize+30,a+60);b.restore()}renderIcon(a,b,c=medalDisplayIconSize){const d=overlayContext;d.fillStyle="#000";d.textAlign="center";d.textBaseline="middle";d.font=.7*c+"px "+fontDefault;this.image.src?d.drawImage(this.image,a-c/2,b-c/2,c,c):d.fillText(this.icon,a,b)}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=CryptoJS());this.session_id=new URL(window.location.href).searchParams.get("ngio_session_id")||0;if(0!=this.session_id){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);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)}}const CryptoJS=()=>eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0));"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){if(glEnable){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glCanvas.style=styleCanvas;glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec2 v;varying vec4 d,e;void main(){gl_Position=m*vec4(p,1,1);v=t;d=c;e=a;}","precision highp float;varying vec2 v;varying vec4 d,e;uniform sampler2D s;void main(){gl_FragColor=texture2D(s,v)*d+e;}");var a=new ArrayBuffer(gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE);glCreateBuffer(gl_ARRAY_BUFFER,a.byteLength,gl_DYNAMIC_DRAW);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);var b=glBatchCount=0;a=(c,d,e,f,g=0)=>{c=glContext.getAttribLocation(glShader,c);glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,g,gl_VERTEX_BYTE_STRIDE,b);b+=f*e};a("p",gl_FLOAT,4,2);a("t",gl_FLOAT,4,2);a("c",gl_UNSIGNED_BYTE,1,4,1);a("a",gl_UNSIGNED_BYTE,1,4,1)}}function glSetBlendMode(a){glEnable&&(glAdditive=a)}function glSetTexture(a=glTileTexture){glEnable&&(a!=glActiveTexture&&glFlush(),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a))}function glCompileShader(a,b){if(glEnable){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glEnable){var c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}}function glCreateBuffer(a,b,c){if(glEnable){var d=glContext.createBuffer();glContext.bindBuffer(a,d);glContext.bufferData(a,b,c);return d}}function glCreateTexture(a){if(glEnable&&a&&a.width){var b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}}function glPreRender(a,b,c,d,e){glEnable&&(glContext.viewport(0,0,glCanvas.width=a,glCanvas.height=b),glContext.clear(gl_COLOR_BUFFER_BIT),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture),glContext.useProgram(glShader),glSetBlendMode(),a=2*e/a,b=2*e/b,glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([a,0,0,0,0,b,0,0,1,1,-1,1,-1-a*c,-1-b*d,0,0])))}function glFlush(){if(glEnable&&glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){glEnable&&glBatchCount&&(glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0))}function glDraw(a,b,c,d,e,f,g,h,k,n=4294967295,m=0){if(glEnable){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var p=Math.cos(e)/2,l=Math.sin(e)/2;e=p*c;p*=d;c*=l;d*=l;l=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;glPositionData[l++]=a-e-d;glPositionData[l++]=b-p+c;glPositionData[l++]=f;glPositionData[l++]=k;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a+e+d;glPositionData[l++]=b+p-c;glPositionData[l++]=h;glPositionData[l++]=g;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a-e+d;glPositionData[l++]=b+p+c;glPositionData[l++]=f;glPositionData[l++]=g;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a-e-d;glPositionData[l++]=b-p+c;glPositionData[l++]=f;glPositionData[l++]=k;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a+e-d;glPositionData[l++]=b-p-c;glPositionData[l++]=h;glPositionData[l++]=k;glColorData[l++]=n;glColorData[l++]=m;glPositionData[l++]=a+e+d;glPositionData[l++]=b+p-c;glPositionData[l++]=h;glPositionData[l++]=g;glColorData[l++]=n;glColorData[l++]=m}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_ARRAY_BUFFER=34962,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24;
@@ -785,7 +785,7 @@ let medalDisplayIconSize = 50;
785
785
  const engineName = 'LittleJS';
786
786
 
787
787
  /** Version of engine */
788
- const engineVersion = '1.2.8';
788
+ const engineVersion = '1.3.0';
789
789
 
790
790
  /** Frames per second to update objects
791
791
  * @default */
package/engine/engine.js CHANGED
@@ -22,7 +22,7 @@
22
22
  const engineName = 'LittleJS';
23
23
 
24
24
  /** Version of engine */
25
- const engineVersion = '1.2.9';
25
+ const engineVersion = '1.3.0';
26
26
 
27
27
  /** Frames per second to update objects
28
28
  * @default */
@@ -79,7 +79,7 @@ copy engine.all.release.js %OUTPUT_FILENAME%
79
79
 
80
80
  rem check code with closure
81
81
  move %OUTPUT_FILENAME% %OUTPUT_FILENAME%.temp
82
- call google-closure-compiler --js %OUTPUT_FILENAME%.temp --js_output_file %OUTPUT_FILENAME% --language_out ECMASCRIPT_2019 --warning_level VERBOSE --jscomp_off *
82
+ call npx google-closure-compiler --js=%OUTPUT_FILENAME%.temp --js_output_file=%OUTPUT_FILENAME% --language_out=ECMASCRIPT_2019 --warning_level=VERBOSE --jscomp_off=*
83
83
  del %OUTPUT_FILENAME%.temp
84
84
  if %ERRORLEVEL% NEQ 0 (
85
85
  pause
@@ -87,7 +87,7 @@ if %ERRORLEVEL% NEQ 0 (
87
87
  )
88
88
 
89
89
  rem lightly minify with uglify
90
- call uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
90
+ call npx uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
91
91
  if %ERRORLEVEL% NEQ 0 (
92
92
  pause
93
93
  exit /b %ERRORLEVEL%
@@ -95,7 +95,7 @@ if %ERRORLEVEL% NEQ 0 (
95
95
 
96
96
  rem --- BUILD TYPESCRIPT DEFINITIONS ---
97
97
 
98
- call tsc engine.all.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
98
+ call npx tsc engine.all.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
99
99
  if %ERRORLEVEL% NEQ 0 (
100
100
  pause
101
101
  exit /b %ERRORLEVEL%
package/engine/index.d.ts CHANGED
@@ -1442,6 +1442,8 @@ declare class ParticleEmitter extends EngineObject {
1442
1442
  fadeRate: number;
1443
1443
  /** @property {Number} - Apply extra randomness percent */
1444
1444
  randomness: number;
1445
+ /** @property {Number} - Do particles collide against tiles */
1446
+ collideTiles: boolean;
1445
1447
  /** @property {Number} - Should particles use addtive blend */
1446
1448
  additive: boolean;
1447
1449
  /** @property {Number} - If set the partile is drawn as a trail, stretched in the drection of velocity */
@@ -1615,7 +1617,7 @@ declare const gl_VERTEX_BYTE_STRIDE: number;
1615
1617
  /** Name of engine */
1616
1618
  declare const engineName: "LittleJS";
1617
1619
  /** Version of engine */
1618
- declare const engineVersion: "1.2.9";
1620
+ declare const engineVersion: "1.3.0";
1619
1621
  /** Frames per second to update objects
1620
1622
  * @default */
1621
1623
  declare const frameRate: 60;
package/package.json CHANGED
@@ -1,19 +1,12 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.2.9",
3
+ "version": "1.3.0",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "engine/engine.all.js",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/KilledByAPixel/LittleJS.git"
9
9
  },
10
- "dependencies": {
11
- "google-closure-compiler": "^20220502.0.0",
12
- "uglify-js": "^3.15.5",
13
- "roadroller": "^2.1.0",
14
- "ect-bin": "^1.4.1",
15
- "typescript": "^4.7.2"
16
- },
17
10
  "keywords": [
18
11
  "HTML5",
19
12
  "JavaScript",