Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AroriaNetwork
GitHub Repository: AroriaNetwork/3kho-backup
Path: blob/main/projects/n-gon/js/spawn.js
1834 views
1
const spawn={nonCollideBossList:["cellBossCulture","bomberBoss","powerUpBoss","orbitalBoss","spawnerBossCulture","growBossCulture"],randomLevelBoss(t,e,i=["shieldingBoss","orbitalBoss","historyBoss","shooterBoss","cellBossCulture","bomberBoss","spiderBoss","launcherBoss","laserTargetingBoss","powerUpBoss","powerUpBossBaby","snakeBoss","streamBoss","pulsarBoss","spawnerBossCulture","grenadierBoss","growBossCulture","blinkBoss","snakeSpitBoss","laserBombingBoss","blockBoss","revolutionBoss","mantisBoss"]){spawn[i[Math.floor(Math.random()*i.length)]](t,e)},pickList:["starter","starter"],fullPickList:["hopper","hopper","hopper","slasher","slasher","shooter","shooter","grenadier","grenadier","striker","striker","laser","laser","stabber","stabber","springer","springer","pulsar","pulsar","launcher","launcherOne","exploder","sneaker","sucker","sniper","spinner","grower","beamer","focuser","spawner","ghoster"],allowedGroupList:["spinner","striker","springer","laser","focuser","beamer","exploder","spawner","shooter","launcher","launcherOne","stabber","sniper","pulsar","grenadier","slasher"],setSpawnList(){spawn.pickList.splice(0,1),spawn.pickList.push(spawn.fullPickList[Math.floor(Math.random()*spawn.fullPickList.length)])},spawnChance:t=>Math.random()<t+.07*simulation.difficulty&&mob.length<16*Math.log10(simulation.difficulty+1)-1,randomMob(t,e,i=1){if(spawn.spawnChance(i)||i===1/0){this[this.pickList[Math.floor(Math.random()*this.pickList.length)]](t,e)}if(tech.isMoreMobs){this[this.pickList[Math.floor(Math.random()*this.pickList.length)]](t,e)}},randomSmallMob(t,e,i=Math.max(Math.min(Math.round(Math.random()*simulation.difficulty*.2),4),0),s=16+Math.ceil(15*Math.random()),o=1){if(spawn.spawnChance(o))for(let o=0;o<i;++o){this[this.pickList[Math.floor(Math.random()*this.pickList.length)]](t+Math.round(20*(Math.random()-.5))+o*s*2.5,e+Math.round(20*(Math.random()-.5)),s)}if(tech.isMoreMobs)for(let o=0;o<i;++o){this[this.pickList[Math.floor(Math.random()*this.pickList.length)]](t+Math.round(20*(Math.random()-.5))+o*s*2.5,e+Math.round(20*(Math.random()-.5)),s)}},randomGroup(t,e,i=1){if(spawn.spawnChance(i)&&simulation.difficulty>2||i===1/0){let i=spawn.pickList[Math.floor(Math.random()*spawn.pickList.length)],s=!1;for(let t=0,e=spawn.allowedGroupList.length;t<e;++t)if(spawn.allowedGroupList[t]===i){s=!0;break}s?Math.random()<.55?spawn.nodeGroup(t,e,i):spawn.lineGroup(t,e,i):Math.random()<.07?(spawn[i](t,e,90+40*Math.random()),spawn.spawnOrbitals(mob[mob.length-1],mob[mob.length-1].radius+50+200*Math.random(),1)):Math.random()<.35?spawn.blockGroup(t,e):(i=Math.random()<.5?"randomList":"random",Math.random()<.55?spawn.nodeGroup(t,e,i):spawn.lineGroup(t,e,i))}},secondaryBossChance:(t,e)=>tech.isDuplicateBoss&&Math.random()<2*tech.duplicationChance()?(tech.isScaleMobsWithDuplication=!0,spawn.randomLevelBoss(t,e),tech.isScaleMobsWithDuplication=!1,!0):!!tech.isResearchBoss&&(powerUps.research.count>3?(powerUps.research.changeRerolls(-4),simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>-=</span> 4<br>${powerUps.research.count}`)):tech.addJunkTechToPool(.49),spawn.randomLevelBoss(t,e),!0),MACHO(t=m.pos.x,e=m.pos.y){mobs.spawn(t,e,3,.1,"transparent");let i=mob[mob.length-1];i.stroke="transparent",i.isShielded=!0,i.leaveBody=!1,i.isBadTarget=!0,i.isUnblockable=!0,i.isDropPowerUp=!1,i.showHealthBar=!1,i.collisionFilter.category=0,i.collisionFilter.mask=0,i.chaseSpeed=3.3,i.isMACHO=!0,i.frictionAir=.006,i.onDeath=function(){tech.isHarmMACHO=!1},i.do=function(){const t=Math.sin(.015*simulation.cycle);this.radius=370*(1+.1*t);const e=Vector.sub(player.position,this.position),i=Vector.magnitude(e),s=Vector.mult(Vector.normalise(e),3e-9);this.force.x+=s.x,this.force.y+=s.y,i<this.radius?(tech.isHarmMACHO=!0,ctx.strokeStyle="rgba(80,120,200,0.2)",ctx.beginPath(),ctx.arc(m.pos.x,m.pos.y,36,0,2*Math.PI),ctx.lineWidth=10,ctx.stroke()):tech.isHarmMACHO=!1,ctx.beginPath(),ctx.arc(this.position.x,this.position.y,this.radius+15,0,2*Math.PI),ctx.strokeStyle="#000",ctx.lineWidth=1,ctx.stroke()}},WIMP(t=level.exit.x+300*(Math.random()-.5),e=level.exit.y+300*(Math.random()-.5)){mobs.spawn(t,e,3,.1,"transparent");let i=mob[mob.length-1];i.stroke="transparent",i.isShielded=!0,i.leaveBody=!1,i.isBadTarget=!0,i.isUnblockable=!0,i.isDropPowerUp=!1,i.showHealthBar=!1,i.collisionFilter.category=0,i.collisionFilter.mask=0,i.chaseSpeed=1+1.5*Math.random(),i.awake=function(){const t=Vector.sub(player.position,this.position),e=Vector.add(this.position,Vector.mult(Vector.normalise(t),this.chaseSpeed));if(Matter.Body.setPosition(this,{x:e.x,y:e.y}),Matter.Body.setVelocity(this,{x:0,y:0}),m.immuneCycle<m.cycle&&Vector.magnitude(Vector.sub(player.position,this.position))<this.radius){const t=tech.isRadioactiveResistance?.0175:.07;m.energy>t?m.immuneCycle<m.cycle&&(m.energy-=t):(m.energy=0,m.damage((tech.isRadioactiveResistance?.00175:.007)*simulation.dmgScale),simulation.drawList.push({x:this.position.x,y:this.position.y,radius:this.radius,color:simulation.mobDmgColor,time:simulation.drawTime}))}ctx.beginPath(),ctx.arc(this.position.x,this.position.y,this.radius,0,2*Math.PI),ctx.fillStyle=`rgba(25,139,170,${.2+.12*Math.random()})`,ctx.fill(),this.radius=100*(1+.25*Math.sin(.03*simulation.cycle))},i.do=function(){player.speed>1&&!m.isCloak&&setTimeout((()=>{this.do=this.awake}),2e3),this.checkStatus()}},finalBoss(t,e,i=300){mobs.spawn(t,e,6,i,"rgb(150,150,255)");let s=mob[mob.length-1];setTimeout((()=>{s.constraint=Constraint.create({pointA:{x:s.position.x,y:s.position.y},bodyB:s,stiffness:1,damping:1}),Composite.add(engine.world,s.constraint)}),2e3),s.isBoss=!0,s.frictionAir=.01,s.memory=1/0,s.hasRunDeathScript=!1,s.locatePlayer();const o=.2;Matter.Body.setDensity(s,o),s.onDeath=function(){if(!this.hasRunDeathScript){this.hasRunDeathScript=!0;const e=body.length,i=Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices));body[e]=Matter.Bodies.fromVertices(this.position.x,this.position.y,i),Matter.Body.setVelocity(body[e],{x:0,y:-3}),Matter.Body.setAngularVelocity(body[e],this.angularVelocity),body[e].collisionFilter.category=cat.body,body[e].collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet,body[e].classType="body",Composite.add(engine.world,body[e]);const s=function(t,e){Matter.Body.scale(t,1.05,1.05),t.mass<e&&setTimeout(s,20,t,e)};function t(){simulation.isHorizontalFlipped?level.exit.x=-5600:level.exit.x=5500,level.exit.y=-330,Matter.Composite.remove(engine.world,map[map.length-1]),map.splice(map.length-1,1),simulation.draw.setPaths()}if(s(body[e],200),lore.techCount>lore.techGoal-1&&!simulation.isCheating)simulation.makeTextLog(`<span class="lore-text">undefined</span> <span class='color-symbol'>=</span> ${lore.techCount}/${lore.techGoal}`,360),setTimeout((function(){simulation.makeTextLog("level.levels.push(\"<span class='lore-text'>null</span>\")",720),t(),level.levels.push("null")}),4e3);else{let e=0;requestAnimationFrame((function i(){if(!simulation.paused)if(e++,e<660)1===e&&simulation.makeTextLog("<em>//enter testing mode to set level.levels.length to <strong>Infinite</strong></em>"),e%60||simulation.makeTextLog(`simulation.analysis <span class='color-symbol'>=</span> ${(.1*(e/60-Math.random())).toFixed(3)}`);else if(660===e)simulation.makeTextLog("simulation.analysis <span class='color-symbol'>=</span> 1 <em>//analysis complete</em>");else if(780===e)simulation.makeTextLog(`<span class="lore-text">undefined</span> <span class='color-symbol'>=</span> ${lore.techCount}/${lore.techGoal}`);else if(1020===e)simulation.makeTextLog("Engine.clear(engine) <em>//simulation successful</em>");else if(1260===e)return document.getElementById("health").style.display="none",document.getElementById("health-bg").style.display="none",document.getElementById("text-log").style.opacity=0,document.getElementById("fade-out").style.opacity=1,void setTimeout((function(){simulation.paused=!0,engine.world.bodies.forEach((t=>{Matter.Composite.remove(engine.world,t)})),Engine.clear(engine),simulation.splashReturn()}),6e3);simulation.testing?(t(),setTimeout((function(){simulation.makeTextLog("level.levels.length <span class='color-symbol'>=</span> <strong>Infinite</strong>")}),1500)):requestAnimationFrame(i)}))}level.difficultyIncrease(simulation.difficultyMode),function(t){for(let e=0;e<t.length;++e)Matter.Composite.remove(engine.world,t[e])}(powerUp),powerUp=[];for(let t=0,e=body.length;t<e;++t){const e=Vector.mult(Vector.normalise(Vector.sub(this.position,body[t].position)),65),i=Vector.add(e,{x:0,y:-.5});Matter.Body.setVelocity(body[t],Vector.add(body[t].velocity,i))}for(let t=0;t<8;t++)for(let t=0,e=mob.length;t<e;++t)mob[t]!==this&&mob[t].damage(1/0,!0);for(let t=0,e=22;t<e;t++)simulation.drawList.push({x:this.position.x,y:this.position.y,radius:150*(t+1),color:"rgba(255,255,255,0.17)",time:5*(e-t+1)})}},s.onDamage=function(){},s.cycle=420,s.endCycle=780,s.totalCycles=0,s.mode=0,s.damageReduction=.25,s.do=function(){if(this.modeDo(),this.checkStatus(),m.isBodiesAsleep||this.cycle++,this.totalCycles++,this.health>.25){if(this.cycle>this.endCycle)if(this.cycle=0,this.mode++,this.damageReduction=.25,this.mode>2){this.mode=0,this.fill="#50f",this.rotateVelocity=Math.abs(this.rotateVelocity)*(player.position.x>this.position.x?1:-1),this.modeDo=this.modeLasers,Matter.Body.scale(this,10,10),Matter.Body.setDensity(s,o),this.isShielded||spawn.shield(this,this.position.x,this.position.y,1);for(let t=0,e=body.length;t<e;++t)body[t].position.x>this.position.x?body[t].force.x=.5:body[t].force.x=-.5}else 1===this.mode?(this.fill="#50f",this.modeDo=this.modeSpawns):2===this.mode&&(this.fill="#000",this.modeDo=this.modeSuck,Matter.Body.scale(this,.1,.1),Matter.Body.setDensity(s,20))}else 3!==this.mode&&(this.cycle=0,Matter.Body.setDensity(s,2),2===this.mode?Matter.Body.scale(this,5,5):Matter.Body.scale(this,.5,.5),this.mode=3,this.fill="#000",this.eventHorizon=750,this.spawnInterval=600,this.rotateVelocity=.001*(player.position.x>this.position.x?1:-1),this.modeDo=this.modeAll)},s.modeDo=function(){},s.modeAll=function(){this.modeSpawns(),this.modeSuck(),this.modeLasers()},s.spawnInterval=395,s.modeSpawns=function(){if(!(this.cycle%this.spawnInterval)&&!m.isBodiesAsleep&&mob.length<40){3!==this.mode&&Matter.Body.setAngularVelocity(this,.1);const t=spawn.fullPickList[Math.floor(Math.random()*spawn.fullPickList.length)];for(let e=0,i=2+this.totalCycles/1e3;e<i;e++){const i=this.vertices[e%6];spawn[t](i.x+50*(Math.random()-.5),i.y+50*(Math.random()-.5));const s=Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position,i))),-18);Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+s.x,y:this.velocity.y+s.y})}if(!(this.cycle%2*this.spawnInterval)&&!m.isBodiesAsleep&&mob.length<40){const t=(this.totalCycles/600+simulation.difficulty/2-30)/15;for(let e=0;e<t;e++)spawn.randomLevelBoss(3e3*(simulation.isHorizontalFlipped?-1:1)+2e3*(Math.random()-.5),200*(Math.random()-.5)-1100)}}},s.eventHorizon=1300,s.eventHorizonCycleRate=4*Math.PI/s.endCycle,s.modeSuck=function(){if(!(this.cycle%60)){const t=Math.floor(this.cycle%360/60);spawn.seeker(this.vertices[t].x,this.vertices[t].y,20*(.5+Math.random()),9);const e=mob[mob.length-1];Matter.Body.setDensity(e,3e-5),e.timeLeft=760,e.accelMag=3e-4*simulation.accelScale,e.frictionAir=.01;const i=Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position,this.vertices[t]))),-7);Matter.Body.setVelocity(e,{x:this.velocity.x+i.x,y:this.velocity.y+i.y})}const t=this.eventHorizon*(1-.25*Math.cos(simulation.cycle*this.eventHorizonCycleRate));if(ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.2*t,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.6)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.4*t,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.4)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.6*t,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.3)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.8*t,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.2)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,t,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.05)",ctx.fill(),Vector.magnitude(Vector.sub(this.position,player.position))<t){m.immuneCycle<m.cycle&&(m.energy>0&&(m.energy-=.01),m.energy<.15&&m.immuneCycle<m.cycle&&m.damage(4e-4*simulation.dmgScale));const t=Math.atan2(player.position.y-this.position.y,player.position.x-this.position.x);player.force.x-=.0017*Math.cos(t)*player.mass*(m.onGround?1.7:1),player.force.y-=.0017*Math.sin(t)*player.mass,ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(m.pos.x,m.pos.y),ctx.lineWidth=Math.min(60,2*this.radius),ctx.strokeStyle="rgba(0,0,0,0.5)",ctx.stroke(),ctx.beginPath(),ctx.arc(m.pos.x,m.pos.y,40,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.3)",ctx.fill()}this.curl(t)},s.rotateVelocity=.0025,s.rotateCount=0,s.lasers=function(t,e,i=.14*simulation.dmgScale){const s=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}};best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const o={x:t.x+7e3*Math.cos(e),y:t.y+7e3*Math.sin(e)};s(t,o,map),s(t,o,body),m.isCloak||s(t,o,[playerBody,playerHead]),best.who&&(best.who===playerBody||best.who===playerHead)&&m.immuneCycle<m.cycle&&(m.immuneCycle<m.cycle+60+tech.collisionImmuneCycles&&(m.immuneCycle=m.cycle+60+tech.collisionImmuneCycles),m.damage(i),simulation.drawList.push({x:best.x,y:best.y,radius:1500*i,color:"rgba(80,0,255,0.5)",time:20})),best.dist2===1/0&&(best=o),ctx.moveTo(t.x,t.y),ctx.lineTo(best.x,best.y)},s.modeLasers=function(){if(!m.isBodiesAsleep&&!this.isStunned){let t=!1;for(let e=0;e<this.status.length;e++)if("slow"===this.status[e].type){t=!0;break}t||(this.rotateCount++,Matter.Body.setAngle(this,this.rotateCount*this.rotateVelocity),Matter.Body.setAngularVelocity(this,0),Matter)}if(this.cycle<240){const t=this.cycle/240,e=this.cycle<120?0:.14*simulation.dmgScale*t;ctx.beginPath(),this.lasers(this.vertices[0],this.angle+Math.PI/6,e),this.lasers(this.vertices[1],this.angle+3*Math.PI/6,e),this.lasers(this.vertices[2],this.angle+5*Math.PI/6,e),this.lasers(this.vertices[3],this.angle+7*Math.PI/6,e),this.lasers(this.vertices[4],this.angle+9*Math.PI/6,e),this.lasers(this.vertices[5],this.angle+11*Math.PI/6,e),ctx.strokeStyle="#50f",ctx.lineWidth=1.5*t,ctx.setLineDash([70+300*Math.random(),55*Math.random()]),ctx.stroke(),ctx.setLineDash([]),ctx.lineWidth=20,ctx.strokeStyle=`rgba(80,0,255,${.07*t})`,ctx.stroke()}else ctx.beginPath(),this.lasers(this.vertices[0],this.angle+Math.PI/6),this.lasers(this.vertices[1],this.angle+3*Math.PI/6),this.lasers(this.vertices[2],this.angle+5*Math.PI/6),this.lasers(this.vertices[3],this.angle+7*Math.PI/6),this.lasers(this.vertices[4],this.angle+9*Math.PI/6),this.lasers(this.vertices[5],this.angle+11*Math.PI/6),ctx.strokeStyle="#50f",ctx.lineWidth=1.5,ctx.setLineDash([70+300*Math.random(),55*Math.random()]),ctx.stroke(),ctx.setLineDash([]),ctx.lineWidth=20,ctx.strokeStyle="rgba(80,0,255,0.07)",ctx.stroke()}},starter(t,e,i=Math.floor(15+20*Math.random())){mobs.spawn(t,e,8,i,"#9ccdc6");let s=mob[mob.length-1];s.accelMag=2e-4,s.repulsionRange=2e5+i*i,s.seeAtDistance2=2e6,Matter.Body.setDensity(s,5e-4),s.do=function(){this.seePlayerByLookingAt(),this.attraction(),this.repulsion(),this.checkStatus()}},blockGroup(t,e,i=3+8*Math.random()){for(let s=0;s<i;s++){const i=25+Math.floor(20*Math.random());spawn.blockGroupMob(t+Math.random()*i,e+Math.random()*i,i)}},blockGroupMob(t,e,i=25+Math.floor(20*Math.random())){mobs.spawn(t,e,4,i,"#999");let s=mob[mob.length-1];s.g=15e-5,s.accelMag=8e-4*simulation.accelScale,s.groupingRangeMax=25e4+1e5*Math.random(),s.groupingRangeMin=8*i*(8*i),s.groupingStrength=5e-4,s.memory=200,s.isGrouper=!0,s.seeAtDistance2=36e4,s.seePlayerFreq=Math.floor(50+50*Math.random()),s.do=function(){if(this.gravity(),this.checkStatus(),this.seePlayerCheck(),this.seePlayer.recall){this.attraction(),ctx.beginPath();for(let t=0,e=mob.length;t<e;t++)if(mob[t].isGrouper&&mob[t]!=this&&mob[t].isDropPowerUp){const e=Vector.magnitudeSquared(Vector.sub(this.position,mob[t].position));if(e<this.groupingRangeMax){if(mob[t].seePlayer.recall||mob[t].seePlayerCheck(),e>this.groupingRangeMin){const e=Math.atan2(mob[t].position.y-this.position.y,mob[t].position.x-this.position.x),i=this.groupingStrength*mob[t].mass;mob[t].force.x-=i*Math.cos(e),mob[t].force.y-=i*Math.sin(e)}ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(mob[t].position.x,mob[t].position.y)}}ctx.strokeStyle="#0ff",ctx.lineWidth=1,ctx.stroke()}}},blockBoss(t,e,i=60){const s=[];mobs.spawn(t,e,4,i,"#999");const o=mob[mob.length-1];o.isBoss=!0,Matter.Body.setDensity(o,.002),o.damageReduction=.04/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.frictionAir=.01,o.accelMag=2e-4,o.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y);for(const t of mob)t.isNecroMob&&(t.leaveBody=!0,t.damage(1/0))},o.target=player,o.do=function(){if(this.checkStatus(),this.seePlayerCheck(),this.target){const t=Vector.mult(Vector.normalise(Vector.sub(this.target.position,this.position)),this.accelMag*this.mass);this.force.x+=t.x,this.force.y+=t.y}if(!(simulation.cycle%30||m.isBodiesAsleep)){for(let t=0;t<body.length;t++)Vector.magnitude(Vector.sub(this.position,body[t].position))<700&&!body[t].isNotHoldable&&(Matter.Composite.remove(engine.world,body[t]),this.target=null,spawn.blockMob(body[t].position.x,body[t].position.y,body[t],0),body.splice(t,1),s.push([60,mob[mob.length-1]]));if(this.distanceToPlayer()>1500&&null===this.target)this.target=player;else if(body.length){let t=1/0,e=null;for(const i of body){const s=Vector.magnitudeSquared(Vector.sub(this.position,i.position));s<t&&0===Matter.Query.ray(map,this.position,i.position).length&&(t=s,e=i)}this.target=e}if(!(simulation.cycle%90)){let t=0;for(let e=0,i=mob.length;e<i;e++)mob[e].isNecroMob&&t++;if(t<20*Math.random()*Math.random()){const t=Vector.normalise(Vector.sub(player.position,this.position));for(let e=0,o=3*Math.random();e<o;e++){this.damageReduction+=.001;const e=.99;Matter.Body.scale(this,e,e),this.radius*=e;const o=Vector.add(Vector.mult(t,i+200*Math.random()),this.position);spawn.blockMob(o.x+100*(Math.random()-.5),o.y+100*(Math.random()-.5),null),this.torque+=35e-6*this.inertia,s.push([60,mob[mob.length-1]])}}}}for(let t=0;t<s.length;t++){const[e,i]=s[t];if(0!==e){if(i.alive){const t=Math.floor((i.vertices.length-1)*e/60);ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(i.vertices[t].x,i.vertices[t].y),ctx.moveTo(i.vertices[0].x,i.vertices[0].y);for(let t=1;t<i.vertices.length;t++)ctx.lineTo(i.vertices[t].x,i.vertices[t].y);ctx.lineTo(i.vertices[0].x,i.vertices[0].y),ctx.strokeStyle="#0ff",ctx.lineWidth=3,ctx.stroke()}s[t][0]--}else s.splice(t,1)}}},blockMob(t,e,i,s=60){if(null===i)mobs.spawn(t,e,4,1.25+3.5*Math.random(),"#999");else{const s=Vector.magnitude(Vector.sub(i.vertices[0],i.vertices[1]))+Vector.magnitude(Vector.sub(i.vertices[1],i.vertices[2]))/2;mobs.spawn(t,e,4,Math.min(70,s),"#999"),i.bounds.max.x-i.bounds.min.x<150&&i.bounds.max.y-i.bounds.min.y<150&&Matter.Body.setVertices(mob[mob.length-1],i.vertices)}const o=mob[mob.length-1];o.damageReduction=.5,o.isNecroMob=!0,o.g=12e-5,o.accelMag=3e-4*Math.sqrt(simulation.accelScale),o.memory=120,o.leaveBody=!1,o.isDropPowerUp=!1,o.cycle=0,o.do=function(){if(this.checkStatus(),this.seePlayerCheck(),!m.isBodiesAsleep)if(this.cycle++,this.cycle>s)this.damageReduction=1.8,this.do=this.normalDo;else{const t=1.04;Matter.Body.scale(this,t,t),this.radius*=t}},o.normalDo=function(){this.gravity(),this.checkStatus(),this.seePlayerCheck(),this.attraction()}},cellBossCulture(t,e,i=20,s=5){const o=Math.random();for(let a=0;a<s;a++)spawn.cellBoss(t,e,i,o)},cellBoss(t,e,i=20,s){mobs.spawn(t+Math.random(),e+Math.random(),20,i*(1+1.2*Math.random()),"rgba(0,100,105,0.4)");let o=mob[mob.length-1];o.stroke="transparent",o.isBoss=!0,o.isCell=!0,o.cellID=s,o.accelMag=165e-6*simulation.accelScale,o.memory=40,o.isVerticesChange=!0,o.frictionAir=.012,o.seePlayerFreq=Math.floor(11+7*Math.random()),o.seeAtDistance2=14e5,o.cellMassMax=70,o.collisionFilter.mask=cat.player|cat.bullet,Matter.Body.setDensity(o,35e-5);o.split=function(){Matter.Body.scale(this,.45,.45),this.radius=Math.sqrt(642*this.mass/Math.PI),spawn.cellBoss(this.position.x,this.position.y,this.radius,this.cellID),mob[mob.length-1].health=this.health},o.onHit=function(){this.health=1,this.split()},o.onDamage=function(t){Math.random()<.34*t*Math.sqrt(this.mass)&&this.health>t&&this.split()},o.damageReduction=.17/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.do=function(){if(!m.isBodiesAsleep){if(this.seePlayerByDistOrLOS(),this.checkStatus(),this.attraction(),this.seePlayer.recall&&this.mass<this.cellMassMax){const t=1+2e-4*this.cellMassMax/this.mass;Matter.Body.scale(this,t,t),this.radius=Math.sqrt(642*this.mass/Math.PI)}if(!(simulation.cycle%this.seePlayerFreq)){const t=150,e=700;for(let i=0,s=mob.length;i<s;i++)if(mob[i].isCell&&mob[i].id!==this.id){const s=Vector.sub(this.position,mob[i].position),o=Vector.magnitude(s);o<t?this.force=Vector.mult(Vector.normalise(s),.002*this.mass):o>e&&(this.force=Vector.mult(Vector.normalise(s),.003*-this.mass))}}}},o.onDeath=function(){this.isCell=!1;let t=0;for(let e=0,i=mob.length;e<i;e++)mob[e].isCell&&mob[e].cellID===this.cellID&&t++;t<1?powerUps.spawnBossPowerUp(this.position.x,this.position.y):(this.leaveBody=!1,this.isDropPowerUp=!1)}},spawnerBossCulture(t,e,i=50,s=8+Math.min(20,.4*simulation.difficulty)){tech.deathSpawnsFromBoss+=.4;const o=Math.random();for(let a=0;a<s;a++)spawn.spawnerBoss(t,e,i,o)},spawnerBoss(t,e,i,s){mobs.spawn(t+Math.random(),e+Math.random(),4,i,"rgba(255,60,0,0.3)");let o=mob[mob.length-1];o.isBoss=!0,o.isSpawnBoss=!0,o.spawnID=s,o.accelMag=18e-5*simulation.accelScale,o.memory=1/0,o.showHealthBar=!1,o.isVerticesChange=!0,o.frictionAir=.011,o.seePlayerFreq=Math.floor(14+7*Math.random()),o.seeAtDistance2=2e5,o.stroke="transparent",o.collisionFilter.mask=cat.player|cat.bullet,Matter.Body.setAngularVelocity(o,.12*(Math.random()-.5)),o.onHit=function(){this.explode()},o.damageReduction=.2/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.doAwake=function(){if(!(m.isBodiesAsleep||(this.alwaysSeePlayer(),this.checkStatus(),this.attraction(),simulation.cycle%this.seePlayerFreq))){const t=40,e=240;for(let i=0,s=mob.length;i<s;i++)if(mob[i].isSpawnBoss&&mob[i].id!==this.id){const s=Vector.sub(this.position,mob[i].position),o=Vector.magnitude(s);o<t?this.force=Vector.mult(Vector.normalise(s),.002*this.mass):o>e&&(this.force=Vector.mult(Vector.normalise(s),.002*-this.mass))}}},o.do=function(){if(this.checkStatus(),this.seePlayer.recall){this.do=this.doAwake;for(let t=0,e=mob.length;t<e;t++)mob[t].isSpawnBoss&&mob[t].spawnID===this.spawnID&&(mob[t].seePlayer.recall=1)}},o.onDeath=function(){this.isSpawnBoss=!1;let t=0;for(let e=0,i=mob.length;e<i;e++)mob[e].isSpawnBoss&&mob[e].spawnID===this.spawnID&&t++;t<1?(powerUps.spawnBossPowerUp(this.position.x,this.position.y),tech.deathSpawnsFromBoss-=.4):(this.leaveBody=!1,this.isDropPowerUp=!1);const e=tech.deathSpawns+tech.deathSpawnsFromBoss,s=Math.min(12,e*Math.ceil(Math.random()*simulation.difficulty*e));for(let t=0;t<s;t++)spawn.spawns(this.position.x+(Math.random()-.5)*i*2.5,this.position.y+(Math.random()-.5)*i*2.5),Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+10*(Math.random()-.5),y:this.velocity.x+10*(Math.random()-.5)})}},growBossCulture(t,e,i=17,s=12+Math.min(10,.25*simulation.difficulty)){const o=Math.random(),a=200+50*Math.sqrt(s);for(let n=0;n<s;++n){const s=2*Math.PI*Math.random(),n=Math.max(i,a*(1-Math.pow(Math.random(),1.5)));spawn.growBoss(t+n*Math.cos(s),e+n*Math.sin(s),i,o)}spawn.constrain2AdjacentMobs(s,1e-4,!1)},growBoss(t,e,i,s){mobs.spawn(t+Math.random(),e+Math.random(),6,i,"hsl(144, 15%, 50%)");let o=mob[mob.length-1];o.isBoss=!0,o.isBuffBoss=!0,o.buffID=s,o.memory=1/0,o.isVerticesChange=!0,o.frictionAir=.012,o.seePlayerFreq=Math.floor(11+7*Math.random()),o.seeAtDistance2=2e5,o.stroke="transparent",o.collisionFilter.mask=cat.player|cat.bullet,o.buffCount=0,o.accelMag=5e-5,o.setBuffed=function(){this.buffCount++,this.accelMag+=24e-6,this.fill=`hsl(144, ${5+10*this.buffCount}%, 50%)`;const t=1.135;Matter.Body.scale(this,t,t),this.radius*=t,this.isInvulnerable=!0,this.damageReduction&&(this.startingDamageReduction=this.damageReduction),this.damageReduction=0,this.invulnerabilityCountDown=2*simulation.difficulty},o.onDeath=function(){this.isBuffBoss=!1;let t=0;for(let e=0,i=mob.length;e<i;e++)mob[e].isBuffBoss&&mob[e].buffID===this.buffID&&(t++,mob[e].setBuffed());t<1?powerUps.spawnBossPowerUp(this.position.x,this.position.y):(this.leaveBody=!1,this.isDropPowerUp=!1,powerUps.spawnRandomPowerUp(this.position.x,this.position.y))},o.damageReduction=.23/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.isInvulnerable=!1,o.invulnerabilityCountDown=0,o.do=function(){if(this.isInvulnerable)if(this.invulnerabilityCountDown>0){m.isBodiesAsleep||this.invulnerabilityCountDown--,ctx.beginPath();let t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y),ctx.lineWidth=20,ctx.strokeStyle="rgba(255,255,255,0.7)",ctx.stroke()}else this.isInvulnerable=!1,this.damageReduction=this.startingDamageReduction;this.alwaysSeePlayer(),this.checkStatus(),this.attraction()}},powerUpBossBaby(t,e,i=9,s=60){mobs.spawn(t,e,i,s,"rgba(225,240,245,0.4)");let o=mob[mob.length-1];o.isBoss=!0,o.frictionAir=.006,o.seeAtDistance2=1e6,o.accelMag=4e-4+3e-4*simulation.accelScale,o.collisionFilter.mask=cat.bullet|cat.player|cat.body|cat.map,o.memory=1/0,o.seePlayerFreq=20,o.lockedOn=null,9===i?(powerUps.spawnBossPowerUp(o.position.x,o.position.y),powerUps.spawn(o.position.x,o.position.y,"heal"),powerUps.spawn(o.position.x,o.position.y,"ammo")):m.isCloak||o.foundPlayer(),o.damageReduction=.2/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.isInvulnerable=!0,o.startingDamageReduction=o.damageReduction,o.damageReduction=0,o.invulnerabilityCountDown=60+2*simulation.difficulty,o.onHit=function(){powerUps.ejectTech()&&(powerUps.ejectGraphic("150, 138, 255"),powerUps.spawn(m.pos.x+60*(Math.random()-.5),m.pos.y+60*(Math.random()-.5),"ammo"),powerUps.spawn(m.pos.x+60*(Math.random()-.5),m.pos.y+60*(Math.random()-.5),"research"))},o.onDeath=function(){this.leaveBody=!1,i>3&&(this.isDropPowerUp=!1,spawn.powerUpBossBaby(this.position.x,this.position.y,i-1),Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x,y:this.velocity.y}));for(let t=0;t<powerUp.length;t++)powerUp[t].collisionFilter.mask=cat.map|cat.powerUp},o.do=function(){if(this.isInvulnerable)if(this.invulnerabilityCountDown>0){m.isBodiesAsleep||this.invulnerabilityCountDown--,ctx.beginPath();let t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y),ctx.lineWidth=20,ctx.strokeStyle="rgba(255,255,255,0.7)",ctx.stroke()}else this.isInvulnerable=!1,this.damageReduction=this.startingDamageReduction;for(let t=0;t<Math.min(powerUp.length,this.vertices.length);t++)powerUp[t].collisionFilter.mask=0,Matter.Body.setPosition(powerUp[t],this.vertices[t]),Matter.Body.setVelocity(powerUp[t],{x:0,y:0});this.seePlayerByHistory(),this.attraction(),this.checkStatus()}},powerUpBoss(t,e,i=9,s=130){mobs.spawn(t,e,i,s,"transparent");let o=mob[mob.length-1];o.isBoss=!0,o.frictionAir=.01,o.seeAtDistance2=1e6,o.accelMag=2e-4+4e-4*simulation.accelScale,Matter.Body.setDensity(o,35e-5),o.collisionFilter.mask=cat.bullet|cat.player,o.memory=1/0,o.seePlayerFreq=30,o.lockedOn=null,9===i?(powerUps.spawnBossPowerUp(o.position.x,o.position.y),powerUps.spawn(o.position.x,o.position.y,"heal"),powerUps.spawn(o.position.x,o.position.y,"ammo")):m.isCloak||o.foundPlayer(),o.damageReduction=.2/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.onHit=function(){powerUps.ejectTech()&&(powerUps.ejectGraphic("150, 138, 255"),powerUps.spawn(m.pos.x+60*(Math.random()-.5),m.pos.y+60*(Math.random()-.5),"ammo"),powerUps.spawn(m.pos.x+60*(Math.random()-.5),m.pos.y+60*(Math.random()-.5),"research"))},o.onDeath=function(){this.leaveBody=!1,i>3&&(this.isDropPowerUp=!1,spawn.powerUpBoss(this.position.x,this.position.y,i-1),Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x,y:this.velocity.y}));for(let t=0;t<powerUp.length;t++)powerUp[t].collisionFilter.mask=cat.map|cat.powerUp},o.do=function(){this.stroke=`hsl(0,0%,${80+25*Math.sin(.01*simulation.cycle)}%)`;for(let t=0;t<Math.min(powerUp.length,this.vertices.length);t++)powerUp[t].collisionFilter.mask=0,Matter.Body.setPosition(powerUp[t],this.vertices[t]),Matter.Body.setVelocity(powerUp[t],{x:0,y:0});this.seePlayerCheckByDistance(),this.attraction(),this.checkStatus()}},grower(t,e,i=15){mobs.spawn(t,e,7,i,"hsl(144, 15%, 50%)");let s=mob[mob.length-1];s.isVerticesChange=!0,s.big=!1,s.accelMag=45e-5*simulation.accelScale,s.collisionFilter.mask=cat.map|cat.body|cat.bullet|cat.player,s.do=function(){this.seePlayerByLookingAt(),this.checkStatus(),this.attraction(),this.grow()}},springer(t,e,i=20+Math.ceil(35*Math.random())){mobs.spawn(t,e,10,i,"#b386e8");let s=mob[mob.length-1];s.friction=0,s.frictionAir=.006,s.lookTorque=8e-7,s.g=2e-4,s.seePlayerFreq=Math.floor(40+25*Math.random());const o=14e-5,a=5e-4;s.springTarget={x:s.position.x,y:s.position.y};const n=cons.length;cons[n]=Constraint.create({pointA:s.springTarget,bodyB:s,stiffness:o,damping:a}),Composite.add(engine.world,cons[cons.length-1]),cons[n].length=100+1.5*i,s.cons=cons[n],s.springTarget2={x:s.position.x,y:s.position.y};const l=cons.length;cons[l]=Constraint.create({pointA:s.springTarget2,bodyB:s,stiffness:o,damping:a}),Composite.add(engine.world,cons[cons.length-1]),cons[l].length=100+1.5*i,s.cons2=cons[l],s.do=function(){this.gravity(),this.searchSpring(),this.checkStatus(),this.springAttack()},s.onDeath=function(){this.removeCons()},spawn.shield(s,t,e)},hopper(t,e,i=30+Math.ceil(30*Math.random())){mobs.spawn(t,e,5,i,"rgb(0,200,180)");let s=mob[mob.length-1];s.accelMag=.04,s.g=.0017,s.frictionAir=.01,s.friction=1,s.frictionStatic=1,s.restitution=0,s.delay=120*simulation.CDScale,s.randomHopFrequency=200+Math.floor(150*Math.random()),s.randomHopCD=simulation.cycle+s.randomHopFrequency,Matter.Body.rotate(s,Math.random()*Math.PI),spawn.shield(s,t,e),s.do=function(){if(this.gravity(),this.seePlayerCheck(),this.checkStatus(),this.seePlayer.recall){if(this.cd<simulation.cycle&&(Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length)){this.cd=simulation.cycle+this.delay;const t=(this.accelMag+this.accelMag*Math.random())*this.mass,e=Math.atan2(this.seePlayer.position.y-this.position.y,this.seePlayer.position.x-this.position.x);this.force.x+=t*Math.cos(e),this.force.y+=t*Math.sin(e)-(.07*Math.random()+.06)*this.mass}}else if(this.randomHopCD<simulation.cycle&&(Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length)){this.randomHopCD=simulation.cycle+this.randomHopFrequency,this.randomHopFrequency=Math.max(100,this.randomHopFrequency+200*(.5-Math.random()));const t=(this.accelMag+this.accelMag*Math.random())*this.mass*(.1+.3*Math.random()),e=-Math.PI/2+(Math.random()-.5)*Math.PI;this.force.x+=t*Math.cos(e),this.force.y+=t*Math.sin(e)-.05*this.mass}}},hopBoss(t,e,i=90){mobs.spawn(t,e,5,i,"rgb(0,200,180)");let s=mob[mob.length-1];s.isBoss=!0,s.g=.005,s.frictionAir=.01,s.friction=1,s.frictionStatic=1,s.restitution=0,s.accelMag=.07,s.delay=120*simulation.CDScale,s.randomHopFrequency=200,s.randomHopCD=simulation.cycle+s.randomHopFrequency,s.isInAir=!1,Matter.Body.setDensity(s,.03),spawn.shield(s,t,e,1),spawn.spawnOrbitals(s,i+60,1),s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.lastSpeed=s.speed,s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){if(this.gravity(),this.seePlayerCheck(),this.checkStatus(),this.seePlayer.recall){const t=this.lastSpeed-this.speed;if(this.lastSpeed=this.speed,t>13&&this.speed<5){const t=800;for(let e=body.length-1;e>-1;e--)body[e].isNotHoldable||(sub=Vector.sub(body[e].position,this.position),dist=Vector.magnitude(sub),dist<t&&(knock=Vector.mult(Vector.normalise(sub),Math.min(20,50*body[e].mass/dist)),body[e].force.x+=knock.x,body[e].force.y+=knock.y));simulation.drawList.push({x:this.position.x,y:this.position.y,radius:t,color:"rgba(0,200,180,0.6)",time:4})}if(this.isInAir)(this.velocity.y>-.01&&Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length)&&(this.isInAir=!1,this.cd=simulation.cycle+this.delay);else if(this.cd<simulation.cycle&&(Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length)){this.isInAir=!0;const t=(this.accelMag+this.accelMag*Math.random())*this.mass,e=Math.atan2(this.seePlayer.position.y-this.position.y,this.seePlayer.position.x-this.position.x);this.force.x+=t*Math.cos(e),this.force.y+=t*Math.sin(e)-(.05*Math.random()+.04)*this.mass}}else if(this.randomHopCD<simulation.cycle&&(Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length)){this.randomHopCD=simulation.cycle+this.randomHopFrequency,this.randomHopFrequency=Math.max(100,this.randomHopFrequency+200*(.5-Math.random()));const t=(this.accelMag+this.accelMag*Math.random())*this.mass*(.5+.2*Math.random()),e=-Math.PI/2+(Math.random()-.5)*Math.PI;this.force.x+=t*Math.cos(e),this.force.y+=t*Math.sin(e)-(.1+.08*Math.random())*this.mass}}},spinner(t,e,i=30+Math.ceil(35*Math.random())){mobs.spawn(t,e,5,i,"#000000");let s=mob[mob.length-1];s.fill="#28b",s.rememberFill=s.fill,s.cd=0,s.burstDir={x:0,y:0},s.frictionAir=.022,s.lookTorque=14e-7,s.restitution=0,spawn.shield(s,t,e),s.look=function(){this.seePlayerByLookingAt(),this.checkStatus(),this.seePlayer.recall&&this.cd<simulation.cycle&&(this.burstDir=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)),this.cd=simulation.cycle+40,this.do=this.spin)},s.do=s.look,s.spin=function(){this.checkStatus(),this.torque+=35e-6*this.inertia,this.fill=randomColor({hue:"blue"});const t=2.5*this.radius+50;ctx.strokeStyle="rgba(0,0,0,0.2)",ctx.lineWidth=3,ctx.setLineDash([10,20]);const e=Vector.add(this.position,Vector.mult(this.burstDir,t));ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(e.x,e.y),ctx.stroke(),ctx.setLineDash([]),this.cd<simulation.cycle&&(this.fill=this.rememberFill,this.cd=simulation.cycle+180*simulation.CDScale,this.do=this.look,this.force=Vector.mult(this.burstDir,.25*this.mass))}},sucker(t,e,i=30+Math.ceil(25*Math.random())){i=9+i/8,mobs.spawn(t,e,6,i,"transparent");let s=mob[mob.length-1];s.stroke="transparent",s.eventHorizon=23*i,s.seeAtDistance2=(s.eventHorizon+400)*(s.eventHorizon+400),s.accelMag=1e-4*simulation.accelScale,s.frictionAir=.025,s.collisionFilter.mask=cat.player|cat.bullet,s.memory=1/0,Matter.Body.setDensity(s,.008),s.do=function(){this.speed>5&&Matter.Body.setVelocity(this,{x:.99*this.velocity.x,y:.99*this.velocity.y}),this.seePlayerCheckByDistance(),this.checkStatus();const t=this.eventHorizon*(.93+.17*Math.sin(.011*simulation.cycle)),e=this.accelMag*this.mass,i=Math.atan2(this.seePlayer.position.y-this.position.y,this.seePlayer.position.x-this.position.x);if(this.force.x+=e*Math.cos(i),this.force.y+=e*Math.sin(i),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.25*t,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.9)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.55*t,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.5)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,t,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.1)",ctx.fill(),Vector.magnitude(Vector.sub(this.position,player.position))<t){m.immuneCycle<m.cycle&&(m.energy>0&&(m.energy-=.004),m.energy<.1&&m.damage(15e-5*simulation.dmgScale));const t=Math.atan2(player.position.y-this.position.y,player.position.x-this.position.x);player.force.x-=.00125*player.mass*Math.cos(t)*(m.onGround?1.8:1),player.force.y-=1e-4*player.mass*Math.sin(t),ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(m.pos.x,m.pos.y),ctx.lineWidth=Math.min(60,2*this.radius),ctx.strokeStyle="rgba(0,0,0,0.5)",ctx.stroke(),ctx.beginPath(),ctx.arc(m.pos.x,m.pos.y,40,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.3)",ctx.fill()}}},suckerBoss(t,e,i=25){mobs.spawn(t,e,12,i,"#000");let s=mob[mob.length-1];s.isBoss=!0,s.stroke="transparent",s.eventHorizon=1100,s.seeAtDistance2=(s.eventHorizon+1200)*(s.eventHorizon+1200),s.accelMag=3e-5*simulation.accelScale,s.collisionFilter.mask=cat.player|cat.bullet,s.memory=1600,Matter.Body.setDensity(s,.03),s.onDeath=function(){if(powerUps.spawnBossPowerUp(this.position.x,this.position.y),simulation.difficulty>5){function t(t,e,i){for(let s=0,o=t.length;s<o;s++)if(!t[s].isNotHoldable){const o=Vector.sub(t[s].position,e);Vector.magnitude(o)<i&&Matter.Body.setPosition(t[s],e)}}t(body,this.position,this.eventHorizon),t(mob,this.position,this.eventHorizon)}},s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){if(this.speed>1&&Matter.Body.setVelocity(this,{x:.95*this.velocity.x,y:.95*this.velocity.y}),simulation.cycle%this.seePlayerFreq||(this.distanceToPlayer2()<this.seeAtDistance2?(this.locatePlayer(),this.seePlayer.yes||(this.seePlayer.yes=!0)):this.seePlayer.recall&&this.lostPlayer()),this.checkStatus(),this.seePlayer.recall){if(!(simulation.cycle%240||m.isBodiesAsleep)){spawn.seeker(this.position.x,this.position.y,15*(.7+.5*Math.random()),7);const t=mob[mob.length-1];Matter.Body.setDensity(t,1e-5),t.timeLeft=600,t.accelMag=2e-4*simulation.accelScale,t.frictionAir=.01;const e=Vector.mult(Vector.normalise(Vector.sub(m.pos,this.position)),-20);Matter.Body.setVelocity(t,{x:this.velocity.x+e.x,y:this.velocity.y+e.y})}const t=this.accelMag*this.mass,e=this.seePlayer.position.x-this.position.x,i=this.seePlayer.position.y-this.position.y,s=Math.sqrt(e*e+i*i);this.force.x+=t*e/s,this.force.y+=t*i/s;const o=this.eventHorizon*(1+.2*Math.sin(.008*simulation.cycle));if(ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.2*o,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.6)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.4*o,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.4)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.6*o,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.3)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,.8*o,0,2*Math.PI),ctx.fillStyle="rgba(0,20,40,0.2)",ctx.fill(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,o,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.05)",ctx.fill(),Vector.magnitude(Vector.sub(this.position,player.position))<o){m.immuneCycle<m.cycle&&(m.energy>0&&(m.energy-=.006),m.energy<.1&&m.damage(2e-4*simulation.dmgScale));const t=Math.atan2(player.position.y-this.position.y,player.position.x-this.position.x);player.force.x-=.0013*Math.cos(t)*player.mass*(m.onGround?1.7:1),player.force.y-=.0013*Math.sin(t)*player.mass,ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(m.pos.x,m.pos.y),ctx.lineWidth=Math.min(60,2*this.radius),ctx.strokeStyle="rgba(0,0,0,0.5)",ctx.stroke(),ctx.beginPath(),ctx.arc(m.pos.x,m.pos.y,40,0,2*Math.PI),ctx.fillStyle="rgba(0,0,0,0.3)",ctx.fill()}this.curl(o)}}},spiderBoss(t,e,i=60+Math.ceil(10*Math.random())){let s=[];mobs.spawn(t,e,6,i,"#b386e8");let o=mob[mob.length-1];Matter.Body.setDensity(o,.0032),o.isBoss=!0,s.push(o.id),o.friction=0,o.frictionAir=.0067,o.lookTorque=8e-7,o.g=2e-4,o.seePlayerFreq=Math.floor(30+20*Math.random());const a=14e-5,n=5e-4;o.springTarget={x:o.position.x,y:o.position.y};const l=cons.length;cons[l]=Constraint.create({pointA:o.springTarget,bodyB:o,stiffness:a,damping:n}),Composite.add(engine.world,cons[cons.length-1]),cons[l].length=100+1.5*i,o.cons=cons[l],o.springTarget2={x:o.position.x,y:o.position.y};const r=cons.length;cons[r]=Constraint.create({pointA:o.springTarget2,bodyB:o,stiffness:a,damping:n,length:0}),Composite.add(engine.world,cons[cons.length-1]),cons[r].length=100+1.5*i,o.cons2=cons[r],o.damageReduction=.2/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.do=function(){this.gravity(),this.searchSpring(),this.checkStatus(),this.springAttack()},o.onDeath=function(){this.removeCons(),powerUps.spawnBossPowerUp(this.position.x,this.position.y)},i=22;const c=2*Math.PI/6;spawn.allowShields=!1;for(let o=0;o<6;++o)spawn.stabber(t+100*Math.sin(o*c),e+100*Math.cos(o*c),i,12),Matter.Body.setDensity(mob[mob.length-1],.003),mob[mob.length-1].damageReduction=.5,s.push(mob[mob.length-1].id);spawn.constrain2AdjacentMobs(6,.02,!0);for(let t=0;t<6;++t)consBB[consBB.length]=Constraint.create({bodyA:o,bodyB:mob[mob.length-t-1],stiffness:.02,damping:.03}),Composite.add(engine.world,consBB[consBB.length-1]);spawn.groupShield(s,t,e,100+1*i+30-25),spawn.allowShields=!0},mantisBoss(t,e,i=35){mobs.spawn(t,e,5,i,"#6ba");let s=mob[mob.length-1];s.babyList=[],Matter.Body.setDensity(s,.001),s.damageReduction=.15/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.isBoss=!0,s.friction=0,s.frictionAir=.0067,s.g=2e-4,s.seePlayerFreq=300;const o=8e-5;s.springTarget={x:s.position.x,y:s.position.y};const a=cons.length;cons[a]=Constraint.create({pointA:s.springTarget,bodyB:s,stiffness:o,damping:.01}),Composite.add(engine.world,cons[cons.length-1]),cons[a].length=100+1.5*i,s.cons=cons[a],s.springTarget2={x:s.position.x,y:s.position.y};const n=cons.length;cons[n]=Constraint.create({pointA:s.springTarget2,bodyB:s,stiffness:o,damping:.01,length:0}),Composite.add(engine.world,cons[cons.length-1]),cons[n].length=100+1.5*i,s.cons2=cons[n],s.startingDamageReduction=s.damageReduction,s.isInvulnerable=!1,s.invulnerabilityCountDown=0,s.do=function(){if(this.checkStatus(),this.gravity(),ctx.beginPath(),ctx.arc(this.cons.pointA.x,this.cons.pointA.y,6,0,2*Math.PI),ctx.arc(this.cons2.pointA.x,this.cons2.pointA.y,6,0,2*Math.PI),ctx.fillStyle="#222",ctx.fill(),this.seePlayerCheck(),this.isInvulnerable){ctx.beginPath();let t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y);for(let t=0;t<this.babyList.length;t++)if(this.babyList[t].alive){let e=this.babyList[t].vertices;ctx.moveTo(e[0].x,e[0].y);for(let t=1;t<e.length;t++)ctx.lineTo(e[t].x,e[t].y);ctx.lineTo(e[0].x,e[0].y)}ctx.lineWidth=20,ctx.strokeStyle="rgba(255,255,255,0.7)",ctx.stroke()}else if(this.invulnerabilityCountDown>0)m.isBodiesAsleep||this.invulnerabilityCountDown--;else{this.isInvulnerable=!0,this.damageReduction&&(this.startingDamageReduction=this.damageReduction),this.damageReduction=0;for(let t=0;t<this.babyList.length;t++)this.babyList[t].alive&&(this.babyList[t].isInvulnerable=!0,this.babyList[t].damageReduction=0)}if(this.seePlayer.recall&&0===Matter.Query.ray(map,this.position,this.seePlayer.position).length)if(simulation.cycle%(2*this.seePlayerFreq)){if(!(simulation.cycle%this.seePlayerFreq)){const t=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)),e=Vector.add(this.position,Vector.mult(t,1200));this.springTarget2.x=e.x,this.springTarget2.y=e.y,this.cons.length=100+1.5*this.radius,this.cons2.length=-200,this.isInvulnerable=!1,this.invulnerabilityCountDown=45+Math.max(0,70-simulation.difficulty),this.damageReduction=this.startingDamageReduction;for(let t=0;t<this.babyList.length;t++)this.babyList[t].alive&&(this.babyList[t].damageReduction=this.startingDamageReduction)}}else{const t=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)),e=Vector.add(this.position,Vector.mult(t,1200));this.springTarget.x=e.x,this.springTarget.y=e.y,this.cons.length=-200,this.cons2.length=100+1.5*this.radius,this.isInvulnerable=!1,this.invulnerabilityCountDown=60+Math.max(0,70-.5*simulation.difficulty),this.damageReduction=this.startingDamageReduction;for(let t=0;t<this.babyList.length;t++)this.babyList[t].alive&&(this.babyList[t].damageReduction=this.startingDamageReduction)}else{this.torque=this.lookTorque*this.inertia;const t=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}};if(!(simulation.cycle%this.seePlayerFreq)){best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const e=3e3,i={x:this.position.x+e*Math.cos(this.angle),y:this.position.y+e*Math.sin(this.angle)};t(this.position,i,map),best.dist2!=1/0&&(this.springTarget.x=best.x,this.springTarget.y=best.y,this.cons.length=100+1.5*this.radius,this.cons2.length=100+1.5*this.radius)}}},s.onDeath=function(){this.removeCons(),powerUps.spawnBossPowerUp(this.position.x,this.position.y);for(let t=0;t<this.babyList.length;t++)this.babyList[t].alive&&(this.babyList[t].collisionFilter.mask=cat.map|cat.bullet|cat.player,this.babyList[t].isInvulnerable=!1,this.babyList[t].damageReduction=this.startingDamageReduction,this.babyList[t].collisionFilter.mask=cat.bullet|cat.player|cat.map|cat.body)};const l=2*Math.PI/3;spawn.allowShields=!1;for(let i=0;i<3;++i){spawn.striker(t+80*Math.sin(i*l),e+80*Math.cos(i*l),20,12);const o=mob[mob.length-1];s.babyList.push(o),o.fill="rgb(68, 102, 119)",o.isBoss=!0,o.damageReduction=this.startingDamageReduction,o.collisionFilter.mask=cat.bullet|cat.player,o.delay=60+55*simulation.CDScale+Math.floor(20*Math.random()),o.strikeRange=400,o.onHit=function(){if(this.cd=simulation.cycle+this.delay,b.inventory.length){let t=!1;const e=3;for(let i=0;i<e;i++)for(let e=0;e<b.inventory.length;e++){const i=b.guns[b.inventory[e]];i.ammo>0&&i.ammo!==1/0&&(i.ammo-=Math.ceil((.45*Math.random()+.45*Math.random())*i.ammoPack),i.ammo<0&&(i.ammo=0),t=!0)}if(t){simulation.updateGunHUD();for(let t=0;t<e;t++)powerUps.directSpawn(this.position.x+10*Math.random(),this.position.y+10*Math.random(),"ammo");powerUps.ejectGraphic()}}}}const r=.01;for(let t=1;t<3;++t)consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-t],bodyB:mob[mob.length-t-1],stiffness:r,damping:.1}),Composite.add(engine.world,consBB[consBB.length-1]);consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-1],bodyB:mob[mob.length-3],stiffness:r,damping:.1}),Composite.add(engine.world,consBB[consBB.length-1]);for(let t=0;t<3;++t)consBB[consBB.length]=Constraint.create({bodyA:s,bodyB:mob[mob.length-t-1],stiffness:r,damping:.1}),Composite.add(engine.world,consBB[consBB.length-1]);spawn.allowShields=!0},beamer(t,e,i=15+Math.ceil(15*Math.random())){mobs.spawn(t,e,4,i,"rgb(255,0,190)");let s=mob[mob.length-1];s.repulsionRange=73e3,s.laserRange=370,s.accelMag=5e-4*simulation.accelScale,s.frictionStatic=0,s.friction=0,spawn.shield(s,t,e),s.do=function(){this.seePlayerByLookingAt(),this.checkStatus(),this.attraction(),this.repulsion(),this.harmZone()}},historyBoss(t,e,i=30){if(tech.dynamoBotCount>0)return void spawn.randomLevelBoss(t,e,spawn.nonCollideBossList);mobs.spawn(t,e,0,i,"transparent");let s=mob[mob.length-1];Matter.Body.setDensity(s,.21),s.laserRange=350,s.seeAtDistance2=2e6,s.isBoss=!0,s.showHealthBar=!1,s.delayLimit=60+Math.floor(30*Math.random()),s.followDelay=600-Math.floor(90*Math.random()),s.stroke="transparent",s.collisionFilter.mask=cat.bullet|cat.body,s.memory=1/0,s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.damageReduction=.35/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.awake=function(){this.checkStatus();const t=.3*this.radius,e=2*this.radius,i=this.position.x-e/2,s=this.position.y-.7*e;ctx.fillStyle="rgba(100, 100, 100, 0.3)",ctx.fillRect(i,s,e,t),ctx.fillStyle="rgba(150,0,255,0.7)",ctx.fillRect(i,s,e*this.health,t);const o=Vector.normalise(Vector.sub(m.pos,this.position)),a=Vector.add(Vector.mult(o,15),this.position);ctx.beginPath(),ctx.arc(a.x,a.y,4,0,2*Math.PI),ctx.moveTo(this.position.x+20*o.x,this.position.y+20*o.y),ctx.lineTo(this.position.x+30*o.x,this.position.y+30*o.y),ctx.strokeStyle=this.stroke,ctx.lineWidth=2,ctx.stroke(),ctx.setLineDash([125*Math.random(),125*Math.random()]),this.distanceToPlayer()<this.laserRange&&(m.immuneCycle<m.cycle&&(m.energy>.002?m.energy-=.004:m.damage(4e-4*simulation.dmgScale)),ctx.beginPath(),ctx.moveTo(a.x,a.y),ctx.lineTo(m.pos.x,m.pos.y),ctx.lineTo(m.pos.x+3e3*(Math.random()-.5),m.pos.y+3e3*(Math.random()-.5)),ctx.lineWidth=2,ctx.strokeStyle="rgb(150,0,255)",ctx.stroke(),ctx.beginPath(),ctx.arc(m.pos.x,m.pos.y,40,0,2*Math.PI),ctx.fillStyle="rgba(150,0,255,0.1)",ctx.fill());const n=.015*simulation.cycle,l=.021*simulation.cycle;ctx.lineWidth=1,ctx.fillStyle="rgba(150,0,255,0.05)",ctx.strokeStyle="#70f";for(let t=0,e=6;t<e;t++)ctx.beginPath(),ctx.ellipse(this.position.x,this.position.y,this.laserRange*Math.abs(Math.sin(l+t/e*Math.PI)),this.laserRange,n,0,2*Math.PI),ctx.fill(),ctx.stroke();if(!m.isBodiesAsleep&&!this.isStunned&&!this.isSlowed){this.followDelay>this.delayLimit&&(this.followDelay-=.15);let t=m.history[(m.cycle-Math.floor(this.followDelay))%600];Matter.Body.setPosition(this,{x:t.position.x,y:t.position.y-t.yOff+24.2859})}},s.do=function(){(this.seePlayer.recall||!(simulation.cycle%this.seePlayerFreq)&&this.distanceToPlayer2()<this.seeAtDistance2&&!m.isCloak)&&setTimeout((()=>{this.do=this.awake,this.stroke="rgba(205,0,255,0.5)",this.fill="rgba(205,0,255,0.1)",this.seePlayer.yes=!0}),2e3),this.checkStatus()}},focuser(t,e,i=30+Math.ceil(10*Math.random())){i=Math.ceil(.7*i),mobs.spawn(t,e,4,i,"rgb(0,0,255)");let s=mob[mob.length-1];Matter.Body.setDensity(s,.003),s.restitution=0,s.laserPos=s.position,s.repulsionRange=12e5,s.accelMag=9e-5*simulation.accelScale,s.frictionStatic=0,s.friction=0,s.onDamage=function(){this.laserPos=this.position},spawn.shield(s,t,e),s.do=function(){if(!m.isBodiesAsleep){this.seePlayerByLookingAt(),this.checkStatus(),this.attraction();const t=this.distanceToPlayer2();if(this.seePlayer.yes&&t<4e6){const e=2e3;this.laserPos=Vector.add(this.laserPos,Vector.mult(Vector.sub(player.position,this.laserPos),.1));let i=Vector.magnitude(Vector.sub(this.laserPos,m.pos));const s=12;if(ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),i<s+16){i=s+10;const t=40*this.accelMag*this.mass,e=Math.atan2(this.seePlayer.position.y-this.position.y,this.seePlayer.position.x-this.position.x);this.force.x+=t*Math.cos(e),this.force.y+=t*Math.sin(e)}if(t>8e4){const t=.002;let o=Vector.rotateAbout(this.laserPos,(i-s)*t,this.position),a=Vector.normalise(Vector.sub(o,this.position));o=Vector.add(o,Vector.mult(a,e)),ctx.lineTo(o.x,o.y);let n=Vector.rotateAbout(this.laserPos,(i-s)*-t,this.position);a=Vector.normalise(Vector.sub(n,this.position)),n=Vector.add(n,Vector.mult(a,e)),ctx.lineTo(n.x,n.y),ctx.fillStyle=`rgba(0,0,255,${Math.max(0,.3*s/i)})`,ctx.fill()}}else this.laserPos=this.position}}},laserTargetingBoss(t,e,i=80){const s="#05f";mobs.spawn(t,e,3,i,s);let o=mob[mob.length-1];o.isBoss=!0,o.vertices=Matter.Vertices.rotate(o.vertices,Math.PI,o.position),Matter.Body.rotate(o,Math.random()*Math.PI*2),o.accelMag=18e-5*Math.sqrt(simulation.accelScale),o.seePlayerFreq=30,o.memory=420,o.restitution=1,o.frictionAir=.01,o.frictionStatic=0,o.friction=0,o.lookTorque=1e-6*(Math.random()>.5?-1:1),o.fireDir={x:0,y:0},Matter.Body.setDensity(o,.008),spawn.shield(o,t,e,1),spawn.spawnOrbitals(o,i+200+300*Math.random()),o.onHit=function(){},o.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},o.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.do=function(){if(this.seePlayerByLookingAt(),this.checkStatus(),this.attraction(),this.seePlayer.recall){simulation.cycle%this.seePlayerFreq||(this.fireDir=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)));const t=this.angle+Math.PI/2;c=Math.cos(t)*this.fireDir.x+Math.sin(t)*this.fireDir.y;const e=.4;c>e?this.torque+=4e-6*this.inertia:c<-e&&(this.torque-=4e-6*this.inertia);const i=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}},o=8e3;best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const a={x:this.position.x+o*Math.cos(this.angle),y:this.position.y+o*Math.sin(this.angle)};if(i(this.position,a,map),i(this.position,a,body),m.isCloak||i(this.position,a,[playerBody,playerHead]),(best.who===playerBody||best.who===playerHead)&&m.immuneCycle<m.cycle){const t=.002*simulation.dmgScale;m.damage(t),ctx.fillStyle=s,ctx.beginPath(),ctx.arc(best.x,best.y,1e4*t,0,2*Math.PI),ctx.fill()}best.dist2===1/0&&(best=a),ctx.beginPath(),ctx.moveTo(this.vertices[1].x,this.vertices[1].y),ctx.lineTo(best.x,best.y),ctx.strokeStyle=s,ctx.lineWidth=3,ctx.setLineDash([50+120*Math.random(),50*Math.random()]),ctx.stroke(),ctx.setLineDash([])}}},laserBombingBoss(t,e,i=80){mobs.spawn(t,e,3,i,"rgb(0,235,255)");let s=mob[mob.length-1];s.isBoss=!0,s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),Matter.Body.rotate(s,Math.random()*Math.PI*2),s.accelMag=55e-5*Math.sqrt(simulation.accelScale),s.seePlayerFreq=30,s.memory=420,s.restitution=1,s.frictionAir=.05,s.frictionStatic=0,s.friction=0,s.lookTorque=55e-7*(Math.random()>.5?-1:1)*(1+.1*Math.sqrt(simulation.difficulty)),s.fireDir={x:0,y:0},Matter.Body.setDensity(s,.01),spawn.shield(s,t,e,1),spawn.spawnOrbitals(s,i+200+300*Math.random()),s.onHit=function(){},s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.targetingCount=0,s.targetingTime=60-Math.min(58,3*simulation.difficulty),s.do=function(){if(this.seePlayerByLookingAt(),this.checkStatus(),this.attraction(),this.seePlayer.recall){simulation.cycle%this.seePlayerFreq||(this.fireDir=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)));const t=this.angle+Math.PI/2;c=Math.cos(t)*this.fireDir.x+Math.sin(t)*this.fireDir.y;const e=.02;c>e?this.torque+=4e-6*this.inertia:c<-e&&(this.torque-=4e-6*this.inertia);const i=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}},s=8e3;best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const o={x:this.position.x+s*Math.cos(this.angle),y:this.position.y+s*Math.sin(this.angle)};if(i(this.position,o,map),m.isCloak||i(this.position,o,[playerBody,playerHead]),best.who===playerBody||best.who===playerHead){if(this.targetingCount++,this.targetingCount>this.targetingTime){this.targetingCount-=10;const t=Vector.sub(player.position,this.position),e=Vector.magnitude(t),i=Math.min(55,5+20*simulation.accelScale),s=Vector.mult(Vector.normalise(t),i);spawn.grenade(this.vertices[1].x,this.vertices[1].y,e/i,Math.min(550,250+3*simulation.difficulty),6),Matter.Body.setVelocity(mob[mob.length-1],s)}}else this.targetingCount>0&&this.targetingCount--;best.dist2===1/0&&(best=o),ctx.beginPath(),ctx.moveTo(this.vertices[1].x,this.vertices[1].y),ctx.lineTo(best.x,best.y),ctx.strokeStyle="rgba(0,235,255,1)",ctx.lineWidth=3,ctx.stroke(),this.targetingCount/this.targetingTime>.33&&(ctx.strokeStyle="rgba(0,235,255,0.45)",ctx.lineWidth=10,ctx.stroke(),this.targetingCount/this.targetingTime>.66&&(ctx.strokeStyle="rgba(0,235,255,0.25)",ctx.lineWidth=30,ctx.stroke()))}}},blinkBoss(t,e){mobs.spawn(t,e,5,50,"rgb(0,235,255)");let i=mob[mob.length-1];Matter.Body.rotate(i,.1*Math.PI),Matter.Body.setDensity(i,.018),i.isBoss=!0,i.frictionStatic=0,i.friction=0,i.memory=240,i.seePlayerFreq=60,i.blinkRange=235,.5<Math.random()?(i.grenadeDelay=260,i.blinkRange*=1.5):i.grenadeDelay=100,i.pulseRadius=1.5*Math.min(550,200+2*simulation.difficulty),i.delay=30+35*simulation.CDScale,i.nextBlinkCycle=i.delay,spawn.shield(i,t,e,1),i.onDamage=function(){},i.onDeath=function(){const t=Math.PI*Math.random();for(let e=0,i=3;e<i;e++){spawn.grenade(this.position.x,this.position.y,this.grenadeDelay);const s=mob[mob.length-1],o=5*simulation.accelScale,a=2*Math.PI*e/i+t;Matter.Body.setVelocity(s,{x:o*Math.cos(a),y:o*Math.sin(a)})}powerUps.spawnBossPowerUp(this.position.x,this.position.y)},i.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),i.do=function(){if(this.seePlayerByHistory(),this.nextBlinkCycle<simulation.cycle&&this.seePlayer.yes){this.nextBlinkCycle=simulation.cycle+this.delay;const t=Vector.sub(this.seePlayer.position,this.position),e=Vector.magnitude(t);ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),e<this.blinkRange?Matter.Body.setPosition(this,this.seePlayer.position):Matter.Body.translate(this,Vector.mult(Vector.normalise(t),this.blinkRange)),spawn.grenade(this.position.x,this.position.y,this.grenadeDelay,this.pulseRadius),ctx.lineTo(this.position.x,this.position.y),ctx.lineWidth=2.1*this.radius,ctx.strokeStyle=this.fill,ctx.stroke(),Matter.Body.setVelocity(this,{x:0,y:0}),this.torque+=(4e-5+3e-5*Math.random())*this.inertia*(2*Math.round(Math.random())-1)}this.checkStatus()}},pulsarBoss(t,e,i=90,s=!1){mobs.spawn(t,e,3,i,"#a0f");let o=mob[mob.length-1];s&&(o.collisionFilter.mask=cat.bullet|cat.player),setTimeout((()=>{o.constraint=Constraint.create({pointA:{x:o.position.x,y:o.position.y},bodyB:o,stiffness:1e-4,damping:.3}),Composite.add(engine.world,o.constraint)}),2e3),o.vertices=Matter.Vertices.rotate(o.vertices,Math.PI,o.position),Matter.Body.rotate(o,Math.random()*Math.PI*2),o.radius*=1.5,o.vertices[1].x=o.position.x+Math.cos(o.angle)*o.radius,o.vertices[1].y=o.position.y+Math.sin(o.angle)*o.radius,o.fireCycle=0,o.fireTarget={x:0,y:0},o.pulseRadius=Math.min(500,230+3*simulation.difficulty),o.fireDelay=Math.max(60,150-2*simulation.difficulty),o.isFiring=!1,Matter.Body.setDensity(o,.01),o.isBoss=!0,spawn.shield(o,t,e,1),spawn.spawnOrbitals(o,i+200+300*Math.random(),1),o.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},o.onHit=function(){},o.do=function(){player.speed>5&&(this.do=this.fire)},o.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.fire=function(){if(this.checkStatus(),!m.isBodiesAsleep)if(m.isCloak||this.isStunned)this.isFiring=!1;else if(this.isFiring)this.fireCycle>this.fireDelay?(this.isFiring=!1,this.fireCycle=0,this.torque+=(8e-5+7e-5*Math.random())*this.inertia*(2*Math.round(Math.random())-1),Matter.Query.ray([player],this.fireTarget,this.position).length&&(unit=Vector.mult(Vector.normalise(Vector.sub(this.vertices[1],this.position)),this.distanceToPlayer()-100),this.fireTarget=Vector.add(this.vertices[1],unit)),Vector.magnitude(Vector.sub(player.position,this.fireTarget))<this.pulseRadius&&m.immuneCycle<m.cycle&&(m.immuneCycle=m.cycle+tech.collisionImmuneCycles,m.damage(.045*simulation.dmgScale)),simulation.drawList.push({x:this.fireTarget.x,y:this.fireTarget.y,radius:this.pulseRadius,color:"rgba(120,0,255,0.6)",time:simulation.drawTime}),ctx.beginPath(),ctx.moveTo(this.vertices[1].x,this.vertices[1].y),ctx.lineTo(this.fireTarget.x,this.fireTarget.y),ctx.lineWidth=20,ctx.strokeStyle="rgba(120,0,255,0.3)",ctx.stroke(),ctx.lineWidth=5,ctx.strokeStyle="rgba(120,0,255,1)",ctx.stroke()):(this.fireCycle++,ctx.beginPath(),ctx.arc(this.fireTarget.x,this.fireTarget.y,this.pulseRadius,0,2*Math.PI),ctx.fillStyle="rgba(120,0,255,0.07)",ctx.fill(),ctx.beginPath(),ctx.moveTo(this.vertices[1].x,this.vertices[1].y),ctx.lineTo(this.fireTarget.x,this.fireTarget.y),ctx.setLineDash([40*Math.random(),200*Math.random()]),ctx.lineWidth=2,ctx.strokeStyle="rgba(120,0,255,0.3)",ctx.stroke(),ctx.setLineDash([]));else{this.fireCycle++,this.fireDir=Vector.normalise(Vector.sub(m.pos,this.position));const t=this.angle+Math.PI/2,e=Math.cos(t)*this.fireDir.x+Math.sin(t)*this.fireDir.y,i=.04;e>i?this.torque+=15e-7*this.inertia:e<-i?this.torque-=15e-7*this.inertia:this.fireCycle>45&&(unit=Vector.mult(Vector.normalise(Vector.sub(this.vertices[1],this.position)),this.distanceToPlayer()-100),this.fireTarget=Vector.add(this.vertices[1],unit),Vector.magnitude(Vector.sub(m.pos,this.fireTarget))<1e3&&(Matter.Body.setAngularVelocity(this,0),this.fireLockCount=0,this.isFiring=!0,this.fireCycle=0))}}},pulsar(t,e,i=40){mobs.spawn(t,e,3,i,"#f08");let s=mob[mob.length-1];s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),Matter.Body.rotate(s,Math.random()*Math.PI*2),s.radius*=2,s.vertices[1].x=s.position.x+Math.cos(s.angle)*s.radius,s.vertices[1].y=s.position.y+Math.sin(s.angle)*s.radius,Matter.Body.setDensity(s,.002),s.fireCycle=1/0,s.fireTarget={x:0,y:0},s.pulseRadius=Math.min(400,170+3*simulation.difficulty),s.fireDelay=Math.max(75,140-.5*simulation.difficulty),s.isFiring=!1,s.onHit=function(){},s.canSeeTarget=function(){const t=this.angle+Math.PI/2;return!(Vector.dot({x:Math.cos(t),y:Math.sin(t)},Vector.normalise(Vector.sub(this.fireTarget,this.position)))>.03||Matter.Query.ray(map,this.fireTarget,this.position).length||Matter.Query.ray(body,this.fireTarget,this.position).length||Vector.magnitude(Vector.sub(m.pos,this.fireTarget))>1e3)||(this.isFiring=!1,!1)},s.do=function(){if(this.seePlayerByLookingAt(),this.checkStatus(),!m.isBodiesAsleep)if(this.seePlayer.recall)if(this.isFiring)if(this.fireCycle>this.fireDelay){if(!this.canSeeTarget())return;this.isFiring=!1,this.fireCycle=0,this.torque+=(2e-5+2e-4*Math.random())*this.inertia*(2*Math.round(Math.random())-1),Matter.Query.ray([player],this.fireTarget,this.position).length&&(unit=Vector.mult(Vector.normalise(Vector.sub(this.vertices[1],this.position)),this.distanceToPlayer()-100),this.fireTarget=Vector.add(this.vertices[1],unit)),Vector.magnitude(Vector.sub(player.position,this.fireTarget))<this.pulseRadius&&m.immuneCycle<m.cycle&&(m.immuneCycle=m.cycle+tech.collisionImmuneCycles,m.damage(.03*simulation.dmgScale)),simulation.drawList.push({x:this.fireTarget.x,y:this.fireTarget.y,radius:this.pulseRadius,color:"rgba(255,0,100,0.6)",time:simulation.drawTime}),ctx.beginPath(),ctx.moveTo(this.vertices[1].x,this.vertices[1].y),ctx.lineTo(this.fireTarget.x,this.fireTarget.y),ctx.lineWidth=20,ctx.strokeStyle="rgba(255,0,100,0.3)",ctx.stroke(),ctx.lineWidth=5,ctx.strokeStyle="rgba(255,0,100,1)",ctx.stroke()}else{if(this.fireCycle++,!(simulation.cycle%3||this.canSeeTarget()))return;ctx.beginPath(),ctx.arc(this.fireTarget.x,this.fireTarget.y,this.pulseRadius,0,2*Math.PI),ctx.fillStyle="rgba(255,0,100,0.07)",ctx.fill(),ctx.beginPath(),ctx.moveTo(this.vertices[1].x,this.vertices[1].y),ctx.lineTo(this.fireTarget.x,this.fireTarget.y),ctx.setLineDash([40*Math.random(),200*Math.random()]),ctx.lineWidth=2,ctx.strokeStyle="rgba(255,0,100,0.3)",ctx.stroke(),ctx.setLineDash([])}else{this.fireCycle++;const t=this.angle+Math.PI/2,e=Vector.dot({x:Math.cos(t),y:Math.sin(t)},Vector.normalise(Vector.sub(this.seePlayer.position,this.position))),i=.04;if(e>i)this.torque+=15e-7*this.inertia;else if(e<-i)this.torque-=15e-7*this.inertia;else if(this.fireCycle>60){if(unit=Vector.mult(Vector.normalise(Vector.sub(this.vertices[1],this.position)),this.distanceToPlayer()-100),this.fireTarget=Vector.add(this.vertices[1],unit),!this.canSeeTarget())return;Matter.Body.setAngularVelocity(this,0),this.fireLockCount=0,this.isFiring=!0,this.fireCycle=0}}else this.isFiring=!1}},laser(t,e,i=30){mobs.spawn(t,e,3,i,"#f00");let s=mob[mob.length-1];s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),Matter.Body.rotate(s,Math.random()*Math.PI*2),s.accelMag=1e-4*simulation.accelScale,s.onHit=function(){this.explode()},s.do=function(){this.seePlayerByLookingAt(),this.checkStatus(),this.attraction(),this.laser(),this.torque=this.lookTorque*this.inertia*.5}},laserBoss(t,e,i=30){mobs.spawn(t,e,3,i,"#f00");let s=mob[mob.length-1];setTimeout((()=>{s.constraint=Constraint.create({pointA:{x:s.position.x,y:s.position.y},bodyB:s,stiffness:1,damping:1}),Composite.add(engine.world,s.constraint)}),2e3),s.count=0,s.frictionAir=.03,spawn.spawnOrbitals(s,i+50+200*Math.random()),Matter.Body.setDensity(s,.03),s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.isBoss=!0,s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.rotateVelocity=Math.min(.0045,.0015*simulation.accelScale*simulation.accelScale)*(level.levelsCleared>8?1:-1)*(simulation.isHorizontalFlipped?-1:1),s.do=function(){if(this.fill="#"+Math.random().toString(16).substr(-6),this.checkStatus(),!this.isStunned){if(!m.isBodiesAsleep){let t=!1;for(let e=0;e<this.status.length;e++)if("slow"===this.status[e].type){t=!0;break}t||(this.count++,Matter.Body.setAngle(this,this.count*this.rotateVelocity),Matter.Body.setAngularVelocity(this,0))}ctx.beginPath(),this.lasers(this.vertices[0],this.angle+Math.PI/3),this.lasers(this.vertices[1],this.angle+Math.PI),this.lasers(this.vertices[2],this.angle-Math.PI/3),ctx.strokeStyle="#50f",ctx.lineWidth=1.5,ctx.setLineDash([70+300*Math.random(),55*Math.random()]),ctx.stroke(),ctx.setLineDash([]),ctx.lineWidth=20,ctx.strokeStyle="rgba(80,0,255,0.07)",ctx.stroke()}},s.lasers=function(t,e){const i=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}};best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const s={x:t.x+7e3*Math.cos(e),y:t.y+7e3*Math.sin(e)};if(i(t,s,map),i(t,s,body),m.isCloak||i(t,s,[playerBody,playerHead]),best.who&&(best.who===playerBody||best.who===playerHead)&&m.immuneCycle<m.cycle){m.immuneCycle=m.cycle+tech.collisionImmuneCycles+60;const t=.14*simulation.dmgScale;m.damage(t),simulation.drawList.push({x:best.x,y:best.y,radius:1500*t,color:"rgba(80,0,255,0.5)",time:20})}best.dist2===1/0&&(best=s),ctx.moveTo(t.x,t.y),ctx.lineTo(best.x,best.y)}},stabber(t,e,i=25+Math.ceil(12*Math.random()),s=9){i>80&&(i=65),mobs.spawn(t,e,6,i,"rgb(220,50,205)");let o=mob[mob.length-1];o.isVerticesChange=!0,o.accelMag=6e-4*simulation.accelScale,o.delay=360*simulation.CDScale,o.spikeVertex=0,o.spikeLength=0,o.isSpikeGrowing=!1,o.isSpikeReset=!0,o.collisionFilter.mask=cat.map|cat.body|cat.bullet|cat.player,Matter.Body.rotate(o,.1*Math.PI),spawn.shield(o,t,e),o.onDeath=function(){if(this.spikeLength>4){this.spikeLength=4;const t=Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex],this.position)),this.radius*this.spikeLength);this.vertices[this.spikeVertex].x=this.position.x+t.x,this.vertices[this.spikeVertex].y=this.position.y+t.y}},o.do=function(){if(!m.isBodiesAsleep)if(this.seePlayerByLookingAt(),this.checkStatus(),this.attraction(),this.isSpikeReset){if(this.seePlayer.recall){const t=Vector.sub(this.seePlayer.position,this.position);if(Vector.magnitude(t)<7*this.radius){let t=1/0;for(let e=0,i=this.vertices.length;e<i;e++){const i=Vector.sub(this.seePlayer.position,this.vertices[e]),s=Vector.magnitude(i);s<t&&(this.spikeVertex=e,t=s)}this.spikeLength=1,this.isSpikeGrowing=!0,this.isSpikeReset=!1,Matter.Body.setAngularVelocity(this,0)}}}else{this.isSpikeGrowing?(this.spikeLength+=1,this.spikeLength>s&&(this.isSpikeGrowing=!1)):(Matter.Body.setAngularVelocity(this,.8*this.angularVelocity),this.spikeLength-=.2,this.spikeLength<1&&(this.spikeLength=1,this.isSpikeReset=!0));const t=Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex],this.position)),this.radius*this.spikeLength);this.vertices[this.spikeVertex].x=this.position.x+t.x,this.vertices[this.spikeVertex].y=this.position.y+t.y}}},striker(t,e,i=14+Math.ceil(25*Math.random())){mobs.spawn(t,e,5,i,"rgb(221,102,119)");let s=mob[mob.length-1];s.accelMag=34e-5*simulation.accelScale,s.g=15e-5,s.frictionStatic=0,s.friction=0,s.delay=30+60*simulation.CDScale,s.cd=1/0,s.strikeRange=300,Matter.Body.rotate(s,.1*Math.PI),spawn.shield(s,t,e),s.onDamage=function(){this.cd=simulation.cycle+this.delay},s.do=function(){if(this.gravity(),simulation.cycle%this.seePlayerFreq||(this.distanceToPlayer2()<this.seeAtDistance2&&0===Matter.Query.ray(map,this.position,this.playerPosRandomY()).length&&!m.isCloak?(this.foundPlayer(),this.cd===1/0&&(this.cd=simulation.cycle+.7*this.delay)):this.seePlayer.recall&&(this.lostPlayer(),this.cd=1/0)),this.checkStatus(),this.attraction(),this.cd<simulation.cycle&&this.seePlayer.recall){const t=Vector.sub(this.seePlayer.position,this.position),e=Vector.magnitude(t);this.cd=simulation.cycle+this.delay,ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),e<400?Matter.Body.translate(this,Vector.mult(Vector.normalise(t),e-20-i)):Matter.Body.translate(this,Vector.mult(Vector.normalise(t),this.strikeRange)),ctx.lineTo(this.position.x,this.position.y),ctx.lineWidth=2.1*i,ctx.strokeStyle=this.fill,ctx.stroke(),Matter.Body.setVelocity(this,{x:.5*this.velocity.x,y:.5*this.velocity.y})}}},revolutionBoss(t,e,i=70){const s=9+Math.floor(Math.min(12,.2*simulation.difficulty)),o=[-1.8,0,0,.9,1.2],a=o[Math.floor(Math.random()*o.length)];mobs.spawn(t,e,s,i,"rgb(201,202,225)");let n=mob[mob.length-1];Matter.Body.rotate(n,2*Math.PI*Math.random()),n.accelMag=38e-5*Math.sqrt(simulation.accelScale),n.frictionAir=.01,n.swordRadiusMax=550+10*simulation.difficulty,n.laserAngle=0,n.swordDamage=.0025*simulation.dmgScale,Matter.Body.setDensity(n,.005),n.damageReduction=.1/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),n.isBoss=!0,n.onDamage=function(){},n.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},n.isInvulnerable=!1,n.isNextInvulnerability=.75,n.invulnerabilityCountDown=0,n.invulnerable=function(){if(this.health<this.isNextInvulnerability&&(this.isNextInvulnerability=Math.floor(4*this.health)/4,this.isInvulnerable=!0,this.startingDamageReduction=this.damageReduction,this.damageReduction=0,this.invulnerabilityCountDown=106),this.isInvulnerable)if(this.invulnerabilityCountDown>0){m.isBodiesAsleep||this.invulnerabilityCountDown--,ctx.beginPath();let t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y),ctx.lineWidth=20,ctx.strokeStyle="rgba(255,255,255,0.7)",ctx.stroke()}else this.isInvulnerable=!1,this.damageReduction=this.startingDamageReduction},n.do=function(){this.invulnerable(),this.checkStatus(),this.seePlayerByHistory(60),this.attraction(),m.isBodiesAsleep||(this.laserAngle+=this.isInvulnerable?.06:.015);for(let t=0,e=this.vertices.length;t<e;t++){const i=a*Math.cos(this.laserAngle+2*Math.PI*t/e),o=this.swordRadiusMax*Math.sin(this.laserAngle+2*Math.PI*t/e);o>0&&this.laserSword(this.vertices[t],i+this.angle+(t+.5)/s*2*Math.PI,Math.abs(o))}},n.laserSword=function(t,e,i){const s=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}};best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const o={x:t.x+i*Math.cos(e),y:t.y+i*Math.sin(e)};s(t,o,map),m.isCloak||s(t,o,[playerBody,playerHead]),best.who&&(best.who===playerBody||best.who===playerHead)&&m.immuneCycle<m.cycle&&(m.damage(this.swordDamage),simulation.drawList.push({x:best.x,y:best.y,radius:1500*this.swordDamage,color:"rgba(80,0,255,0.5)",time:20})),best.dist2===1/0&&(best=o),ctx.beginPath(),ctx.moveTo(t.x,t.y),ctx.lineTo(best.x,best.y),ctx.strokeStyle="rgba(100,100,255,0.1)",ctx.lineWidth=10,ctx.stroke(),ctx.strokeStyle="rgba(100,100,255,0.5)",ctx.lineWidth=2,ctx.setLineDash([70+300*Math.random(),55*Math.random()]),ctx.stroke(),ctx.setLineDash([])}},slasher(t,e,i=36+Math.ceil(25*Math.random())){mobs.spawn(t,e,5,i,"rgb(201,202,225)");let s=mob[mob.length-1];Matter.Body.rotate(s,2*Math.PI*Math.random()),s.accelMag=8e-4*simulation.accelScale,s.torqueMagnitude=2e-5*s.inertia*(Math.random()>.5?-1:1),s.frictionStatic=0,s.friction=0,s.frictionAir=.035,s.delay=120*simulation.CDScale,s.cd=0,s.swordRadius=0,s.swordVertex=1,s.swordRadiusMax=350+5*simulation.difficulty,s.swordRadiusGrowRate=s.swordRadiusMax*(.018+6e-4*simulation.difficulty),s.isSlashing=!1,s.swordDamage=.05*simulation.dmgScale,s.laserAngle=3*Math.PI/5;spawn.shield(s,t,e),s.onDamage=function(){},s.do=function(){this.checkStatus(),this.seePlayerByHistory(15),this.attraction(),m.isBodiesAsleep||this.sword()},s.swordWaiting=function(){if(this.seePlayer.recall&&this.cd<simulation.cycle&&this.distanceToPlayer2()<2e5&&0===Matter.Query.ray(map,this.position,this.playerPosRandomY()).length&&0===Matter.Query.ray(body,this.position,this.playerPosRandomY()).length){let t=0;for(let e=0,i=this.vertices.length;e<i;e++){const i=Vector.magnitudeSquared(Vector.sub({x:this.vertices[e].x,y:this.vertices[e].y},m.pos));i>t&&(t=i,this.swordVertex=e)}this.laserAngle=this.swordVertex/5*2*Math.PI+.6283,this.sword=this.swordGrow,this.accelMag=0}},s.sword=s.swordWaiting,s.swordGrow=function(){this.laserSword(this.vertices[this.swordVertex],this.angle+this.laserAngle),this.swordRadius+=this.swordRadiusGrowRate,this.swordRadius>this.swordRadiusMax&&(this.sword=this.swordSlash,this.spinCount=0)},s.swordSlash=function(){this.laserSword(this.vertices[this.swordVertex],this.angle+this.laserAngle),this.torque+=this.torqueMagnitude,this.spinCount++,this.spinCount>60&&(this.sword=this.swordWaiting,this.swordRadius=0,this.accelMag=.001*simulation.accelScale,this.cd=simulation.cycle+this.delay)},s.laserSword=function(t,e){const i=function(t,e,i){for(let s=0;s<i.length;++s){let o=i[s].vertices;const a=o.length-1;for(let n=0;n<a;n++)if(results=simulation.checkLineIntersection(t,e,o[n],o[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,l=e*e+a*a;l<best.dist2&&(!i[s].mob||i[s].alive)&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[n],v2:o[n+1]})}if(results=simulation.checkLineIntersection(t,e,o[0],o[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,l=e*e+n*n;l<best.dist2&&(best={x:results.x,y:results.y,dist2:l,who:i[s],v1:o[0],v2:o[a]})}}};best={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null};const s={x:t.x+this.swordRadius*Math.cos(e),y:t.y+this.swordRadius*Math.sin(e)};i(t,s,body),i(t,s,map),m.isCloak||i(t,s,[playerBody,playerHead]),best.who&&(best.who===playerBody||best.who===playerHead)&&m.immuneCycle<m.cycle&&(m.immuneCycle=m.cycle+tech.collisionImmuneCycles+60,m.damage(this.swordDamage),simulation.drawList.push({x:best.x,y:best.y,radius:1500*this.swordDamage,color:"rgba(80,0,255,0.5)",time:20})),best.dist2===1/0&&(best=s),ctx.beginPath(),ctx.moveTo(t.x,t.y),ctx.lineTo(best.x,best.y),ctx.strokeStyle="rgba(100,100,255,0.1)",ctx.lineWidth=15,ctx.stroke(),ctx.strokeStyle="rgba(100,100,255,0.5)",ctx.lineWidth=4,ctx.setLineDash([70+300*Math.random(),55*Math.random()]),ctx.stroke(),ctx.setLineDash([])}},sneaker(t,e,i=15+Math.ceil(10*Math.random())){mobs.spawn(t,e,5,i,"transparent");let s=mob[mob.length-1];Matter.Body.setDensity(s,.002),s.accelMag=.001*Math.sqrt(simulation.accelScale),s.frictionAir=.01,s.g=2e-4,s.stroke="transparent",s.alpha=1,s.canTouchPlayer=!1,s.collisionFilter.mask=cat.map|cat.body|cat.bullet|cat.mob,s.showHealthBar=!1,s.memory=240,s.do=function(){if(this.gravity(),this.seePlayerByHistory(15),this.checkStatus(),this.attraction(),m.isBodiesAsleep||(this.seePlayer.recall?this.alpha<1&&(this.alpha+=.003+.003/simulation.CDScale):this.alpha>0&&(this.alpha-=.03)),this.alpha>0){this.alpha>.7&&(this.healthBar(),this.canTouchPlayer||(this.canTouchPlayer=!0,this.collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet|cat.mob)),ctx.beginPath();const t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1,i=t.length;e<i;++e)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y),ctx.fillStyle=`rgba(0,0,0,${this.alpha*this.alpha})`,ctx.fill()}else this.canTouchPlayer&&(this.canTouchPlayer=!1,this.collisionFilter.mask=cat.map|cat.body|cat.bullet|cat.mob)}},ghoster(t,e,i=50+Math.ceil(90*Math.random())){mobs.spawn(t,e,7,i,"transparent");let s=mob[mob.length-1];s.seeAtDistance2=3e5,s.accelMag=13e-5*simulation.accelScale,map.length&&(s.searchTarget=map[Math.floor(Math.random()*(map.length-1))].position),s.stroke="transparent",s.alpha=1,s.canTouchPlayer=!1,s.collisionFilter.mask=cat.bullet,s.showHealthBar=!1,s.memory=480,s.do=function(){if(this.speed>5&&Matter.Body.setVelocity(this,{x:.8*this.velocity.x,y:.8*this.velocity.y}),this.seePlayerCheckByDistance(),this.checkStatus(),this.attraction(),this.search(),m.isBodiesAsleep||(this.distanceToPlayer2()<this.seeAtDistance2?this.alpha<1&&(this.alpha+=.005*simulation.CDScale):this.alpha>0&&(this.alpha-=.05)),this.alpha>0){this.alpha>.8&&this.seePlayer.recall&&(this.healthBar(),this.canTouchPlayer||(this.canTouchPlayer=!0,this.collisionFilter.mask=cat.player|cat.bullet)),ctx.beginPath();const t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1,i=t.length;e<i;++e)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y),ctx.lineWidth=1,ctx.fillStyle=`rgba(255,255,255,${this.alpha*this.alpha})`,ctx.fill()}else this.canTouchPlayer&&(this.canTouchPlayer=!1,this.collisionFilter.mask=cat.bullet)}},bomberBoss(t,e,i=88){mobs.spawn(t,e,3,i,"rgba(255,0,200,0.5)");let s=mob[mob.length-1];s.isBoss=!0,Matter.Body.setDensity(s,.0025+13e-5*Math.sqrt(simulation.difficulty)),s.stroke="transparent",s.seeAtDistance2=15e5,s.fireFreq=10+Math.floor(70*simulation.CDScale),s.searchTarget=map[Math.floor(Math.random()*(map.length-1))].position,s.hoverElevation=460+200*(Math.random()-.5),s.hoverXOff=100*(Math.random()-.5),s.accelMag=1e-5*Math.floor(10*(Math.random()+4.5))*simulation.accelScale,s.g=2e-4,s.frictionStatic=0,s.friction=0,s.frictionAir=.01,s.memory=1/0,s.collisionFilter.mask=cat.player|cat.bullet,spawn.shield(s,t,e,1);const o=Math.floor(Math.min(15,3+Math.sqrt(simulation.difficulty))),a=.007+.003*Math.random()+.004*Math.sqrt(simulation.difficulty);let n=i+125+350*Math.random();for(let t=0;t<o;t++)spawn.orbital(s,n,t/o*2*Math.PI,a);n=i+125+350*Math.random();for(let t=0;t<o;t++)spawn.orbital(s,n,t/o*2*Math.PI,-a);s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.damageReduction=.2/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){this.seePlayerCheckByDistance(),this.checkStatus(),this.seePlayer.recall&&(this.hoverOverPlayer(),this.bomb(),this.search())}},shooter(t,e,i=25+Math.ceil(50*Math.random())){mobs.spawn(t,e,3,i,"rgb(255,100,150)");let s=mob[mob.length-1];s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),s.isVerticesChange=!0,s.memory=120,s.fireFreq=.007+.005*Math.random(),s.noseLength=0,s.fireAngle=0,s.accelMag=5e-4*simulation.accelScale,s.frictionStatic=0,s.friction=0,s.frictionAir=.05,s.lookTorque=25e-7*(Math.random()>.5?-1:1),s.fireDir={x:0,y:0},s.onDeath=function(){},s.do=function(){this.seePlayerByLookingAt(),this.checkStatus(),this.fire()}},shooterBoss(t,e,i=110){mobs.spawn(t,e,3,i,"rgb(255,70,180)");let s=mob[mob.length-1];setTimeout((()=>{s.constraint=Constraint.create({pointA:{x:s.position.x,y:s.position.y},bodyB:s,stiffness:4e-5,damping:.1}),Composite.add(engine.world,s.constraint)}),2e3),s.isBoss=!0,s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),s.isVerticesChange=!0,s.memory=240,s.fireFreq=.025,s.noseLength=0,s.fireAngle=0,s.accelMag=.005*simulation.accelScale,s.frictionAir=.05,s.lookTorque=6e-6*(Math.random()>.5?-1:1),s.fireDir={x:0,y:0},setTimeout((()=>{spawn.spawnOrbitals(s,i+25,1),spawn.spawnOrbitals(s,i+75,1)}),100),Matter.Body.setDensity(s,.008+3e-4*Math.sqrt(simulation.difficulty)),s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){this.seePlayerByLookingAt(),this.checkStatus(),this.fire()}},bullet(t,e,i=9,s=0){mobs.spawn(t,e,s,i,"rgb(255,0,0)");let o=mob[mob.length-1];o.stroke="transparent",o.onHit=function(){this.explode(20*this.mass)},Matter.Body.setDensity(o,4e-5),o.timeLeft=200,o.g=.001,o.frictionAir=0,o.restitution=.8,o.leaveBody=!1,o.isDropPowerUp=!1,o.isBadTarget=!0,o.isMobBullet=!0,o.showHealthBar=!1,o.collisionFilter.category=cat.mobBullet,o.collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet,o.do=function(){this.gravity(),this.timeLimit()}},bomb(t,e,i=9,s=5){mobs.spawn(t,e,s,i,"rgb(255,0,0)");let o=mob[mob.length-1];o.stroke="transparent",o.onHit=function(){this.explode(120*this.mass)},o.onDeath=function(){spawn.bullet(this.position.x,this.position.y,this.radius/3,5),spawn.bullet(this.position.x,this.position.y,this.radius/3,5),spawn.bullet(this.position.x,this.position.y,this.radius/3,5);const t=Vector.rotate({x:1,y:1},2*Math.PI*Math.random()),e=Vector.rotate({x:1,y:1},2*Math.PI*Math.random()),i=Vector.normalise(Vector.add(t,e));Matter.Body.setVelocity(mob[mob.length-1],{x:8*t.x,y:8*t.y}),Matter.Body.setVelocity(mob[mob.length-2],{x:8*e.x,y:8*e.y}),Matter.Body.setVelocity(mob[mob.length-3],{x:-8*i.x,y:-8*i.y})},Matter.Body.setDensity(o,5e-5),o.timeLeft=140+Math.floor(30*Math.random()),o.g=.001,o.frictionAir=0,o.restitution=1,o.leaveBody=!1,o.isDropPowerUp=!1,o.isBadTarget=!0,o.isMobBullet=!0,o.showHealthBar=!1,o.collisionFilter.category=cat.mobBullet,o.collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet,o.do=function(){this.gravity(),this.timeLimit()}},sniper(t,e,i=35+Math.ceil(30*Math.random())){mobs.spawn(t,e,3,i,"transparent");let s=mob[mob.length-1];s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),s.isVerticesChange=!0,s.stroke="transparent",s.alpha=1,s.showHealthBar=!1,s.frictionStatic=0,s.friction=0,s.canTouchPlayer=!1,s.collisionFilter.mask=cat.map|cat.body|cat.bullet|cat.mob,s.memory=60,s.fireFreq=.006+.002*Math.random(),s.noseLength=0,s.fireAngle=0,s.accelMag=5e-4*simulation.accelScale,s.frictionAir=.05,s.torque=1e-4*s.inertia,s.fireDir={x:0,y:0},s.onDeath=function(){},s.do=function(){if(this.seePlayerCheck(),this.checkStatus(),!m.isBodiesAsleep){const t=()=>{const t=this.radius+this.radius*this.noseLength;this.vertices[1].x=this.position.x+Math.cos(this.angle)*t,this.vertices[1].y=this.position.y+Math.sin(this.angle)*t};if(this.seePlayer.recall){simulation.cycle%this.seePlayerFreq||(this.fireDir=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)));const e=this.angle+Math.PI/2,i=Vector.dot({x:Math.cos(e),y:Math.sin(e)},this.fireDir),s=.03;if(i>s)this.torque+=4e-6*this.inertia;else if(i<-s)this.torque-=4e-6*this.inertia;else if(this.noseLength>1.5&&i>-.2&&i<.2){spawn.sniperBullet(this.vertices[1].x,this.vertices[1].y,7+Math.ceil(this.radius/15),4);const t=10+15*simulation.accelScale;Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+this.fireDir.x*t+Math.random(),y:this.velocity.y+this.fireDir.y*t+Math.random()}),this.noseLength=0,this.force.x-=.005*this.fireDir.x*this.mass,this.force.y-=.005*this.fireDir.y*this.mass}this.noseLength<1.5&&(this.noseLength+=this.fireFreq),t()}else this.noseLength>.1&&(this.noseLength-=this.fireFreq/2,t());this.seePlayer.recall?this.alpha<1&&(this.alpha+=.01):this.alpha>0&&(this.alpha-=.03)}if(this.alpha>0){this.alpha>.95&&(this.healthBar(),this.canTouchPlayer||(this.canTouchPlayer=!0,this.collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet|cat.mob)),ctx.beginPath();const t=this.vertices;ctx.moveTo(t[0].x,t[0].y);for(let e=1,i=t.length;e<i;++e)ctx.lineTo(t[e].x,t[e].y);ctx.lineTo(t[0].x,t[0].y),ctx.fillStyle=`rgba(25,0,50,${this.alpha*this.alpha})`,ctx.fill()}else this.canTouchPlayer&&(this.canTouchPlayer=!1,this.collisionFilter.mask=cat.map|cat.body|cat.bullet|cat.mob)}},sniperBullet(t,e,i=9,s=4){mobs.spawn(t,e,s,i,"rgb(255,0,155)");let o=mob[mob.length-1];o.stroke="transparent",o.onHit=function(){this.explode(20*this.mass)},Matter.Body.setDensity(o,5e-5),o.timeLeft=120,o.frictionAir=0,o.restitution=0,o.leaveBody=!1,o.isDropPowerUp=!1,o.isBadTarget=!0,o.isMobBullet=!0,o.showHealthBar=!1,o.collisionFilter.category=cat.mobBullet,o.collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet,o.do=function(){this.timeLimit(),(Matter.Query.collides(this,map).length>0||Matter.Query.collides(this,body).length>0&&this.speed<3)&&(this.isDropPowerUp=!1,this.death())}},launcherOne(t,e,i=30+Math.ceil(40*Math.random())){mobs.spawn(t,e,3,i,"rgb(150,150,255)");let s=mob[mob.length-1];s.accelMag=4e-5*simulation.accelScale,s.fireFreq=Math.floor(420+90*Math.random()*simulation.CDScale),s.frictionStatic=0,s.friction=0,s.frictionAir=.015,spawn.shield(s,t,e),s.onDamage=function(){},s.do=function(){if(this.seePlayerCheck(),this.checkStatus(),this.attraction(),this.seePlayer.recall&&!(simulation.cycle%this.fireFreq)&&!m.isBodiesAsleep){Matter.Body.setAngularVelocity(this,.14),spawn.seeker(this.vertices[0].x,this.vertices[0].y,20,9);const t=mob[mob.length-1];Matter.Body.setDensity(t,3e-5),t.timeLeft=840,t.accelMag=35e-5*simulation.accelScale,t.frictionAir=.01;const e=Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position,this.vertices[0]))),-6);Matter.Body.setVelocity(t,{x:this.velocity.x+e.x,y:this.velocity.y+e.y})}}},launcher(t,e,i=30+Math.ceil(40*Math.random())){mobs.spawn(t,e,3,i,"rgb(150,150,255)");let s=mob[mob.length-1];s.accelMag=4e-5*simulation.accelScale,s.fireFreq=Math.floor(420+90*Math.random()*simulation.CDScale),s.frictionStatic=0,s.friction=0,s.frictionAir=.02,spawn.shield(s,t,e),s.onDamage=function(){},s.do=function(){if(this.seePlayerCheck(),this.checkStatus(),this.attraction(),this.seePlayer.recall&&!(simulation.cycle%this.fireFreq)&&!m.isBodiesAsleep){Matter.Body.setAngularVelocity(this,.14);for(let t=0,e=this.vertices.length;t<e;t++){spawn.seeker(this.vertices[t].x,this.vertices[t].y,7);const e=Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position,this.vertices[t]))),-8);Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+e.x,y:this.velocity.y+e.y})}}}},launcherBoss(t,e,i=90){mobs.spawn(t,e,6,i,"rgb(150,150,255)");let s=mob[mob.length-1];s.isBoss=!0,s.accelMag=1e-4*simulation.accelScale,s.fireFreq=Math.floor(330*simulation.CDScale),s.frictionStatic=0,s.friction=0,s.frictionAir=.02,s.memory=420,s.repulsionRange=1e6,spawn.shield(s,t,e,1),spawn.spawnOrbitals(s,i+50+200*Math.random()),Matter.Body.setDensity(s,.0022+2e-4*Math.sqrt(simulation.difficulty)),s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.onDamage=function(){},s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){if(this.seePlayerCheck(),this.checkStatus(),this.attraction(),this.repulsion(),this.seePlayer.recall&&!(simulation.cycle%this.fireFreq)&&!m.isBodiesAsleep){Matter.Body.setAngularVelocity(this,.11);for(let t=0,e=this.vertices.length;t<e;t++){spawn.seeker(this.vertices[t].x,this.vertices[t].y,8);const e=Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position,this.vertices[t]))),-10);Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+e.x,y:this.velocity.y+e.y})}}}},grenadierBoss(t,e,i=95){mobs.spawn(t,e,6,i,"rgb(0,235,255)");let s=mob[mob.length-1];s.isBoss=!0,s.accelMag=1e-4*simulation.accelScale,s.fireFreq=Math.floor(360*simulation.CDScale),s.frictionStatic=0,s.friction=0,s.frictionAir=.035,s.memory=420,s.repulsionRange=12e5,spawn.spawnOrbitals(s,i+50,1),spawn.spawnOrbitals(s,i+125,1),spawn.spawnOrbitals(s,i+200,1),Matter.Body.setDensity(s,.004+2e-4*Math.sqrt(simulation.difficulty)),s.onDeath=function(){for(let t=0;t<6;t++){spawn.grenade(this.position.x,this.position.y,75*simulation.CDScale);const e=mob[mob.length-1],i=4*simulation.accelScale,s=2*Math.PI*t/6;Matter.Body.setVelocity(e,{x:i*Math.cos(s),y:i*Math.sin(s)})}powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.grenadeLimiter=0,s.onDamage=function(){if(this.grenadeLimiter<240){this.grenadeLimiter+=60,spawn.grenade(this.position.x,this.position.y,80+Math.floor(60*Math.random()));const t=mob[mob.length-1],e=Vector.mult(Vector.normalise(Vector.sub(player.position,t.position)),3*Math.sqrt(simulation.accelScale)+4*Math.random());Matter.Body.setVelocity(t,{x:this.velocity.x+e.x,y:this.velocity.y+e.y})}},s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){this.grenadeLimiter>1&&this.grenadeLimiter--,this.seePlayerCheck(),this.checkStatus(),this.attraction()}},grenadier(t,e,i=35+Math.ceil(20*Math.random())){mobs.spawn(t,e,3,i,"rgb(0,235,255)");let s=mob[mob.length-1];s.vertices=Matter.Vertices.rotate(s.vertices,Math.PI,s.position),s.isVerticesChange=!0,s.frictionStatic=0,s.friction=0,s.memory=60,s.fireFreq=.0055+.0015*Math.random(),s.noseLength=0,s.fireAngle=0,s.accelMag=6e-4*simulation.accelScale,s.frictionAir=.05,s.torque=1e-4*s.inertia*(Math.random()>.5?-1:1),s.fireDir={x:0,y:0},s.onDeath=function(){spawn.grenade(this.position.x,this.position.y,75*simulation.CDScale),mob[mob.length-1].collisionFilter.mask=cat.player|cat.map},s.do=function(){if(this.seePlayerCheck(),this.checkStatus(),!m.isBodiesAsleep){const t=()=>{const t=this.radius+this.radius*this.noseLength;this.vertices[1].x=this.position.x+Math.cos(this.angle)*t,this.vertices[1].y=this.position.y+Math.sin(this.angle)*t};if(this.seePlayer.recall){simulation.cycle%this.seePlayerFreq||(this.fireDir=Vector.normalise(Vector.sub(this.seePlayer.position,this.position)));const e=this.angle+Math.PI/2,i=Vector.dot({x:Math.cos(e),y:Math.sin(e)},this.fireDir),s=.03;if(i>s)this.torque+=4e-6*this.inertia;else if(i<-s)this.torque-=4e-6*this.inertia;else if(this.noseLength>1.5&&i>-.2&&i<.2){spawn.grenade(this.vertices[1].x,this.vertices[1].y);const t=5*simulation.accelScale;Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+this.fireDir.x*t+Math.random(),y:this.velocity.y+this.fireDir.y*t+Math.random()}),this.noseLength=0,this.force.x-=.005*this.fireDir.x*this.mass,this.force.y-=.005*this.fireDir.y*this.mass}this.noseLength<1.5&&(this.noseLength+=this.fireFreq),t()}else this.noseLength>.1&&(this.noseLength-=this.fireFreq/2,t())}}},grenade(t,e,i=90+Math.ceil(60/simulation.accelScale),s=Math.min(550,250+3*simulation.difficulty),o=3){mobs.spawn(t,e,4,o,"rgb(215,0,190)");let a=mob[mob.length-1];a.stroke="transparent",a.onHit=function(){this.explode(20*this.mass)},Matter.Body.setDensity(a,4e-5),a.lifeSpan=i,a.timeLeft=a.lifeSpan,a.frictionAir=0,a.restitution=.8,a.leaveBody=!1,a.isDropPowerUp=!1,a.isBadTarget=!0,a.isMobBullet=!0,a.onDeath=function(){Vector.magnitude(Vector.sub(player.position,this.position))<s&&m.immuneCycle<m.cycle&&(m.immuneCycle=m.cycle+tech.collisionImmuneCycles,m.damage(.02*simulation.dmgScale)),simulation.drawList.push({x:this.position.x,y:this.position.y,radius:s,color:"rgba(255,0,220,0.3)",time:simulation.drawTime})},a.showHealthBar=!1,a.collisionFilter.category=cat.mobBullet,a.collisionFilter.mask=cat.map|cat.body|cat.player,a.do=function(){this.timeLimit(),ctx.beginPath(),ctx.arc(this.position.x,this.position.y,s*(1.01-this.timeLeft/this.lifeSpan),0,2*Math.PI),ctx.fillStyle="rgba(255,0,220,0.05)",ctx.fill()}},shieldingBoss(t,e,i=200){mobs.spawn(t,e,9,i,"rgb(150, 150, 255)");let s=mob[mob.length-1];setTimeout((()=>{s.constraint=Constraint.create({pointA:{x:s.position.x,y:s.position.y},bodyB:s,stiffness:1e-4,damping:1}),Composite.add(engine.world,s.constraint)}),2e3),Matter.Body.rotate(s,2*Math.random()*Math.PI),s.isBoss=!0,s.cycle=0,s.maxCycles=110,s.frictionStatic=0,s.friction=0,s.frictionAir=.5,spawn.shield(s,t,e,1),spawn.spawnOrbitals(s,i+50+200*Math.random()),Matter.Body.setDensity(s,.0045),s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.onDamage=function(){this.cycle=0},s.damageReduction=.35/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){this.checkStatus(),ctx.beginPath(),ctx.moveTo(this.vertices[this.vertices.length-1].x,this.vertices[this.vertices.length-1].y);const t=(this.vertices.length+1)*this.cycle/this.maxCycles;t>1&&ctx.lineTo(this.vertices[0].x,this.vertices[0].y);for(let e=1;e<t-1;e++)ctx.lineTo(this.vertices[e].x,this.vertices[e].y);if(ctx.lineWidth=5,ctx.strokeStyle="rgb(255,255,255)",ctx.stroke(),!m.isBodiesAsleep&&(this.cycle++,this.cycle>this.maxCycles)){this.cycle=0,ctx.beginPath();for(let t=0;t<mob.length;t++)mob[t].isShielded||mob[t].shield||!mob[t].isDropPowerUp||!mob[t].alive||mob[t].isBoss||(ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(mob[t].position.x,mob[t].position.y),spawn.shield(mob[t],mob[t].position.x,mob[t].position.y,1,!0),mob[mob.length-1].damageReduction=.0375/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1));!this.isShielded&&this.alive&&spawn.shield(this,this.position.x,this.position.y,1,!0),ctx.lineWidth=20,ctx.strokeStyle="rgb(200,200,255)",ctx.stroke()}}},streamBoss(t,e,i=110){mobs.spawn(t,e,5,i,"rgb(245,180,255)");let s=mob[mob.length-1];s.isBoss=!0,s.accelMag=8e-5*simulation.accelScale,s.canFire=!1,s.closestVertex1=0,s.closestVertex2=1,s.cycle=0,s.frictionStatic=0,s.friction=0,s.frictionAir=.022,s.memory=240,s.repulsionRange=12e5,spawn.shield(s,t,e,1),spawn.spawnOrbitals(s,i+50+200*Math.random()),Matter.Body.setDensity(s,.01),s.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},s.onDamage=function(){},s.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.do=function(){if(this.seePlayerCheck(),this.checkStatus(),this.attraction(),this.repulsion(),this.cycle++,this.seePlayer.recall&&this.cycle%15==0&&!m.isBodiesAsleep)if(this.canFire){this.cycle>120&&(this.cycle=0,this.canFire=!1),spawn.seeker(this.vertices[this.closestVertex1].x,this.vertices[this.closestVertex1].y,6),Matter.Body.setDensity(mob[mob.length-1],1e-6);const t=Vector.mult(Vector.normalise(Vector.sub(this.position,this.vertices[this.closestVertex1])),-10);Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+t.x,y:this.velocity.y+t.y}),spawn.seeker(this.vertices[this.closestVertex2].x,this.vertices[this.closestVertex2].y,6),Matter.Body.setDensity(mob[mob.length-1],1e-6);const e=Vector.mult(Vector.normalise(Vector.sub(this.position,this.vertices[this.closestVertex2])),-10);Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+e.x,y:this.velocity.y+e.y})}else if(this.cycle>210){this.cycle=0,this.canFire=!0;let t=1/0;for(let e=0;e<this.vertices.length;e++){const i=Vector.magnitudeSquared(Vector.sub(this.vertices[e],player.position));i<t&&(t=i,this.closestVertex2=this.closestVertex1,this.closestVertex1=e)}this.closestVertex2===this.closestVertex1&&(this.closestVertex2++,this.closestVertex2===this.vertices.length&&(this.closestVertex2=0))}}},seeker(t,e,i=8,s=6){mobs.spawn(t,e,s,i,"rgb(255,0,255)");let o=mob[mob.length-1];o.stroke="transparent",o.onHit=function(){this.explode(20*this.mass)},Matter.Body.setDensity(o,15e-6),o.timeLeft=420,o.accelMag=17e-5*simulation.accelScale,o.frictionAir=.01,o.restitution=.5,o.leaveBody=!1,o.isDropPowerUp=!1,o.isBadTarget=!0,o.isMobBullet=!0,o.showHealthBar=!1,o.collisionFilter.category=cat.mobBullet,o.collisionFilter.mask=cat.player|cat.map|cat.body|cat.bullet,o.do=function(){this.alwaysSeePlayer(),this.attraction(),this.timeLimit()}},spawner(t,e,i=55+Math.ceil(50*Math.random())){mobs.spawn(t,e,4,i,"rgb(255,150,0)");let s=mob[mob.length-1];s.g=4e-4,s.leaveBody=!1,s.onDeath=function(){for(let t=0;t<Math.ceil(.15*this.mass+2.5*Math.random());++t)spawn.spawns(this.position.x+(Math.random()-.5)*i*2.5,this.position.y+(Math.random()-.5)*i*2.5),Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+15*(Math.random()-.5),y:this.velocity.x+15*(Math.random()-.5)})},spawn.shield(s,t,e),s.do=function(){this.gravity(),this.seePlayerCheck(),this.checkStatus(),this.attraction()}},spawns(t,e,i=15){mobs.spawn(t,e,4,i,"rgb(255,0,0)");let s=mob[mob.length-1];s.onHit=function(){this.explode()},s.collisionFilter.mask=cat.player|cat.bullet|cat.body|cat.map|cat.mob,s.showHealthBar=!1,Matter.Body.setDensity(s,1e-4),s.g=2e-5,s.accelMag=12e-5*simulation.accelScale,s.isDropPowerUp=!1,s.leaveBody=!1,s.seePlayerFreq=Math.floor(80+50*Math.random()),s.frictionAir=.004,s.do=function(){this.gravity(),this.seePlayerCheck(),this.checkStatus(),this.attraction()}},exploder(t,e,i=40+Math.ceil(50*Math.random())){mobs.spawn(t,e,4,i,"rgb(255,0,0)");let s=mob[mob.length-1];s.onHit=function(){this.explode()},s.g=4e-4,s.do=function(){this.gravity(),this.seePlayerCheck(),this.checkStatus(),this.attraction()}},snakeSpitBoss(t,e,i=50){const s=Math.min(8+Math.ceil(.5*simulation.difficulty),40);let o=Math.PI,a=300;const n="rgb(235,180,255)";mobs.spawn(t+a*Math.cos(o),e+a*Math.sin(o),8,i,n);let l=mob[mob.length-1];l.isBoss=!0,l.accelMag=1e-4+2e-4*Math.sqrt(simulation.accelScale),l.memory=250,l.laserRange=500,Matter.Body.setDensity(l,.0022+22e-5*Math.sqrt(simulation.difficulty)),l.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y);for(let t=0;t<mob.length;t++)mob[t].isSnakeTail&&mob[t].alive&&(mob[t].isSnakeTail=!1,mob[t].do=mob[t].doActive)},l.canFire=!1,l.closestVertex1=0,l.cycle=0,l.damageReduction=.2/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),l.do=function(){if(this.seePlayerByHistory(),this.checkStatus(),this.attraction(),this.cycle++,this.seePlayer.recall&&this.cycle%10==0&&!m.isBodiesAsleep)if(this.canFire){this.cycle>120&&(this.cycle=0,this.canFire=!1),spawn.seeker(this.vertices[this.closestVertex1].x,this.vertices[this.closestVertex1].y,6),Matter.Body.setDensity(mob[mob.length-1],1e-6);const t=Vector.mult(Vector.normalise(Vector.sub(this.position,this.vertices[this.closestVertex1])),-10);Matter.Body.setVelocity(mob[mob.length-1],{x:this.velocity.x+t.x,y:this.velocity.y+t.y})}else if(this.cycle>210){this.cycle=0,this.canFire=!0;let t=1/0;for(let e=0;e<this.vertices.length;e++){const i=Vector.magnitudeSquared(Vector.sub(this.vertices[e],player.position));i<t&&(t=i,this.closestVertex1=e)}}},o-=.1,a-=10;for(let i=0;i<s;++i)o-=.15+.008*i,a-=5,spawn.snakeBody(t+a*Math.cos(o),e+a*Math.sin(o),20);this.constrain2AdjacentMobs(s,.06*Math.random()+.01);for(let t=mob.length-1,e=t-s;t>e;t--)mob[t].fill=t%2?"#778":n;consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-s],bodyB:mob[mob.length-1-s],stiffness:.05}),Composite.add(engine.world,consBB[consBB.length-1]),consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-s+1],bodyB:mob[mob.length-1-s],stiffness:.05}),Composite.add(engine.world,consBB[consBB.length-1]),consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-s+2],bodyB:mob[mob.length-1-s],stiffness:.05}),Composite.add(engine.world,consBB[consBB.length-1])},snakeBoss(t,e,i=50){const s=Math.min(8+Math.ceil(.5*simulation.difficulty),40);let o=Math.PI,a=300;const n="#f27";mobs.spawn(t+a*Math.cos(o),e+a*Math.sin(o),8,i,n);let l=mob[mob.length-1];l.isBoss=!0,l.accelMag=77e-5*simulation.accelScale,l.memory=250,l.laserRange=500,Matter.Body.setDensity(l,.00165+11e-5*Math.sqrt(simulation.difficulty)),l.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y);for(let t=0;t<mob.length;t++)mob[t].isSnakeTail&&mob[t].alive&&(mob[t].isSnakeTail=!1,mob[t].do=mob[t].doActive)},l.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),l.do=function(){this.seePlayerByHistory(),this.checkStatus(),this.attraction(),this.harmZone()},o-=.1,a-=10;for(let i=0;i<s;++i)o-=.15+.008*i,a-=5,spawn.snakeBody(t+a*Math.cos(o),e+a*Math.sin(o),20);this.constrain2AdjacentMobs(s,.06*Math.random()+.01);for(let t=mob.length-1,e=t-s;t>e;t--)mob[t].fill=t%2?"#333":n;consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-s],bodyB:mob[mob.length-1-s],stiffness:.05}),Composite.add(engine.world,consBB[consBB.length-1]),consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-s+1],bodyB:mob[mob.length-1-s],stiffness:.05}),Composite.add(engine.world,consBB[consBB.length-1]),consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-s+2],bodyB:mob[mob.length-1-s],stiffness:.05}),Composite.add(engine.world,consBB[consBB.length-1])},snakeBody(t,e,i=10){mobs.spawn(t,e,8,i,"rgba(0,180,180,0.4)");let s=mob[mob.length-1];s.collisionFilter.mask=cat.bullet|cat.player|cat.mob,s.accelMag=6e-4*simulation.accelScale,s.leaveBody=!1,s.showHealthBar=!1,s.isDropPowerUp=!1,s.frictionAir=.015,s.isSnakeTail=!0,s.stroke="transparent",s.onDeath=function(){},s.do=function(){this.checkStatus()},s.doActive=function(){this.checkStatus(),this.alwaysSeePlayer(),this.attraction()}},tetherBoss(t,e,i,s=90){mobs.spawn(t,e,8,s,"rgb(0,60,80)");let o=mob[mob.length-1];o.isBoss=!0,o.g=1e-4,o.accelMag=.002*simulation.accelScale,o.memory=20,Matter.Body.setDensity(o,5e-4+2e-4*Math.sqrt(simulation.difficulty)),cons[cons.length]=Constraint.create({pointA:{x:i.x,y:i.y},bodyB:o,stiffness:12e-5}),Composite.add(engine.world,cons[cons.length-1]),spawn.shield(o,t,e,1),setTimeout((()=>{spawn.spawnOrbitals(o,s+50+200*Math.random())}),100),o.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y),this.removeCons()},o.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),o.do=function(){this.gravity(),this.seePlayerCheck(),this.checkStatus(),this.attraction()}},shield(t,e,i,s=Math.min(.02+.005*simulation.difficulty,.2)+tech.duplicationChance(),o=!1){if(this.allowShields&&Math.random()<s){mobs.spawn(e,i,9,t.radius+30,"rgba(220,220,255,0.9)");let s=mob[mob.length-1];s.stroke="rgb(220,220,255)",Matter.Body.setDensity(s,1e-5),s.shield=!0,s.damageReduction=.075/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),s.isUnblockable=!0,s.isExtraShield=o,s.collisionFilter.category=cat.mobShield,s.collisionFilter.mask=cat.bullet,consBB[consBB.length]=Constraint.create({bodyA:s,bodyB:t,stiffness:.4,damping:.1}),Composite.add(engine.world,consBB[consBB.length-1]),s.onDamage=function(){this.alertNearByMobs(),this.fill=`rgba(220,220,255,${.3+.6*this.health})`},s.leaveBody=!1,s.isDropPowerUp=!1,s.showHealthBar=!1,s.shieldTargetID=t.id,t.isShielded=!0,s.onDeath=function(){for(let t=0,e=mob.length;t<e;t++)mob[t].id===this.shieldTargetID&&(mob[t].isShielded=!1)},s.do=function(){this.checkStatus()},mob.unshift(s)}},groupShield(t,e,i,s,o=.4){const a=t.length;mobs.spawn(e,i,9,s,"rgba(220,220,255,0.9)");let n=mob[mob.length-1];n.stroke="rgb(220,220,255)",Matter.Body.setDensity(n,1e-5),n.frictionAir=0,n.shield=!0,n.damageReduction=.075/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),n.collisionFilter.category=cat.mobShield,n.collisionFilter.mask=cat.bullet;for(let t=0;t<a;++t)mob[mob.length-t-2].isShielded=!0,consBB[consBB.length]=Constraint.create({bodyA:n,bodyB:mob[mob.length-t-2],stiffness:o,damping:.1}),Composite.add(engine.world,consBB[consBB.length-1]);n.onDamage=function(){this.alertNearByMobs(),this.fill=`rgba(220,220,255,${.3+.6*this.health})`},n.onDeath=function(){for(let e=0;e<t.length;e++)for(let i=0,s=mob.length;i<s;i++)mob[i].id===t[e]&&(mob[i].isShielded=!1)},n.leaveBody=!1,n.isDropPowerUp=!1,n.showHealthBar=!1,mob[mob.length-1]=mob[mob.length-1-a],mob[mob.length-1-a]=n,n.do=function(){this.checkStatus()}},spawnOrbitals(t,e,i=Math.min(.25+.005*simulation.difficulty)){if(Math.random()<i){const i=Math.floor(Math.min(15,3+Math.sqrt(simulation.difficulty))),s=(.007+.003*Math.random()+.004*Math.sqrt(simulation.difficulty))*(Math.random()<.5?1:-1);for(let o=0;o<i;o++)spawn.orbital(t,e,o/i*2*Math.PI,s)}},orbital(t,e,i,s){mobs.spawn(t.position.x,t.position.y,8,12,"rgb(255,0,150)");let o=mob[mob.length-1];o.stroke="transparent",Matter.Body.setDensity(o,.1),o.leaveBody=!1,o.isDropPowerUp=!1,o.isBadTarget=!0,o.isUnblockable=!0,o.showHealthBar=!1,o.isOrbital=!0,o.collisionFilter.category=cat.mobBullet,o.collisionFilter.mask=cat.bullet,o.do=function(){if(!t||!t.alive)return void this.death();const o=simulation.cycle*s+i,a={x:Math.cos(o),y:Math.sin(o)};if(Matter.Body.setPosition(this,Vector.add(t.position,Vector.mult(a,e))),Matter.Query.collides(this,[player]).length>0&&(!m.isCloak||!tech.isIntangible)&&m.immuneCycle<m.cycle){m.immuneCycle=m.cycle+tech.collisionImmuneCycles;const t=.035*simulation.dmgScale;m.damage(t),simulation.drawList.push({x:this.position.x,y:this.position.y,radius:500*t,color:simulation.mobDmgColor,time:simulation.drawTime}),this.death()}}},orbitalBoss(t,e,i=88){const s=Math.random(),o=Math.min(15,Math.floor(2+4*s+.75*Math.sqrt(simulation.difficulty)));mobs.spawn(t,e,o,i,"rgb(255,0,150)");let a=mob[mob.length-1];a.isBoss=!0,Matter.Body.setDensity(a,.0017+2e-4*Math.sqrt(simulation.difficulty)),a.stroke="transparent",a.seeAtDistance2=2e6,a.memory=1/0,a.frictionAir=.04,a.accelMag=3e-4*simulation.accelScale,a.collisionFilter.mask=cat.player|cat.bullet,spawn.shield(a,t,e,1);const n=Math.random();let l=(.009+.0011*Math.sqrt(simulation.difficulty))*(Math.random()<.5?1:-1),r=i+400+200*n+7*o;for(let t=0;t<o;t++)spawn.orbital(a,r,t/o*2*Math.PI,l);const c=[];for(let t=0;t<o;t++)c.push(mob.length-1-t);r=Math.max(60,100+100*Math.random()-3*o-80*n),l*=1.25+2*Math.random();const h=Math.max(2,Math.floor(6-5*s+.5*Math.sqrt(simulation.difficulty)));for(let t=0;t<o;t++)for(let e=0,i=h;e<i;e++)spawn.orbital(mob[c[t]],r,e/i*2*Math.PI,l);a.onDeath=function(){powerUps.spawnBossPowerUp(this.position.x,this.position.y)},a.damageReduction=.25/(tech.isScaleMobsWithDuplication?1+tech.duplicationChance():1),a.do=function(){this.seePlayerCheckByDistance(),this.checkStatus(),this.attraction()}},allowShields:!0,nodeGroup(t,e,i="striker",s=Math.min(2+Math.ceil(Math.random()*(simulation.difficulty+2)),8),o=Math.ceil(10*Math.random())+18,a=Math.ceil(100*Math.random())+70,n=.03*Math.random()+.005){this.allowShields=!1;const l=2*Math.PI/s;let r=[];for(let n=0;n<s;++n){let s=i;"random"===i?s=this.fullPickList[Math.floor(Math.random()*this.fullPickList.length)]:"randomList"===i&&(s=this.pickList[Math.floor(Math.random()*this.pickList.length)]),this[s](t+a*Math.sin(n*l),e+a*Math.cos(n*l),o),r.push(mob[mob.length-1].id)}Math.random()<.3?this.constrain2AdjacentMobs(s,2*n,!0):this.constrainAllMobCombos(s,n),s>2&&Math.random()<.998&&this.groupShield(r,t,e,a+2.5*o+6*s-25),this.allowShields=!0},lineGroup(t,e,i="striker",s=Math.min(3+Math.ceil(Math.random()*simulation.difficulty+2),8),o=Math.ceil(10*Math.random())+17,a=Math.ceil(80*Math.random())+30,n=.06*Math.random()+.01){this.allowShields=!1;for(let n=0;n<s;++n){let s=i;"random"===i?s=this.fullPickList[Math.floor(Math.random()*this.fullPickList.length)]:"randomList"===i&&(s=this.pickList[Math.floor(Math.random()*this.pickList.length)]),this[s](t+n*o+n*a,e,o)}this.constrain2AdjacentMobs(s,n),this.allowShields=!0},constrainAllMobCombos(t,e){for(let i=1;i<t+1;++i)for(let s=i+1;s<t+1;++s)consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-i],bodyB:mob[mob.length-s],stiffness:e}),Composite.add(engine.world,consBB[consBB.length-1])},constrain2AdjacentMobs(t,e,i=!1){for(let i=0;i<t-1;++i)consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-i-1],bodyB:mob[mob.length-i-2],stiffness:e}),Composite.add(engine.world,consBB[consBB.length-1]);if(t>2)for(let i=0;i<t-2;++i)consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-i-1],bodyB:mob[mob.length-i-3],stiffness:e}),Composite.add(engine.world,consBB[consBB.length-1]);i&&t>3&&(consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-1],bodyB:mob[mob.length-t],stiffness:e}),Composite.add(engine.world,consBB[consBB.length-1]),consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-2],bodyB:mob[mob.length-t],stiffness:e}),Composite.add(engine.world,consBB[consBB.length-1]),consBB[consBB.length]=Constraint.create({bodyA:mob[mob.length-1],bodyB:mob[mob.length-t+1],stiffness:e}),Composite.add(engine.world,consBB[consBB.length-1]))},constraintPB(t,e,i,s){cons[cons.length]=Constraint.create({pointA:{x:t,y:e},bodyB:body[i],stiffness:s}),Composite.add(engine.world,cons[cons.length-1])},constraintBB(t,e,i){consBB[consBB.length]=Constraint.create({bodyA:body[t],bodyB:body[e],stiffness:i}),Composite.add(engine.world,consBB[consBB.length-1])},wireHead(){const t=1300;mobs.spawn(t,-100,0,7.5,"transparent");let e=mob[mob.length-1];e.collisionFilter.category=cat.body,e.collisionFilter.mask=cat.map,e.inertia=1/0,e.g=4e-4,e.restitution=0,e.stroke="transparent",e.freeOfWires=!1,e.frictionStatic=1,e.friction=1,e.frictionAir=.01,e.isDropPowerUp=!1,e.showHealthBar=!1,e.isBadTarget=!0,e.isUnblockable=!0,e.do=function(){if(this.freeOfWires)this.gravity();else{if(m.pos.x>t&&(this.freeOfWires=!0,this.fill="#000",this.force.x+=-.003,player.force.x+=.06),Matter.Body.setVelocity(player,{x:player.velocity.x,y:player.velocity.y+.3}),m.pos.x>700&&player.velocity.x>-2){let e=.75*Math.min(.6,Math.max(0,100/(t-m.pos.x)));m.onGround||(e*=3),Matter.Body.setVelocity(player,{x:player.velocity.x-e,y:player.velocity.y})}Matter.Body.setPosition(this,{x:m.pos.x+42*Math.cos(m.angle+Math.PI),y:m.pos.y+42*Math.sin(m.angle+Math.PI)})}ctx.beginPath(),ctx.moveTo(-50,-1e3),ctx.quadraticCurveTo(-50,0,this.position.x,this.position.y),this.freeOfWires||ctx.lineTo(m.pos.x+30*Math.cos(m.angle+Math.PI),m.pos.y+30*Math.sin(m.angle+Math.PI)),ctx.lineCap="butt",ctx.lineWidth=15,ctx.strokeStyle="#000",ctx.stroke(),ctx.lineCap="round"}},wireKnee(){mobs.spawn(1425,-100,0,2,"transparent");let t=mob[mob.length-1];t.collisionFilter.category=cat.body,t.collisionFilter.mask=cat.map,t.g=3e-4,t.stroke="transparent",t.restitution=0,t.freeOfWires=!1,t.frictionStatic=1,t.friction=1,t.frictionAir=.01,t.isDropPowerUp=!1,t.showHealthBar=!1,t.isBadTarget=!0,t.isUnblockable=!0,t.do=function(){this.freeOfWires?this.gravity():(m.pos.x>1425&&(this.freeOfWires=!0,this.force.x-=4e-4,this.fill="#222"),m.calcLeg(0,0),Matter.Body.setPosition(this,{x:m.pos.x+m.flipLegs*m.knee.x-5,y:m.pos.y+m.knee.y})),ctx.beginPath(),ctx.moveTo(-70,-1e3),ctx.quadraticCurveTo(-70,0,this.position.x,this.position.y),ctx.lineWidth=5,ctx.strokeStyle="#222",ctx.lineCap="butt",ctx.stroke(),ctx.lineCap="round"}},wireKneeLeft(){mobs.spawn(1400,-100,0,2,"transparent");let t=mob[mob.length-1];t.collisionFilter.category=cat.body,t.collisionFilter.mask=cat.map,t.g=3e-4,t.stroke="transparent",t.restitution=0,t.freeOfWires=!1,t.frictionStatic=1,t.friction=1,t.frictionAir=.01,t.isDropPowerUp=!1,t.showHealthBar=!1,t.isBadTarget=!0,t.isUnblockable=!0,t.do=function(){this.freeOfWires?this.gravity():(m.pos.x>1400&&(this.freeOfWires=!0,this.force.x+=-3e-4,this.fill="#333"),m.calcLeg(Math.PI,-3),Matter.Body.setPosition(this,{x:m.pos.x+m.flipLegs*m.knee.x-5,y:m.pos.y+m.knee.y})),ctx.beginPath(),ctx.moveTo(-85,-1e3),ctx.quadraticCurveTo(-85,0,this.position.x,this.position.y),ctx.lineWidth=5,ctx.lineCap="butt",ctx.strokeStyle="#333",ctx.stroke(),ctx.lineCap="round"}},wireFoot(){mobs.spawn(1350,-100,0,2,"transparent");let t=mob[mob.length-1];t.collisionFilter.category=cat.body,t.collisionFilter.mask=cat.map,t.g=3e-4,t.restitution=0,t.stroke="transparent",t.freeOfWires=!1,t.frictionAir=.01,t.isDropPowerUp=!1,t.showHealthBar=!1,t.isBadTarget=!0,t.isUnblockable=!0,t.do=function(){this.freeOfWires?this.gravity():(m.pos.x>1350&&(this.freeOfWires=!0,this.force.x+=-6e-4,this.fill="#111"),m.calcLeg(0,0),Matter.Body.setPosition(this,{x:m.pos.x+m.flipLegs*m.foot.x-5,y:m.pos.y+m.foot.y-1})),ctx.beginPath(),ctx.moveTo(-34,-1e3),ctx.quadraticCurveTo(-34,0,this.position.x,this.position.y),ctx.lineWidth=5,ctx.lineCap="butt",ctx.strokeStyle="#111",ctx.stroke(),ctx.lineCap="round"}},wireFootLeft(){mobs.spawn(1325,-100,0,2,"transparent");let t=mob[mob.length-1];t.collisionFilter.category=cat.body,t.collisionFilter.mask=cat.map,t.g=3e-4,t.restitution=0,t.stroke="transparent",t.freeOfWires=!1,t.frictionAir=.01,t.isDropPowerUp=!1,t.showHealthBar=!1,t.isBadTarget=!0,t.isUnblockable=!0,t.do=function(){this.freeOfWires?this.gravity():(m.pos.x>1325&&(this.freeOfWires=!0,this.force.x+=-5e-4,this.fill="#222"),m.calcLeg(Math.PI,-3),Matter.Body.setPosition(this,{x:m.pos.x+m.flipLegs*m.foot.x-5,y:m.pos.y+m.foot.y-1})),ctx.beginPath(),ctx.moveTo(-24,-1e3),ctx.quadraticCurveTo(-24,0,this.position.x,this.position.y),ctx.lineWidth=5,ctx.strokeStyle="#222",ctx.lineCap="butt",ctx.stroke(),ctx.lineCap="round"}},boost(t,e,i=1e3){spawn.mapVertex(t+50,e+35,"120 40 -120 40 -50 -40 50 -40"),level.addQueryRegion(t,e-20,100,20,"boost",[[player],body,mob,powerUp,bullet],-1.21*Math.sqrt(Math.abs(i)))},blockDoor(t,e,i=60){spawn.mapRect(t,e-290,40,60),spawn.mapRect(t,e,40,50);for(let s=0;s<4;++s)spawn.bodyRect(t+5,e-260+s*i+3*s,30,i)},debris(t,e,i,s=Math.floor(2+9*Math.random())){for(let o=0;o<s;++o)if(Math.random()<.15)powerUps.chooseRandomPowerUp(t+Math.random()*i,e);else{const s=18+25*Math.random();spawn.bodyRect(t+Math.random()*i,e,s*(.6+Math.random()),s*(.6+Math.random()),1)}},bodyRect(t,e,i,s,o=1,a={friction:.05,frictionAir:.001}){Math.random()<o&&(body[body.length]=Bodies.rectangle(t+i/2,e+s/2,i,s,a))},bodyVertex(t,e,i,s){body[body.length]=Matter.Bodies.fromVertices(t,e,Vertices.fromPath(i),s)},mapRect(t,e,i,s,o){map[map.length]=Bodies.rectangle(t+i/2,e+s/2,i,s,o)},mapVertex(t,e,i,s){map[map.length]=Matter.Bodies.fromVertices(t,e,Vertices.fromPath(i),s)},spawnBuilding(t,e,i,s,o,a,n){this.mapRect(t,e,i,25),this.mapRect(t,e+s,i,35),"left"===n?this.mapRect(t,e,25,s):(this.mapRect(t,e,25,s-150),o&&this.bodyRect(t+5,e+s-150,15,150,this.propsFriction)),"right"===n?this.mapRect(t-25+i,e,25,s):(this.mapRect(t-25+i,e,25,s-150),a&&this.bodyRect(t+i-20,e+s-150,15,150,this.propsFriction))},spawnStairs(t,e,i,s,o,a){if(s+=50,a)for(let a=0;a<i;a++)this.mapRect(t-s/i*(1+a),e-o+a*o/i,s/i+50,o-a*o/i+50);else for(let a=0;a<i;a++)this.mapRect(t+a*s/i,e-o+a*o/i,s/i+50,o-a*o/i+50)},propsFriction:{friction:.5,frictionAir:.02,frictionStatic:1},propsFrictionMedium:{friction:.15,frictionStatic:1},propsBouncy:{friction:0,frictionAir:0,frictionStatic:0,restitution:1},propsSlide:{friction:.003,frictionStatic:.4,restitution:0,density:.002},propsLight:{density:.001},propsOverBouncy:{friction:0,frictionAir:0,frictionStatic:0,restitution:1.05},propsHeavy:{density:.01},propsIsNotHoldable:{isNotHoldable:!0},propsNoRotation:{inertia:1/0},propsHoist:{inertia:1/0,frictionAir:.001,friction:1e-4,frictionStatic:0,restitution:0,isNotHoldable:!0},propsDoor:{density:.001,friction:0,frictionAir:.03,frictionStatic:0,restitution:0},sandPaper:{friction:1,frictionStatic:1,restitution:0}};
2
3