function BotController(){this.decisionDelay=10,this.lastDecision=0,this.init=function(){},this.makeDecisions=function(t){switch(this.decisionDelay<=0&&(this.lastDecision=parseInt(10*Math.random()),this.decisionDelay=10),this.decisionDelay--,this.lastDecision){case 0:t.idle();break;case 1:t.turnRight();break;case 2:t.accelerate();break;case 3:t.turnLeft();break;case 4:t.turnRight();break;case 5:t.shoot(),this.lastDecision=0;break;case 6:t.idle();break;case 7:t.accelerate();break;case 8:t.turnRight();break;case 9:t.shoot(),this.lastDecision=0}},this.getColor=function(){switch(parseInt(4*Math.random())){case 0:return"#DDDD33";case 1:return"#DD33DD";case 2:return"#33DD33";case 3:return"#3333DD"}}}function Bullet(t,i){this.position={x:0,y:0},this.velocity={x:0,y:0},this.acceleration={x:0,y:0},this.angleRadians=0,this.fireRate=5,this.lifetime=100,this.timeToDie=0,this.isDead=!1,this.owner=i,this.damage=1,this.fire=function(t,i,s){this.position.x=t.x+8*Math.cos(s),this.position.y=t.y+8*Math.sin(s),this.velocity.x=i.x,this.velocity.y=i.y,this.angleRadians=s,this.velocity.x+=this.fireRate*Math.cos(s),this.velocity.y+=this.fireRate*Math.sin(s),this.timeToDie=this.lifetime},this.update=function(i){this.timeToDie-=i,this.timeToDie<=0?t.expireBullet(this):(this.position.x+=this.velocity.x*i,this.position.y+=this.velocity.y*i)},this.draw=function(t){this.isDead||(t.fillStyle="#DDDDDD",t.beginPath(),t.arc(this.position.x,this.position.y,2,0,2*Math.PI),t.fill())},this.checkHit=function(t){var s=Math.sqrt(Math.pow(t.position.x-this.position.x,2)+Math.pow(t.position.y-this.position.y,2));t.id!=i&&t.width/2>=s&&(t.takeDamage(this.damage,i),this.isDead=!0)}}function Camera(){this.x=0,this.y=0,this.scale=1,this.viewBox={x:100,y:100,width:600,height:400},this.padding=10,this.init=function(t){this.viewBox.x=t.width/3,this.viewBox.y=t.height/3,this.viewBox.width=t.width-2*this.viewBox.x,this.viewBox.height=t.height-2*this.viewBox.y},this.update=function(t,i,s){this.followPlayer(i,s)},this.handleResize=function(t){this.viewBox.x=t.width/3,this.viewBox.y=t.height/3,this.viewBox.width=t.width-2*this.viewBox.x,this.viewBox.height=t.height-2*this.viewBox.y},this.followPlayer=function(t){var i={x:0,y:0};i.x=this.x+t.position.x,i.y=this.y+t.position.y,i.x<=this.viewBox.x&&(this.x-=i.x-this.viewBox.x),t.position.x+this.x>=this.viewBox.x+this.viewBox.width&&(this.x+=this.viewBox.x+this.viewBox.width-i.x),i.y<=this.viewBox.y&&(this.y-=i.y-this.viewBox.y),t.position.y+this.y>=this.viewBox.y+this.viewBox.height&&(this.y+=this.viewBox.y+this.viewBox.height-i.y)}}function GravityWellGame(){this.game=null,this.system=null,this.player=null,this.ships=[],this.bullets=[],this.systems=[],this.planets=[],this.camera=null,this.background=null,this.farBackground=null,this.state={shipIndex:1,planetIndex:1,solarIndex:1},this.shipIndex=1,this.planetIndex=1,this.solarIndex=1,this.settings={},this.settings.enableMouseControl=!0,this.init=function(t,i){this.game=this,this.system=t,this.camera=new Camera,this.camera.init(i),this.background=new Scenery(this.camera,.1),this.farBackground=new Scenery(this.camera,.05),this.systems.push(new SolarSystem(this.game,{x:-4e4,y:-4e4})),this.systems.push(new SolarSystem(this.game,{x:0,y:-4e4})),this.systems.push(new SolarSystem(this.game,{x:4e4,y:-4e4})),this.systems.push(new SolarSystem(this.game,{x:-4e4,y:0})),this.systems.push(new SolarSystem(this.game,{x:0,y:0})),this.systems.push(new SolarSystem(this.game,{x:4e4,y:0})),this.systems.push(new SolarSystem(this.game,{x:-4e4,y:4e4})),this.systems.push(new SolarSystem(this.game,{x:0,y:4e4})),this.systems.push(new SolarSystem(this.game,{x:4e4,y:4e4})),this.player=new Ship(this.game,new HumanController),this.player.id=this.state.shipIndex++;for(var s in this.systems){(n=this.systems[s]).id=this.state.solarIndex++;var e=n.spawnPlanets(this.state),h=n.spawnShips(this.state);this.planets=this.planets.concat(e),this.ships=this.ships.concat(h)}var a=this.systems[4].ships[0];this.ships.splice(this.ships.indexOf(a),1),this.ships.push(this.player),this.systems[4].ships[0]=this.player;for(var s in this.systems){var n;(n=this.systems[s]).init()}this.ui=new HeadsUpDisplay(this.game,this.camera),this.ui.init(this.player,i)},this.updateDelta=function(t,i){this.update(t);for(var s in this.ships){this.ships[s].update(i)}for(var s in this.systems){this.systems[s].update(i)}for(var s in this.bullets){this.bullets[s].update(i)}this.camera.update(t,this.player,i),this.farBackground.update(t,i),this.background.update(t,i),this.ui.update(i)},this.update=function(t){for(var i in this.ships){(h=this.ships[i]).control()}for(var i in this.bullets){var s=this.bullets[i];for(var e in this.ships){var h=this.ships[e];s.checkHit(h)}}for(var i in this.ships){h=this.ships[i];for(var e in this.ships){var a=this.ships[e];h!=a&&h.checkHit(a)}for(var n in this.systems){this.systems[n].checkCrash(h)}}},this.draw=function(t){this.farBackground.draw(t),this.background.draw(t),t.save(),t.translate(this.camera.x,this.camera.y);for(var i in this.systems){this.systems[i].draw(t)}for(var i in this.ships){this.ships[i].draw(t)}for(var i in this.bullets){this.bullets[i].draw(t)}t.restore(),this.ui.draw(t)},this.spawnBullet=function(t){var i=new Bullet(this.game,t.id);i.fire(t.position,t.velocity,t.targetAngle),this.bullets.push(i)},this.expireBullet=function(t){this.bullets.splice(this.bullets.indexOf(t),1)},this.handleResize=function(t){this.camera.handleResize(t)},this.mouseMove=function(t,i,s){this.settings.enableMouseControl&&this.player.controller.mouseSteer(this.player,this.camera,i,s)},this.mouseDown=function(t,i,s,e){if(this.settings.enableMouseControl)switch(i){case 0:this.player.shoot();break;case 2:this.player.controller.mouseSteer(this.player,this.camera,s,e),this.player.accelerate()}},this.mouseUp=function(t,i,s,e){if(this.settings.enableMouseControl)switch(i){case 2:this.player.idle()}},this.touchStart=function(t,i,s){this.settings.enableMouseControl&&(this.player.controller.mouseSteer(this.player,this.camera,i,s),this.player.accelerate())},this.touchMove=function(t,i,s){this.settings.enableMouseControl&&(this.player.controller.mouseSteer(this.player,this.camera,i,s),this.player.accelerate())},this.touchEnd=function(t,i,s){this.settings.enableMouseControl&&this.player.idle()},this.contextMenu=function(t,i){},this.getNearestPlanet=function(t,i){var s=Number.MAX_SAFE_INTEGER,e=null;for(var h in t.planets){var a=t.planets[h],n=this.calculateDistanceTo(i,a);n2&&i<6&&(this.planetColor="#33DD33",this.radius=140,this.mass=1400,this.type="habitable"),this.rotationRadians=2*Math.PI*Math.random(),this.orbitSpeed=1e-5},this.update=function(t){this.angleRadians+=this.orbitSpeed,this.rotationRadians+=this.rotationSpeed,this.position.x=this.system.position.x+this.orbitRadius*Math.cos(this.angleRadians),this.position.y=this.system.position.y+this.orbitRadius*Math.sin(this.angleRadians)},this.draw=function(t){var i={x:0,y:0};i.x=this.system.position.x,i.y=this.system.position.y,t.save(),t.fillStyle="#000000",t.translate(this.position.x,this.position.y),t.beginPath(),t.arc(0,0,this.radius,0,2*Math.PI),t.fill(),t.restore(),t.strokeStyle="#3333DD",t.lineWidth=1,t.save(),t.translate(this.system.position.x,this.system.position.y),t.beginPath(),t.arc(0,0,this.orbitRadius,0,2*Math.PI),t.stroke(),t.restore(),t.save(),t.strokeStyle=this.planetColor,t.lineWidth=2,t.translate(this.position.x,this.position.y),t.rotate(this.rotationRadians),t.beginPath(),t.arc(0,0,this.radius,0,2*Math.PI),t.stroke(),t.restore(),t.save(),t.translate(this.position.x,this.position.y),t.beginPath(),t.fillStyle=this.teamColor,t.rect(-8,-6,16,12),t.fill(),t.font="16px sans-serif",t.textAlign="center",t.fillStyle="#DDDDDD",t.strokeStyle="#333333",t.lineWidth=2;t.measureText("Planet "+this.id).width;t.fillText("Planet "+this.id,0,0),t.restore()},this.addGravity=function(i){var s=t.calculateAngleTo(this,i),e=t.calculateDistanceTo(this,i);i.acceleration.x+=system.formatFloat(this.mass*(1/Math.pow(e,2))*Math.cos(s)),i.acceleration.y+=system.formatFloat(this.mass*(1/Math.pow(e,2))*Math.sin(s))},this.claim=function(t){this.teamId=t.teamId,this.teamColor=t.shipColor}}function Scenery(t,i){this.position={x:0,y:0},this.width=786,this.height=786,this.spriteCanvas=null,this.spriteContext=null,this.canvasWidth=128,this.canvasHeight=128,this.debug=!1,this.parallaxDepth=i,this.update=function(i){this.canvasWidth=i.width,this.canvasHeight=i.height;var s={x:0,y:0};s.x=t.x*this.parallaxDepth+this.position.x,s.y=t.y*this.parallaxDepth+this.position.y,s.x<-this.width&&(this.position.x+=this.width),s.x>0&&(this.position.x-=this.width),s.y<-this.height&&(this.position.y+=this.height),s.y>0&&(this.position.y-=this.height)},this.preRender=function(){if(null==this.spriteContext){this.spriteCanvas=document.createElement("canvas"),this.spriteCanvas.width=this.width,this.spriteCanvas.height=this.height,this.spriteContext=this.spriteCanvas.getContext("2d"),this.spriteContext.fillStyle="#DDDDDD";for(var t=parseInt(Math.sqrt(this.width)),i=0;ia){this.angleRadians=h,this.targetAngle=h,n=this.touching.radius-a;var o={x:0,y:0};o.x=(n+this.width/2)*Math.cos(h),o.y=(n+this.height/2)*Math.sin(h),this.position.x+=o.x,this.position.y+=o.y,this.velocity.x=0,this.velocity.y=0,this.touching.claim(this)}}else this.position.x+=this.velocity.x*i,this.position.y+=this.velocity.y*i}},this.control=function(){this.controller.makeDecisions(this)},this.respawn=function(){if(null==this.spawn||this.spawn.teamId!=this.teamId){var i=[];for(var s in t.planets){var e=t.planets[s];e.teamId==this.teamId&&"habitable"==e.type&&i.push(e)}this.spawn=i[parseInt(i.length*Math.random())]}var h=2*Math.PI*Math.random();this.position.x=this.spawn.position.x+this.spawn.radius*Math.cos(h),this.position.y=this.spawn.position.y+this.spawn.radius*Math.sin(h),this.health=5,this.angleRadians=h,this.isAccelerating=!1,this.isDead=!1},this.die=function(){if(!this.isDead){this.velocity.x/=4,this.velocity.y/=4;for(var i=0;i<5;i++)this.targetAngle=2*Math.PI*Math.random(),t.spawnBullet(this);var s=this;setTimeout(function(){s.respawn()},3e3),this.isDead=!0}},this.idle=function(){this.isAccelerating=!1},this.toggleAccelerate=function(){this.isAccelerating?this.idle():this.accelerate()},this.accelerate=function(){this.isAccelerating=!0},this.shoot=function(){this.isDead||t.spawnBullet(this)},this.turnLeft=function(){null==this.touching&&(this.targetAngle-=this.turnRate)},this.turnRight=function(){null==this.touching&&(this.targetAngle+=this.turnRate)},this.preRender=function(t,i){null==i&&(i=0),t.fillStyle=this.shipColor,t.strokeStyle=this.shipColor,t.lineWidth=4,t.save(),t.translate(this.width/2,this.height/2),t.rotate(i),t.beginPath(),t.moveTo(this.width/2,0),t.lineTo(-this.width/2,-this.height/3),t.lineTo(-this.width/2,this.height/3),t.lineTo(this.width/2,0),t.fill(),t.restore()},this.draw=function(t){if(null==this.spriteContext&&(this.spriteCanvas=document.createElement("canvas"),this.spriteCanvas.width=this.width,this.spriteCanvas.height=this.height,this.spriteContext=this.spriteCanvas.getContext("2d"),this.preRender(this.spriteContext)),!this.isDead){var i={x:0,y:0};i.x=this.position.x,i.y=this.position.y,t.save(),t.translate(i.x,i.y),t.rotate(this.targetAngle),this.isAccelerating&&(t.fillStyle="#7777FF",t.beginPath(),t.moveTo(-this.width-5,0),t.lineTo(-this.width/2,3),t.lineTo(-this.width/2,-3),t.lineTo(-this.width-5,0),t.fill()),t.drawImage(this.spriteCanvas,0,0,this.spriteCanvas.width,this.spriteCanvas.height,-this.spriteCanvas.width/2,-this.spriteCanvas.height/2,this.width,this.height),t.strokeStyle="#00FF00",this.isTakingDamage&&(t.strokeStyle="#FF0000",this.isTakingDamage=!1),t.restore(),t.save(),t.translate(i.x,i.y),t.font="16px sans-serif",t.textAlign="center",t.fillStyle="#DDDDDD",t.strokeStyle="#333333",t.lineWidth=2;t.measureText("Player "+this.id).width;t.fillText("Player "+this.id,0,0),t.restore()}},this.takeDamage=function(t,i){this.isTakingDamage=!0,this.health-=t,this.lastHit=i},this.checkHit=function(t){var i=Math.sqrt(Math.pow(t.position.x-this.position.x,2)+Math.pow(t.position.y-this.position.y,2));this.id!=t.id&&t.width/2>=i&&(this.takeDamage(1),this.lastHit=t.id)}}function SolarSystem(t,i){this.id=0,this.position=i,this.planets=[],this.ships=[],this.systemColor=null,this.radius=400,this.mass=5e4,this.teamId=0,this.init=function(){this.teamId=this.id,this.systemColor=this.getColor(this.teamId);for(var t in this.planets){this.planets[t].init(this)}this.planets[parseInt(this.planets.length*Math.random())];for(var t in this.ships){this.ships[t].init(this.systemColor,this)}},this.getColor=function(t){switch(t){case 1:return"crimson";case 2:return"orangered";case 3:return"gold";case 4:return"limegreen";case 5:return"dodgerblue";case 6:return"aqua";case 7:return"darkmagenta";case 8:return"ghostwhite";case 9:return"orchid"}},this.spawnPlanets=function(i){for(var s=1;s<=7;s++){if(parseInt(8*Math.random())>4||4==s){var e=new Planet(t,s);e.id=i.planetIndex++,4==s&&(e.teamId=this.id,e.teamColor=this.getColor(this.id)),this.planets.push(e)}}return this.planets},this.spawnShips=function(i){for(var s=0;s<4;s++){var e=new Ship(t,new BotController);e.id=i.shipIndex++,this.ships.push(e)}return this.ships},this.update=function(t){for(var i in this.planets){this.planets[i].update(t)}},this.draw=function(t){t.fillStyle="#000000",t.strokeStyle="#DDDD33",t.lineWidth=3,t.save(),t.translate(this.position.x,this.position.y),t.beginPath(),t.arc(0,0,this.radius,0,2*Math.PI),t.fill(),t.stroke(),t.restore();for(var i in this.planets){this.planets[i].draw(t)}t.save(),t.translate(this.position.x,this.position.y),t.font="16px sans-serif",t.textAlign="center",t.fillStyle="#DDDDDD",t.strokeStyle="#333333",t.lineWidth=2;t.measureText("System "+this.id).width;t.fillText("System "+this.id,0,0),t.restore()},this.addGravity=function(i){var s=t.calculateAngleTo(this,i),e=t.calculateDistanceTo(this,i);i.acceleration.x+=system.formatFloat(this.mass*(1/Math.pow(e,2))*Math.cos(s)),i.acceleration.y+=system.formatFloat(this.mass*(1/Math.pow(e,2))*Math.sin(s))},this.checkCrash=function(i){if(!i.isDead){var s=t.calculateDistanceTo(i,this);if(this.radius+i.width/2>s)return i.touching=this,void i.die();for(var e in this.planets){var h=this.planets[e];i.touching==h&&(i.touching=null);s=t.calculateDistanceTo(i,h);if(h.radius+i.width/2>s&&(i.touching=h,Math.abs(i.velocity.x)+Math.abs(i.velocity.y)>3))return void i.die()}}}}function System(){var t=null,i=null,s={},e=null,h=null;this.game=null;var a="#D3D3D3",n=0;this.create=function(s,e,n){(h=this).game=e,a=n||a,t=document.getElementById(s),i=document.createElement("canvas"),t.appendChild(i),window.addEventListener("resize",h.handleResize),i.addEventListener("touchmove",h.handleTouchMove),i.addEventListener("mousemove",h.handleMouseMove),i.addEventListener("mousedown",h.handleMouseDown),i.addEventListener("contextmenu",h.handleContextMenu),i.addEventListener("touchstart",h.handleTouchStart),i.addEventListener("mouseup",h.handleMouseUp),i.addEventListener("touchend",h.handleTouchEnd),this.game.init(h,i),h.handleResize(null),window.requestAnimationFrame(h.handleRequestAnimationFrame)},this.getCanvasSize=function(){return{width:i.width+0,height:i.height+0}},this.preRender=function(){null==this.backgroundContext&&(this.backgroundCanvas=document.createElement("canvas"),this.backgroundCanvas.width=i.width,this.backgroundCanvas.height=i.height,this.backgroundContext=this.backgroundCanvas.getContext("2d"),this.backgroundContext.fillStyle=a,this.backgroundContext.fillRect(0,0,this.backgroundCanvas.width,this.backgroundCanvas.height))},this.handleResize=function(a){i.width=t.offsetWidth,i.height=t.offsetHeight,(e=i.getContext("2d",s)).translate(.5,.5),h.game.handleResize(i)},this.handleRequestAnimationFrame=function(t){var s=(new Date).getTime(),o=(s-n)/(1e3/60);o>100&&(o=1e3/60),h.game.updateDelta(i,o),n=s,e.fillStyle=a,e.fillRect(0,0,i.width,i.height),h.game.draw(e),window.requestAnimationFrame(h.handleRequestAnimationFrame)},this.handleMouseMove=function(t){h.game.mouseMove(i,t.offsetX,t.offsetY)},this.handleMouseDown=function(t){h.game.mouseDown(i,t.button,t.offsetX,t.offsetY)},this.handleMouseUp=function(t){h.game.mouseUp(i,t.button,t.offsetX,t.offsetY)},this.handleTouchStart=function(t){h.game.touchStart(i,t.touches[0].clientX,t.touches[0].clientY)},this.handleTouchMove=function(t){h.game.touchMove(i,t.touches[0].clientX,t.touches[0].clientY)},this.handleTouchEnd=function(t){h.game.touchEnd(i,t.offsetX,t.offsetY)},this.handleContextMenu=function(t){return h.game.contextMenu(i,t),t.preventDefault(),!1},this.handleServerMessage=function(t){h.game.receiveMessage(t)},this.formatFloat=function(t){return Number.isNaN(parseFloat(t))?0:parseFloat(t.toFixed(4))}}window.Keys={Left:37,Up:38,Right:39,Down:40,W:87,A:65,S:83,D:68,Space:32};