let bullet=[];const b={dmgScale:null,gravity:6e-4,activeGun:null,inventoryGun:0,inventory:[],setFireMethod(){tech.isFireMoveLock?b.fire=b.fireFloat:tech.isAlwaysFire?b.fire=b.fireAlwaysFire:b.fire=b.fireNormal},fire(){},fireNormal(){b.inventory.length&&(input.fire&&m.fireCDcycle<m.cycle&&(!input.field||m.fieldFire)&&(b.guns[b.activeGun].ammo>0?b.fireWithAmmo():b.outOfAmmo(),m.holdingTarget&&m.drop()),b.guns[b.activeGun].do())},fireNotMove(){b.inventory.length&&(input.fire&&m.fireCDcycle<m.cycle&&(!input.field||m.fieldFire)&&player.speed<2.5&&m.onGround&&Math.abs(m.yOff-m.yOffGoal)<1&&(b.guns[b.activeGun].ammo>0?b.fireWithAmmo():b.outOfAmmo(),m.holdingTarget&&m.drop()),b.guns[b.activeGun].do())},fireAlwaysFire(){b.inventory.length&&(m.fireCDcycle<m.cycle&&player.speed<.5&&m.onGround&&Math.abs(m.yOff-m.yOffGoal)<1&&(b.guns[b.activeGun].ammo>0&&b.fireWithAmmo(),m.holdingTarget&&m.drop()),b.guns[b.activeGun].do())},fireFloat(){b.inventory.length&&(!input.fire||input.field&&!m.fieldFire||(m.fireCDcycle<m.cycle&&(b.guns[b.activeGun].ammo>0?b.fireWithAmmo():b.outOfAmmo(),m.holdingTarget&&m.drop()),Matter.Body.setVelocity(player,{x:0,y:-55*player.mass*simulation.g}),player.force.x=0,player.force.y=0),b.guns[b.activeGun].do())},fireWithAmmo(){b.guns[b.activeGun].fire(),tech.isCrouchAmmo&&input.down?(tech.isCrouchAmmo%2&&(b.guns[b.activeGun].ammo--,simulation.updateGunHUD()),tech.isCrouchAmmo++):(b.guns[b.activeGun].ammo--,simulation.updateGunHUD())},outOfAmmo(){if(simulation.makeTextLog(`${b.guns[b.activeGun].name}.<span class='color-g'>ammo</span><span class='color-symbol'>:</span> 0`),m.fireCDcycle=m.cycle+30,tech.isAmmoFromHealth&&m.health>.01){tech.extraMaxHealth-=.01,m.setMaxHealth();for(let t=0;t<4;t++)powerUps.spawn(m.pos.x+50*(Math.random()-.5),m.pos.y+50*(Math.random()-.5),"ammo")}},refundAmmo(){tech.isCrouchAmmo&&input.down?(tech.isCrouchAmmo--,tech.isCrouchAmmo%2&&(b.guns[b.activeGun].ammo++,simulation.updateGunHUD())):(b.guns[b.activeGun].ammo++,simulation.updateGunHUD())},giveGuns(t="random",e=10){if(tech.ammoCap&&(e=.45*tech.ammoCap),tech.isOneGun&&b.removeAllGuns(),"random"===t){options=[];for(let t=0,e=b.guns.length;t<e;t++)b.guns[t].have||options.push(t);if(0===options.length)return;t=options[Math.floor(Math.random()*options.length)]}if("all"===t){b.inventoryGun=0;for(let t=0;t<b.guns.length;t++)b.inventory[t]=t,b.guns[t].have=!0,b.guns[t].ammo=Math.ceil(b.guns[t].ammoPack*e);b.activeGun=0}else{if(isNaN(t)){let e=!1;for(let o=0;o<b.guns.length;o++)if(t===b.guns[o].name){t=o,e=!0;break}if(!e)return}b.guns[t].have||b.inventory.push(t),b.guns[t].have=!0,b.guns[t].ammo=Math.ceil(b.guns[t].ammoPack*e),null===b.activeGun&&(b.activeGun=t,b.guns[b.activeGun].charge&&(b.guns[b.activeGun].charge=0))}if(simulation.makeGunHUD(),b.setFireCD(),tech.isOneGun&&b.inventory>0){let t=0;for(let e=0,o=tech.tech.length;e<o;e++)if(tech.tech[e].isGunTech&&tech.tech[e].count>0&&!tech.tech[e].isNonRefundable&&!tech.tech[e].isRemoveGun){t+=tech.removeTech(e)}for(let e=0;e<t;e++){const t=[];for(let o=0,i=tech.tech.length;o<i;o++)if(tech.tech[o].isGunTech&&tech.tech[o].allowed()&&!tech.tech[e].isRemoveGun&&!tech.tech[o].isJunk&&!tech.tech[o].isBadRandomOption&&tech.tech[o].count<tech.tech[o].maxCount){const e=tech.tech[o].requires.search(b.guns[b.activeGun].name),i=tech.tech[o].requires.search(" not ");-1!==e&&(-1===i||i>e)&&t.push(o)}if(t.length){const e=Math.floor(Math.random()*t.length);tech.giveTech(t[e]),simulation.makeTextLog(`<span class='color-var'>tech</span>.giveTech("<span class='color-text'>${tech.tech[t[e]].name}</span>")`)}else tech.giveTech()}}},removeGun(t,e=!1){for(let o=0;o<b.guns.length;o++)if(b.guns[o].name===t){b.guns[o].have=!1;for(let t=0;t<b.inventory.length;t++)if(b.inventory[t]===o){b.inventory.splice(t,1);break}b.inventory.length?b.activeGun=b.inventory[0]:b.activeGun=null,simulation.makeGunHUD(),e&&b.guns.splice(o,1);break}b.setFireCD()},removeAllGuns(){b.inventory=[];for(let t=0,e=b.guns.length;t<e;++t)b.guns[t].count=0,b.guns[t].have=!1,b.guns[t].ammo!=1/0&&(b.guns[t].ammo=0);b.activeGun=null},bulletRemove(){let t=bullet.length;for(;t--;)if(bullet[t].endCycle<simulation.cycle){if(bullet[t].onEnd(t),!bullet[t])break;Matter.Composite.remove(engine.world,bullet[t]),bullet.splice(t,1)}},bulletDraw(){ctx.beginPath();for(let t=0,e=bullet.length;t<e;t++){let e=bullet[t].vertices;ctx.moveTo(e[0].x,e[0].y);for(let t=1;t<e.length;t+=1)ctx.lineTo(e[t].x,e[t].y);ctx.lineTo(e[0].x,e[0].y)}ctx.fillStyle=color.bullet,ctx.fill()},bulletDo(){for(let t=0,e=bullet.length;t<e;t++)bullet[t].do()},fireProps(t,e,o,i){m.fireCDcycle=m.cycle+Math.floor(t*b.fireCDscale),Matter.Body.setVelocity(bullet[i],{x:m.Vx/2+e*Math.cos(o),y:m.Vy/2+e*Math.sin(o)}),Composite.add(engine.world,bullet[i])},fireCDscale:1,setFireCD(){b.fireCDscale=tech.fireRate*tech.slowFire*tech.researchHaste*tech.aimDamage,tech.isFastTime&&(b.fireCDscale*=.5),tech.isFireRateForGuns&&(b.fireCDscale*=Math.pow(.82,b.inventory.length)),tech.isFireMoveLock&&(b.fireCDscale*=.5)},fireAttributes:(t,e=!0)=>e?{angle:t,friction:.5,frictionAir:0,dmg:0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:10,beforeDmg(){},onEnd(){}}:{inertia:1/0,angle:t,friction:.5,frictionAir:0,dmg:0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:10,beforeDmg(){},onEnd(){}},muzzleFlash(t=10){ctx.fillStyle="#fb0",ctx.beginPath(),ctx.arc(m.pos.x+35*Math.cos(m.angle),m.pos.y+35*Math.sin(m.angle),t,0,2*Math.PI),ctx.fill()},removeConsBB(t){for(let e=0,o=consBB.length;e<o;++e){if(consBB[e].bodyA===t){consBB[e].bodyA=consBB[e].bodyB,consBB.splice(e,1);break}if(consBB[e].bodyB===t){consBB[e].bodyB=consBB[e].bodyA,consBB.splice(e,1);break}}},onCollision(t){const e=t.pairs;for(let t=0,i=e.length;t!=i;t++){function o(t){t.onWallHit&&t.onWallHit()}e[t].bodyA.collisionFilter.category===cat.map&&e[t].bodyB.collisionFilter.category===cat.bullet?o(e[t].bodyB):e[t].bodyB.collisionFilter.category===cat.map&&e[t].bodyA.collisionFilter.category===cat.bullet&&o(e[t].bodyA)}},explosionRange:()=>tech.explosiveRadius*(tech.isExplosionHarm?1.8:1)*(tech.isSmallExplosion?.66:1)*(tech.isExplodeRadio?1.25:1),explosion(t,e,o="rgba(255,25,0,0.6)"){let i,s,a,l=.017*(e*=tech.explosiveRadius)*(tech.isExplosionStun?.7:1);if(tech.isExplosionHarm&&(e*=1.8),tech.isSmallExplosion&&(o="rgba(255,0,30,0.7)",e*=.66,l*=1.66),tech.isExplodeRadio){if(e*=1.25,tech.isSmartRadius&&(e=Math.max(Math.min(e,Vector.magnitude(Vector.sub(t,player.position))-25),1)),o="rgba(25,139,170,0.25)",simulation.drawList.push({x:t.x,y:t.y,radius:e,color:o,time:2*simulation.drawTime}),Vector.magnitude(Vector.sub(t,player.position))<e){const t=(tech.isExplosionHarm?1.2:.45)*(tech.isRadioactiveResistance?.25:1);m.immuneCycle<m.cycle&&(m.energy-=t),m.energy<0&&(m.energy=0,simulation.dmgScale&&m.damage(.03*(tech.isRadioactiveResistance?.25:1)))}let a=1.5;for(let o=0,n=mob.length;o<n;++o)mob[o].alive&&!mob[o].isShielded&&(s=Vector.sub(t,mob[o].position),i=Vector.magnitude(s)-mob[o].radius,i<e&&(mob[o].shield&&(l*=2.5),Matter.Query.ray(map,mob[o].position,t).length>0&&(l*=.5),mobs.statusDoT(mob[o],l*a*.25,240),tech.isExplosionStun&&mobs.statusStun(mob[o],60),mob[o].locatePlayer(),a*=.87))}else{tech.isSmartRadius&&(e=Math.max(Math.min(e,Vector.magnitude(Vector.sub(t,player.position))-25),1)),simulation.drawList.push({x:t.x,y:t.y,radius:e,color:o,time:simulation.drawTime});const n=100+2*e;if(simulation.drawList.push({x:t.x,y:t.y,radius:n,color:"rgba(100,20,0,0.03)",time:simulation.drawTime}),m.immuneCycle<m.cycle)if(s=Vector.sub(t,player.position),i=Vector.magnitude(s),i<e){const t=e*(tech.isExplosionHarm?55e-5:18e-5);if(tech.isImmuneExplosion){const e=Math.min(1,Math.max(1-.5*m.energy,0));simulation.dmgScale&&m.damage(e*t)}else simulation.dmgScale&&m.damage(t);a=Vector.mult(Vector.normalise(s),-Math.sqrt(l)*player.mass*.013),player.force.x+=a.x,player.force.y+=a.y}else i<n&&(a=Vector.mult(Vector.normalise(s),-Math.sqrt(l)*player.mass*.005),player.force.x+=a.x,player.force.y+=a.y);for(let o=body.length-1;o>-1;o--)if(!body[o].isNotHoldable)if(s=Vector.sub(t,body[o].position),i=Vector.magnitude(s),i<e){if(a=Vector.mult(Vector.normalise(s),-Math.sqrt(l)*body[o].mass*.022),body[o].force.x+=a.x,body[o].force.y+=a.y,tech.isBlockExplode){body[o]===m.holdingTarget&&m.drop();const t=20+350*Math.pow(body[o].mass,.25),e=body[o].position,i=level.onLevel;Matter.Composite.remove(engine.world,body[o]),body.splice(o,1),setTimeout((()=>{i===level.onLevel&&b.explosion(e,t)}),150+300*Math.random())}}else i<n&&(a=Vector.mult(Vector.normalise(s),-Math.sqrt(l)*body[o].mass*.011),body[o].force.x+=a.x,body[o].force.y+=a.y);for(let o=0,r=powerUp.length;o<r;++o)s=Vector.sub(t,powerUp[o].position),i=Vector.magnitude(s),i<e?(a=Vector.mult(Vector.normalise(s),-Math.sqrt(l)*powerUp[o].mass*.013),powerUp[o].force.x+=a.x,powerUp[o].force.y+=a.y):i<n&&(a=Vector.mult(Vector.normalise(s),-Math.sqrt(l)*powerUp[o].mass*.007),powerUp[o].force.x+=a.x,powerUp[o].force.y+=a.y);let r=1.5;for(let o=0,c=mob.length;o<c;++o)mob[o].alive&&!mob[o].isShielded&&(s=Vector.sub(t,mob[o].position),i=Vector.magnitude(s)-mob[o].radius,i<e?(mob[o].shield&&(l*=2.5),Matter.Query.ray(map,mob[o].position,t).length>0&&(l*=.5),mob[o].damage(l*r*b.dmgScale),mob[o].locatePlayer(),a=Vector.mult(Vector.normalise(s),-Math.sqrt(l*r)*mob[o].mass*.01),mob[o].force.x+=a.x,mob[o].force.y+=a.y,tech.isExplosionStun&&mobs.statusStun(mob[o],120),e*=.95,r*=.87):!mob[o].seePlayer.recall&&i<n&&(mob[o].locatePlayer(),a=Vector.mult(Vector.normalise(s),-Math.sqrt(l*r)*mob[o].mass*.006),mob[o].force.x+=a.x,mob[o].force.y+=a.y,tech.isExplosionStun&&mobs.statusStun(mob[o],60)))}},pulse(t,e=m.angle,o=m.pos){let i,s=5.5*t;const a=[{x:o.x+20*Math.cos(e),y:o.y+20*Math.sin(e)},{x:o.x+5e3*Math.cos(e),y:o.y+5e3*Math.sin(e)}],l=function(t,e,o){for(let s=0;s<o.length;++s){let a=o[s].vertices;const l=a.length-1;for(let n=0;n<l;n++)if(results=simulation.checkLineIntersection(t,e,a[n],a[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,l=t.y-results.y,r=e*e+l*l;r<i.dist2&&(!o[s].mob||o[s].alive)&&(i={x:results.x,y:results.y,dist2:r,who:o[s],v1:a[n],v2:a[n+1]})}if(results=simulation.checkLineIntersection(t,e,a[0],a[l]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,r=e*e+n*n;r<i.dist2&&(!o[s].mob||o[s].alive)&&(i={x:results.x,y:results.y,dist2:r,who:o[s],v1:a[0],v2:a[l]})}}};if(i={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null},tech.isPulseAim){let t=2200;for(let e=0,o=mob.length;e<o;e++){const o=Vector.magnitude(Vector.sub(a[0],mob[e].position));s<o&&o<t&&!mob[e].isBadTarget&&0===Matter.Query.ray(map,a[0],mob[e].position).length&&0===Matter.Query.ray(body,a[0],mob[e].position).length&&(t=o,i.who=mob[e],a[a.length-1]=mob[e].position)}}if(i.who||(l(a[0],a[1],mob),l(a[0],a[1],map),l(a[0],a[1],body),i.dist2!=1/0&&(a[a.length-1]={x:i.x,y:i.y})),i.who){b.explosion(a[1],s);const t=1.2*s;b.explosion({x:a[1].x+t*(Math.random()-.5),y:a[1].y+t*(Math.random()-.5)},s),b.explosion({x:a[1].x+t*(Math.random()-.5),y:a[1].y+t*(Math.random()-.5)},s)}ctx.beginPath(),ctx.moveTo(a[0].x,a[0].y),ctx.lineTo(a[1].x,a[1].y),t>50&&(ctx.strokeStyle="rgba(255,0,0,0.10)",ctx.lineWidth=70,ctx.stroke()),ctx.strokeStyle="rgba(255,0,0,0.25)",ctx.lineWidth=20,ctx.stroke(),ctx.strokeStyle="#f00",ctx.lineWidth=4,ctx.stroke();const n=Vector.sub(a[1],a[0]),r=Vector.magnitude(n);for(let e=0,o=Math.floor(5e-4*r*t);e<o;e++){const t=Math.random();simulation.drawList.push({x:a[0].x+n.x*t+10*(Math.random()-.5),y:a[0].y+n.y*t+10*(Math.random()-.5),radius:1.5+5*Math.random(),color:"rgba(255,0,0,0.5)",time:Math.floor(9+25*Math.random()*Math.random())})}},grenade(){},setGrenadeMode(){grenadeDefault=function(t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e=m.angle,o=1){const i=bullet.length;bullet[i]=Bodies.circle(t.x,t.y,15,b.fireAttributes(e,!1)),Matter.Body.setDensity(bullet[i],3e-4),bullet[i].explodeRad=300*o,bullet[i].onEnd=function(){b.explosion(this.position,this.explodeRad),tech.fragments&&b.targetedNail(this.position,tech.fragments*Math.floor(2+2*Math.random()))},bullet[i].minDmgSpeed=1,bullet[i].beforeDmg=function(){this.endCycle=0},speed=input.down?43:32,Matter.Body.setVelocity(bullet[i],{x:m.Vx/2+speed*Math.cos(e),y:m.Vy/2+speed*Math.sin(e)}),bullet[i].endCycle=simulation.cycle+Math.floor(input.down?120:80),bullet[i].restitution=.4,bullet[i].do=function(){this.force.y+=.0025*this.mass},Composite.add(engine.world,bullet[i])},grenadeRPG=function(t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e=m.angle,o=1){const i=bullet.length;bullet[i]=Bodies.circle(t.x,t.y,15,b.fireAttributes(e,!1)),Matter.Body.setDensity(bullet[i],3e-4),bullet[i].explodeRad=305*o,bullet[i].onEnd=function(){b.explosion(this.position,this.explodeRad),tech.fragments&&b.targetedNail(this.position,tech.fragments*Math.floor(2+2*Math.random()))},bullet[i].minDmgSpeed=1,bullet[i].beforeDmg=function(){this.endCycle=0},speed=input.down?46:32,Matter.Body.setVelocity(bullet[i],{x:m.Vx/2+speed*Math.cos(e),y:m.Vy/2+speed*Math.sin(e)}),Composite.add(engine.world,bullet[i]),bullet[i].endCycle=simulation.cycle+70,bullet[i].frictionAir=.07;bullet[i].thrust={x:.015*bullet[i].mass*Math.cos(e),y:.015*bullet[i].mass*Math.sin(e)},bullet[i].do=function(){this.force.x+=this.thrust.x,this.force.y+=this.thrust.y,(Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length)&&(this.endCycle=0)}},grenadeRPGVacuum=function(t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e=m.angle,o=1){const s=bullet.length;bullet[s]=Bodies.circle(t.x,t.y,15,b.fireAttributes(e,!1)),Matter.Body.setDensity(bullet[s],3e-4),bullet[s].explodeRad=350*o+Math.floor(50*Math.random())+110*tech.isBlockExplode,bullet[s].onEnd=function(){b.explosion(this.position,this.explodeRad),tech.fragments&&b.targetedNail(this.position,tech.fragments*Math.floor(2+2*Math.random()))},bullet[s].minDmgSpeed=1,bullet[s].beforeDmg=function(){this.endCycle=0},speed=input.down?46:32,Matter.Body.setVelocity(bullet[s],{x:m.Vx/2+speed*Math.cos(e),y:m.Vy/2+speed*Math.sin(e)}),Composite.add(engine.world,bullet[s]),bullet[s].endCycle=simulation.cycle+70,bullet[s].frictionAir=.07;bullet[s].thrust={x:.015*bullet[s].mass*Math.cos(e),y:.015*bullet[s].mass*Math.sin(e)},bullet[s].do=function(){if(!m.isBodiesAsleep&&simulation.cycle>this.endCycle-40||Matter.Query.collides(this,map).length||Matter.Query.collides(this,body).length){const e=this;function t(t,s=3.2*e.explodeRad){for(i=0,len=t.length;i<len;i++){const a=Vector.sub(e.position,t[i].position),l=Vector.magnitude(a);l<s&&l>150&&(knock=Vector.mult(Vector.normalise(a),o*t[i].mass/Math.sqrt(l)),t[i].force.x+=knock.x,t[i].force.y+=knock.y)}}let o=.1;simulation.cycle>this.endCycle-5?(o=-.22,t(mob,3*this.explodeRad),t(body,2*this.explodeRad),t(powerUp,1.5*this.explodeRad),t(bullet,1.5*this.explodeRad),t([player],1.3*this.explodeRad)):(o=.11,t(mob,3*this.explodeRad),t(body,2*this.explodeRad),t(powerUp,1.5*this.explodeRad),t(bullet,1.5*this.explodeRad),t([player],1.3*this.explodeRad)),Matter.Body.setVelocity(this,{x:0,y:0});const s=2.75*this.explodeRad*(this.endCycle-simulation.cycle)/40;ctx.fillStyle="rgba(0,0,0,0.1)",ctx.beginPath(),ctx.arc(this.position.x,this.position.y,s,0,2*Math.PI),ctx.fill()}else this.force.x+=this.thrust.x,this.force.y+=this.thrust.y}},grenadeVacuum=function(t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e=m.angle,o=1){const s=bullet.length;bullet[s]=Bodies.circle(t.x,t.y,20,b.fireAttributes(e,!1)),Matter.Body.setDensity(bullet[s],2e-4),bullet[s].explodeRad=350*o+Math.floor(50*Math.random())+100*tech.isBlockExplode,bullet[s].onEnd=function(){b.explosion(this.position,this.explodeRad),tech.fragments&&b.targetedNail(this.position,5*tech.fragments)},bullet[s].beforeDmg=function(){this.endCycle=0},bullet[s].restitution=.4,bullet[s].do=function(){this.force.y+=.0025*this.mass;if(!m.isBodiesAsleep&&simulation.cycle>this.endCycle-40){const e=this;function t(t,s=3.2*e.explodeRad){for(i=0,len=t.length;i<len;i++){const a=Vector.sub(e.position,t[i].position),l=Vector.magnitude(a);l<s&&l>150&&(knock=Vector.mult(Vector.normalise(a),o*t[i].mass/Math.sqrt(l)),t[i].force.x+=knock.x,t[i].force.y+=knock.y)}}let o=.1;simulation.cycle>this.endCycle-5?(o=-.22,t(mob,3*this.explodeRad),t(body,2*this.explodeRad),t(powerUp,1.5*this.explodeRad),t(bullet,1.5*this.explodeRad),t([player],1.3*this.explodeRad)):(o=.11,t(mob,3*this.explodeRad),t(body,2*this.explodeRad),t(powerUp,1.5*this.explodeRad),t(bullet,1.5*this.explodeRad),t([player],1.3*this.explodeRad)),Matter.Body.setVelocity(this,{x:0,y:0});const s=2.75*this.explodeRad*(this.endCycle-simulation.cycle)/40;ctx.fillStyle="rgba(0,0,0,0.1)",ctx.beginPath(),ctx.arc(this.position.x,this.position.y,s,0,2*Math.PI),ctx.fill()}},speed=35,bullet[s].endCycle=simulation.cycle+70,input.down&&(speed+=9,bullet[s].endCycle+=20),Matter.Body.setVelocity(bullet[s],{x:m.Vx/2+speed*Math.cos(e),y:m.Vy/2+speed*Math.sin(e)}),Composite.add(engine.world,bullet[s])},grenadeNeutron=function(t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e=m.angle,o=1){const s=bullet.length;if(bullet[s]=Bodies.polygon(t.x,t.y,10,4,b.fireAttributes(e,!1)),b.fireProps((input.down?45:25)/Math.pow(.93,tech.missileCount),input.down?35:20,e,s),Matter.Body.setDensity(bullet[s],1e-6),bullet[s].endCycle=1/0,bullet[s].frictionAir=0,bullet[s].friction=1,bullet[s].frictionStatic=1,bullet[s].restitution=0,bullet[s].minDmgSpeed=0,bullet[s].damageRadius=100,bullet[s].maxDamageRadius=450*o+130*tech.isNeutronSlow,bullet[s].radiusDecay=(.81+.15*tech.isNeutronSlow)/tech.isBulletsLastLonger,bullet[s].stuckTo=null,bullet[s].stuckToRelativePosition=null,tech.isRPG){const t=2;Matter.Body.scale(bullet[s],t,t),speed=input.down?25:15,Matter.Body.setVelocity(bullet[s],{x:m.Vx/2+speed*Math.cos(e),y:m.Vy/2+speed*Math.sin(e)});const o=.005;bullet[s].thrust={x:bullet[s].mass*o*Math.cos(e),y:bullet[s].mass*o*Math.sin(e)}}bullet[s].beforeDmg=function(){},bullet[s].stuck=function(){},bullet[s].do=function(){const t=()=>{this.collisionFilter.mask=0,Matter.Body.setVelocity(this,{x:0,y:0}),tech.isRPG&&(this.thrust={x:0,y:0}),this.do=this.radiationMode},e=Matter.Query.collides(this,mob);if(e.length)t(),this.stuckTo=e[0].bodyA,mobs.statusDoT(this.stuckTo,.5,360),this.stuckTo.isVerticesChange?this.stuckToRelativePosition={x:0,y:0}:this.stuckToRelativePosition=Vector.rotate(Vector.sub(this.position,this.stuckTo.position),-this.stuckTo.angle),this.stuck=function(){if(this.stuckTo&&this.stuckTo.alive){const t=Vector.rotate(this.stuckToRelativePosition,this.stuckTo.angle);Matter.Body.setPosition(this,Vector.add(Vector.add(t,this.stuckTo.velocity),this.stuckTo.position)),Matter.Body.setVelocity(this,this.stuckTo.velocity)}else this.collisionFilter.mask=cat.map|cat.body|cat.player|cat.mob,this.stuck=function(){this.force.y+=.001*this.mass}};else{const e=Matter.Query.collides(this,body);e.length?(e[0].bodyA.isNotHoldable?this.do=this.radiationMode:(t(),this.stuckTo=e[0].bodyA,this.stuckToRelativePosition=Vector.rotate(Vector.sub(this.position,this.stuckTo.position),-this.stuckTo.angle)),this.stuck=function(){if(this.stuckTo){const t=Vector.rotate(this.stuckToRelativePosition,this.stuckTo.angle);Matter.Body.setPosition(this,Vector.add(Vector.add(t,this.stuckTo.velocity),this.stuckTo.position))}else this.force.y+=.001*this.mass}):Matter.Query.collides(this,map).length?t():tech.isRPG?(this.force.x+=this.thrust.x,this.force.y+=this.thrust.y):this.force.y+=.001*this.mass}},bullet[s].radiationMode=function(){if(this.stuck(),!m.isBodiesAsleep)if(this.damageRadius=.85*this.damageRadius+.15*this.maxDamageRadius,this.maxDamageRadius-=this.radiusDecay,this.damageRadius<15)this.endCycle=0;else{if(Vector.magnitude(Vector.sub(player.position,this.position))<this.damageRadius){const t=tech.isRadioactiveResistance?625e-6:.0025;m.energy>t?m.immuneCycle<m.cycle&&(m.energy-=t):(m.energy=0,simulation.dmgScale&&m.damage(tech.isRadioactiveResistance?4e-5:16e-5))}for(let t=0,e=mob.length;t<e;t++)if(Vector.magnitude(Vector.sub(mob[t].position,this.position))<this.damageRadius+mob[t].radius){let e=.11*b.dmgScale;Matter.Query.ray(map,mob[t].position,this.position).length>0&&(e*=.25),mob[t].shield&&(e*=3),mob[t].damage(e),mob[t].locatePlayer(),tech.isNeutronSlow&&Matter.Body.setVelocity(mob[t],{x:.97*mob[t].velocity.x,y:.97*mob[t].velocity.y})}if(ctx.beginPath(),ctx.arc(this.position.x,this.position.y,this.damageRadius,0,2*Math.PI),ctx.globalCompositeOperation="lighter",ctx.fillStyle=`rgba(25,139,170,${.2+.06*Math.random()})`,ctx.fill(),ctx.globalCompositeOperation="source-over",tech.isNeutronSlow){let t=(t,e=3.2*this.explodeRad)=>{for(i=0,len=t.length;i<len;i++){const o=Vector.sub(this.position,t[i].position);Vector.magnitude(o)<e&&Matter.Body.setVelocity(t[i],{x:.975*t[i].velocity.x,y:.975*t[i].velocity.y})}};t(body,this.damageRadius),t([player],this.damageRadius)}}}};let t=null;for(let e=0,o=b.guns.length;e<o;e++)"grenades"===b.guns[e].name&&(t=e);tech.isNeutronBomb?(b.grenade=grenadeNeutron,tech.isRPG?b.guns[t].do=function(){}:t&&(b.guns[t].do=function(){if(!input.field&&input.down){const t=80,e=input.down?35:20,o=input.down?.137:.135,i={x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)};ctx.strokeStyle="rgba(68, 68, 68, 0.2)",ctx.lineWidth=2,ctx.beginPath();for(let e=1,s=19;e<s+1;e++){const a=t*e/s;ctx.lineTo(m.pos.x+a*i.x,m.pos.y+a*i.y+o*a*a)}ctx.stroke()}})):tech.isRPG?(b.guns[t].do=function(){},tech.isVacuumBomb?b.grenade=grenadeRPGVacuum:b.grenade=grenadeRPG):tech.isVacuumBomb?(b.grenade=grenadeVacuum,t&&(b.guns[t].do=function(){if(!input.field&&input.down){const t=Math.floor(input.down?50:30),e=input.down?44:35,o={x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)};ctx.strokeStyle="rgba(68, 68, 68, 0.2)",ctx.lineWidth=2,ctx.beginPath();for(let e=1.6,i=19;e<i+1;e++){const s=t*e/i;ctx.lineTo(m.pos.x+s*o.x,m.pos.y+s*o.y+.34*s*s)}ctx.stroke()}})):(b.grenade=grenadeDefault,t&&(b.guns[t].do=function(){if(!input.field&&input.down){const t=Math.floor(input.down?120:80),e=input.down?43:32,o={x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)};ctx.strokeStyle="rgba(68, 68, 68, 0.2)",ctx.lineWidth=2,ctx.beginPath();for(let e=.5,i=19;e<i+1;e++){const s=t*e/i;ctx.lineTo(m.pos.x+s*o.x,m.pos.y+s*o.y+.34*s*s)}ctx.stroke()}}))},dart(t,e=m.angle,o=.8){const i={score:1e4,position:null};for(let o=0,s=mob.length;o<s;++o)if(mob[o].alive&&!mob[o].isBadTarget&&0===Matter.Query.ray(map,t,mob[o].position).length){const s=Vector.dot({x:Math.cos(e),y:Math.sin(e)},Vector.normalise(Vector.sub(mob[o].position,t))),a=Vector.magnitude(Vector.sub(t,mob[o].position));a<i.score&&s>.9-4e-4*a&&(i.score=a,i.position=mob[o].position)}i.position||(i.position=Vector.mult(Vector.sub(simulation.mouseInGame,t),1e4));const s=bullet.length;bullet[s]=Bodies.fromVertices(t.x,t.y,[{x:-20*o,y:2*o,index:0,isInternal:!1},{x:-20*o,y:-2*o,index:1,isInternal:!1},{x:5*o,y:-2*o,index:4,isInternal:!1},{x:20*o,y:0,index:3,isInternal:!1},{x:5*o,y:2*o,index:4,isInternal:!1}],{cycle:0,angle:e,friction:1,frictionAir:.15,thrustMag:.03,turnRate:.15,drawStringControlMagnitude:3e3+5e3*Math.random(),drawStringFlip:Math.round(Math.random())?1:-1,dmg:7,classType:"bullet",endCycle:simulation.cycle+120,collisionFilter:{category:cat.bullet,mask:tech.isShieldPierce?cat.body|cat.mob|cat.mobBullet:cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:0,lookFrequency:Math.floor(7+3*Math.random()),density:.001,beforeDmg(t){tech.isShieldPierce&&t.isShielded&&(t.isShielded=!1,requestAnimationFrame((()=>{t.isShielded=!0}))),tech.fragments&&(b.targetedNail(this.vertices[2],4*tech.fragments),this.endCycle=0),t.isBadTarget||(this.frictionAir=.01,this.do=this.doNoTargeting)},onEnd(){},doNoTargeting:function(){Matter.Query.collides(this,map).length&&(this.collisionFilter.mask=0,Matter.Body.setAngularVelocity(this,0),Matter.Body.setVelocity(this,{x:0,y:0}),this.do=()=>{})},do(){if(!m.isBodiesAsleep){this.cycle++;const t={x:Math.cos(this.angle),y:Math.sin(this.angle)},e=Vector.normalise(Vector.sub(this.position,i.position)),o=Vector.cross(e,t);o>.01?Matter.Body.rotate(this,this.turnRate*Math.sqrt(o)):o<.01&&Matter.Body.rotate(this,-this.turnRate*Math.sqrt(Math.abs(o))),this.force.x+=this.thrustMag*this.mass*Math.cos(this.angle),this.force.y+=this.thrustMag*this.mass*Math.sin(this.angle),Matter.Query.collides(this,map).length&&(this.collisionFilter.mask=0,Matter.Body.setAngularVelocity(this,0),Matter.Body.setVelocity(this,{x:0,y:0}),this.do=this.doNoTargeting)}}}),Matter.Body.setVelocity(bullet[s],{x:m.Vx/2+40*Math.cos(bullet[s].angle),y:m.Vy/2+40*Math.sin(bullet[s].angle)}),Composite.add(engine.world,bullet[s])},harpoon(t,e,o=m.angle,s=1,a=!1,l=15){const n=bullet.length,r=100*Math.sqrt(s);bullet[n]=Bodies.fromVertices(t.x,t.y,[{x:-40*s,y:2*s,index:0,isInternal:!1},{x:-40*s,y:-2*s,index:1,isInternal:!1},{x:50*s,y:-3*s,index:3,isInternal:!1},{x:30*s,y:2*s,index:4,isInternal:!1}],{cycle:0,angle:o,friction:1,frictionAir:.4,thrustMag:.1,turnRate:a?.1:.03,drawStringControlMagnitude:3e3+5e3*Math.random(),drawStringFlip:Math.round(Math.random())?1:-1,dmg:7,classType:"bullet",endCycle:simulation.cycle+2.5*l+15,collisionFilter:{category:cat.bullet,mask:tech.isShieldPierce?cat.map|cat.body|cat.mob|cat.mobBullet:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:0,lookFrequency:Math.floor(7+3*Math.random()),density:tech.harpoonDensity,beforeDmg(t){tech.isShieldPierce&&t.isShielded&&(t.isShielded=!1,requestAnimationFrame((()=>{t.isShielded=!0}))),tech.fragments&&(b.targetedNail(this.vertices[2],4*tech.fragments),a||(this.endCycle=0)),t.isBadTarget||(a?this.do=this.returnToPlayer:(this.frictionAir=.01,this.do=()=>{this.force.y+=.003*this.mass,this.draw()}))},caughtPowerUp:null,dropCaughtPowerUp(){this.caughtPowerUp&&(this.caughtPowerUp.collisionFilter.category=cat.powerUp,this.caughtPowerUp.collisionFilter.mask=cat.map|cat.powerUp,this.caughtPowerUp=null)},onEnd(){if(!this.caughtPowerUp||simulation.isChoosing||"heal"===this.caughtPowerUp.name&&m.health===m.maxHealth&&!tech.isOverHeal)this.dropCaughtPowerUp();else{let t=null;for(let e=0,o=powerUp.length;e<o;++e)powerUp[e]===this.caughtPowerUp&&(t=e);null!==t?(powerUps.onPickUp(this.caughtPowerUp),this.caughtPowerUp.effect(),Matter.Composite.remove(engine.world,this.caughtPowerUp),powerUp.splice(t,1),tech.isHarpoonPowerUp&&(tech.harpoonDensity=.064)):this.dropCaughtPowerUp()}},drawToggleHarpoon(){ctx.beginPath(),ctx.moveTo(this.vertices[0].x,this.vertices[0].y);for(let t=1,e=this.vertices.length;t<e;t+=1)ctx.lineTo(this.vertices[t].x,this.vertices[t].y);ctx.lineTo(this.vertices[0].x,this.vertices[0].y),ctx.lineJoin="miter",ctx.miterLimit=100,ctx.lineWidth=60,ctx.strokeStyle="rgba(0,255,255,0.25)",ctx.stroke(),ctx.lineWidth=20,ctx.strokeStyle="rgb(0,255,255)",ctx.stroke(),ctx.lineJoin="round",ctx.miterLimit=10,ctx.sillStyle="#000",ctx.fill()},drawString(){const t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e=Vector.sub(t,this.vertices[0]),o=Vector.mult(Vector.normalise(Vector.perp(e)),this.drawStringFlip*Math.min(80,10+this.drawStringControlMagnitude/(10+Vector.magnitude(e)))),i=Vector.add(Vector.add(t,Vector.mult(e,-.5)),o);ctx.strokeStyle="#000",ctx.lineWidth=.5,ctx.beginPath(),ctx.moveTo(t.x,t.y),ctx.quadraticCurveTo(i.x,i.y,this.vertices[0].x,this.vertices[0].y),ctx.stroke()},draw(){},returnToPlayer(){if(Vector.magnitude(Vector.sub(this.position,m.pos))<r){this.endCycle=0,m.cycle+25*b.fireCDscale<m.fireCDcycle&&(m.fireCDcycle=m.cycle+35*b.fireCDscale);const t=Vector.mult(Vector.sub(this.velocity,player.velocity),input.down?15e-5:3e-4);for(player.force.x+=t.x,player.force.y+=t.y,i=0,len=b.guns.length;i<len;i++)if("harpoon"===b.guns[i].name){b.guns[i].ammo++,simulation.updateGunHUD();break}}else{m.energy>.005&&!m.isBodiesAsleep&&(m.energy-=.005);const t=Vector.sub(this.position,m.pos),e=1+1e-6*Vector.magnitude(t)*Vector.magnitude(t),o=Vector.mult(Vector.normalise(t),e*this.thrustMag*this.mass);this.force.x-=o.x,this.force.y-=o.y,this.grabPowerUp()}this.draw()},grabPowerUp(){if(this.caughtPowerUp)Matter.Body.setPosition(this.caughtPowerUp,Vector.add(this.vertices[2],this.velocity)),Matter.Body.setVelocity(this.caughtPowerUp,{x:0,y:0});else for(let t=0,e=powerUp.length;t<e;++t){const e=powerUp[t].circleRadius+50;if(Vector.magnitudeSquared(Vector.sub(this.vertices[2],powerUp[t].position))<e*e&&("heal"!==powerUp[t].name||m.health!==m.maxHealth||tech.isOverHeal)){this.caughtPowerUp=powerUp[t],Matter.Body.setVelocity(powerUp[t],{x:0,y:0}),Matter.Body.setPosition(powerUp[t],this.vertices[2]),powerUp[t].collisionFilter.category=0,powerUp[t].collisionFilter.mask=0,this.thrustMag*=.6,this.endCycle+=.5;break}}},do(){if(!m.isBodiesAsleep){if(this.cycle++,a)if(this.cycle>l)if(m.energy<.05){const t=Vector.mult(Vector.normalise(Vector.sub(this.position,m.pos)),3*this.thrustMag*this.mass);this.force.x-=t.x,this.force.y-=t.y,this.frictionAir=.002,this.do=()=>{this.force.y+=.001*this.mass},this.dropCaughtPowerUp()}else this.do=this.returnToPlayer,Matter.Body.setDensity(this,5e-4),this.angularSpeed<.5&&(this.torque+=.001*this.inertia*(Math.random()-.5)),this.collisionFilter.mask=cat.map|cat.mob|cat.mobBullet|cat.mobShield;else this.grabPowerUp();else this.cycle>30&&(this.frictionAir=.003,this.do=()=>{this.force.y+=.003*this.mass});if(e){const t={x:Math.cos(this.angle),y:Math.sin(this.angle)},o=Vector.normalise(Vector.sub(this.position,e.position));Vector.cross(o,t)>0?Matter.Body.rotate(this,this.turnRate):Matter.Body.rotate(this,-this.turnRate)}(a||e)&&(this.force.x+=this.thrustMag*this.mass*Math.cos(this.angle),this.force.y+=this.thrustMag*this.mass*Math.sin(this.angle))}this.draw()}}),a||e||(Matter.Body.setVelocity(bullet[n],{x:m.Vx/2+60*Math.cos(bullet[n].angle),y:m.Vy/2+60*Math.sin(bullet[n].angle)}),bullet[n].frictionAir=.002,bullet[n].do=function(){this.force.y+=.001*this.mass,this.draw()}),tech.isHarpoonPowerUp&&bullet[n].density>.01?bullet[n].draw=a?function(){this.drawToggleHarpoon(),this.drawString()}:function(){this.drawToggleHarpoon()}:a&&(bullet[n].draw=function(){this.drawString()}),Composite.add(engine.world,bullet[n])},missile(t,e,o,i=1){tech.missileSize&&(i*=1.5);const s=bullet.length;bullet[s]=Bodies.rectangle(t.x,t.y,30*i,4*i,{angle:e,friction:.5,frictionAir:.045,dmg:0,classType:"bullet",endCycle:simulation.cycle+Math.floor((230+40*Math.random())*tech.isBulletsLastLonger),collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:10,lookFrequency:Math.floor(10+3*Math.random()),explodeRad:180*(tech.missileSize?1.5:1)+60*Math.random(),density:.02,beforeDmg(){Matter.Body.setDensity(this,1e-4),this.tryToLockOn(),this.endCycle=0},onEnd(){b.explosion(this.position,this.explodeRad*i),tech.fragments&&b.targetedNail(this.position,tech.fragments*Math.floor(2+2*Math.random()))},lockedOn:null,tryToLockOn(){let t=1/0;const e=Vector.add(this.position,Vector.mult(this.velocity,30));this.lockedOn=null;for(let o=0,s=mob.length;o<s;++o)if(mob[o].alive&&!mob[o].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[o].position).length){const s=Vector.magnitude(Vector.sub(e,mob[o].position));s<t&&(t=s,this.lockedOn=mob[o]),Vector.magnitude(Vector.sub(this.position,mob[o].position)<this.explodeRad)&&(this.endCycle=0,mob[o].lockedOn.damage(2*b.dmgScale*i))}this.lockedOn&&Vector.magnitude(Vector.sub(this.position,this.lockedOn.position))<this.explodeRad&&(this.endCycle=0,this.lockedOn.damage(4*b.dmgScale*i))},do(){if(m.isBodiesAsleep)ctx.beginPath(),ctx.arc(this.position.x-Math.cos(this.angle)*(30*i-3)+4*(Math.random()-.5),this.position.y-Math.sin(this.angle)*(30*i-3)+4*(Math.random()-.5),2+9*i,0,2*Math.PI),ctx.fillStyle="rgba(255,155,0,0.5)",ctx.fill();else{if(m.cycle%this.lookFrequency||this.tryToLockOn(),this.lockedOn){const t={x:Math.cos(this.angle),y:Math.sin(this.angle)},e=Vector.normalise(Vector.sub(this.position,this.lockedOn.position)),o=Vector.dot(e,t),i=Math.min(.08,1*(1+o));Vector.cross(e,t)>0?Matter.Body.rotate(this,i):Matter.Body.rotate(this,-i),this.frictionAir=Math.min(.1,Math.max(.04,1+o))}const t=this.angle;this.force.x+=a*Math.cos(t),this.force.y+=a*Math.sin(t),ctx.beginPath(),ctx.arc(this.position.x-Math.cos(this.angle)*(25*i-3)+4*(Math.random()-.5),this.position.y-Math.sin(this.angle)*(25*i-3)+4*(Math.random()-.5),11*i,0,2*Math.PI),ctx.fillStyle="rgba(255,155,0,0.5)",ctx.fill()}}});const a=.0066*bullet[s].mass*(tech.missileSize?.6:1);Matter.Body.setVelocity(bullet[s],{x:m.Vx/2+o*Math.cos(e),y:m.Vy/2+o*Math.sin(e)}),Composite.add(engine.world,bullet[s])},lastAngle:0,wasExtruderOn:!1,isExtruderOn:!1,didExtruderDrain:!1,canExtruderFire:!0,extruder(){const t=.0021;if(m.energy>t&&b.canExtruderFire){m.energy-=t,m.energy<0&&(m.fieldCDcycle=m.cycle+120,m.energy=0),b.isExtruderOn=!0;const e=8+12*tech.isPlasmaRange,o=bullet.length,i=Vector.add(m.pos,player.velocity);bullet[o]=Bodies.polygon(i.x+20*Math.cos(m.angle),i.y+20*Math.sin(m.angle),4,.01,{cycle:-.5,isWave:!0,endCycle:simulation.cycle+40,inertia:1/0,frictionAir:0,isInHole:!0,minDmgSpeed:0,dmg:2.5*b.dmgScale,classType:"bullet",isBranch:!1,restitution:0,collisionFilter:{category:0,mask:0},beforeDmg(){},onEnd(){},do(){if(!m.isBodiesAsleep){if(this.endCycle<simulation.cycle+1&&(this.isWave=!1),Matter.Query.point(map,this.position).length)this.isBranch=!0,this.do=()=>{this.endCycle<simulation.cycle+1&&(this.isWave=!1)};else for(let t=0,e=mob.length;t<e;t++){const e=Vector.magnitudeSquared(Vector.sub(this.position,mob[t].position)),o=mob[t].radius+tech.extruderRange/2;if(e<o*o){Matter.Body.setVelocity(mob[t],{x:.25*mob[t].velocity.x,y:.25*mob[t].velocity.y}),Matter.Body.setPosition(this,Vector.add(this.position,mob[t].velocity));let e=this.dmg/Math.min(10,mob[t].mass);mob[t].damage(e),mob[t].alive&&mob[t].foundPlayer()}}this.cycle++;const t=(input.down?6:12)*Math.cos(.09*simulation.cycle),e=Vector.mult(s,t*Math.cos(.36*this.cycle)),o=Vector.mult(player.velocity,.4);Matter.Body.setPosition(this,Vector.add(o,Vector.add(this.position,e)))}}}),Composite.add(engine.world,bullet[o]),Matter.Body.setVelocity(bullet[o],{x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)});const s=Vector.normalise(Vector.perp(bullet[o].velocity));(180-Math.abs(Math.abs(b.lastAngle-m.angle)-180)>.13||!b.wasExtruderOn)&&(bullet[o].isBranch=!0,bullet[o].do=function(){this.endCycle<simulation.cycle+1&&(this.isWave=!1)}),b.lastAngle=m.angle}else b.canExtruderFire=!1},plasma(){const t=.0011;if(m.energy>t){let e;m.energy-=t,m.energy<0&&(m.fieldCDcycle=m.cycle+120,m.energy=0);let o=tech.isPlasmaRange*(120+(input.down?400:300)*Math.sqrt(Math.random()));const i=[{x:m.pos.x+20*Math.cos(m.angle),y:m.pos.y+20*Math.sin(m.angle)},{x:m.pos.x+o*Math.cos(m.angle),y:m.pos.y+o*Math.sin(m.angle)}],s=function(t,o,i){for(let s=0;s<i.length;++s){let a=i[s].vertices;const l=a.length-1;for(let n=0;n<l;n++)if(results=simulation.checkLineIntersection(t,o,a[n],a[n+1]),results.onLine1&&results.onLine2){const o=t.x-results.x,l=t.y-results.y,r=o*o+l*l;r<e.dist2&&(!i[s].mob||i[s].alive)&&(e={x:results.x,y:results.y,dist2:r,who:i[s],v1:a[n],v2:a[n+1]})}if(results=simulation.checkLineIntersection(t,o,a[0],a[l]),results.onLine1&&results.onLine2){const o=t.x-results.x,n=t.y-results.y,r=o*o+n*n;r<e.dist2&&(!i[s].mob||i[s].alive)&&(e={x:results.x,y:results.y,dist2:r,who:i[s],v1:a[0],v2:a[l]})}}};if(e={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null},s(i[0],i[1],mob),s(i[0],i[1],map),s(i[0],i[1],body),e.dist2!=1/0)if(i[i.length-1]={x:e.x,y:e.y},e.who.alive){const t=.8*b.dmgScale;e.who.damage(t),e.who.locatePlayer();const o=Vector.mult(Vector.normalise(Vector.sub(m.pos,i[1])),-.01*Math.min(5,e.who.mass));Matter.Body.applyForce(e.who,i[1],o),Matter.Body.setVelocity(e.who,{x:.7*e.who.velocity.x,y:.7*e.who.velocity.y}),simulation.drawList.push({x:i[1].x,y:i[1].y,radius:Math.sqrt(2e3*t*e.who.damageReduction),color:"rgba(255,0,255,0.2)",time:4*simulation.drawTime})}else if(!e.who.isStatic){const t=Vector.mult(Vector.normalise(Vector.sub(m.pos,i[1])),-.007*Math.sqrt(Math.sqrt(e.who.mass)));Matter.Body.applyForce(e.who,i[1],t)}ctx.strokeStyle="rgba(255,0,255,0.1)",ctx.lineWidth=14,ctx.beginPath(),ctx.moveTo(i[0].x,i[0].y),ctx.lineTo(i[1].x,i[1].y),ctx.stroke(),ctx.strokeStyle="#f0f",ctx.lineWidth=2,ctx.stroke();const a=Math.cos(m.angle),l=Math.sin(m.angle);let n=m.pos.x+20*a,r=m.pos.y+20*l;ctx.beginPath(),ctx.moveTo(n,r);const c=Vector.magnitude(Vector.sub(i[0],i[1]))/10;for(let t=0;t<8;t++)n+=c*(a+1.5*(Math.random()-.5)),r+=c*(l+1.5*(Math.random()-.5)),ctx.lineTo(n,r);ctx.lineWidth=2*Math.random(),ctx.stroke()}},laser(t={x:m.pos.x+20*Math.cos(m.angle),y:m.pos.y+20*Math.sin(m.angle)},e={x:t.x+3e3*Math.cos(m.angle),y:t.y+3e3*Math.sin(m.angle)},o=tech.laserDamage,i=tech.laserReflections,s=!1,a=1){const l=1-1/(1.5*i);let n=b.dmgScale*o,r={x:1,y:1,dist2:1/0,who:null,v1:1,v2:1};const c=[{x:t.x,y:t.y},{x:e.x,y:e.y}],h=function(t,e,o){for(let i=0;i<o.length;++i){let s=o[i].vertices;const a=s.length-1;for(let l=0;l<a;l++)if(results=simulation.checkLineIntersection(t,e,s[l],s[l+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,a=t.y-results.y,n=e*e+a*a;n<r.dist2&&(!o[i].mob||o[i].alive)&&(r={x:results.x,y:results.y,dist2:n,who:o[i],v1:s[l],v2:s[l+1]})}if(results=simulation.checkLineIntersection(t,e,s[0],s[a]),results.onLine1&&results.onLine2){const e=t.x-results.x,l=t.y-results.y,n=e*e+l*l;n<r.dist2&&(!o[i].mob||o[i].alive)&&(r={x:results.x,y:results.y,dist2:n,who:o[i],v1:s[0],v2:s[a]})}}},d=function(){r={x:1,y:1,dist2:1/0,who:null,v1:1,v2:1},h(c[c.length-2],c[c.length-1],mob),h(c[c.length-2],c[c.length-1],map),h(c[c.length-2],c[c.length-1],body)},u=function(){if(r.who.alive){if(r.who.damage(n),r.who.locatePlayer(),r.who.damageReduction&&simulation.drawList.push({x:c[c.length-1].x,y:c[c.length-1].y,radius:Math.sqrt(2e3*n*r.who.damageReduction)+2,color:tech.laserColorAlpha,time:simulation.drawTime}),tech.isLaserPush){const t=c.length-1;Matter.Body.setVelocity(r.who,{x:.94*r.who.velocity.x,y:.94*r.who.velocity.y});const e=Vector.mult(Vector.normalise(Vector.sub(c[t],c[Math.max(0,t-1)])),.006*a*Math.min(6,r.who.mass));Matter.Body.applyForce(r.who,c[t],e)}}else if(tech.isLaserPush&&"body"===r.who.classType){const t=c.length-1;Matter.Body.setVelocity(r.who,{x:.94*r.who.velocity.x,y:.94*r.who.velocity.y});const e=Vector.mult(Vector.normalise(Vector.sub(c[t],c[Math.max(0,t-1)])),.006*a*Math.min(6,r.who.mass));Matter.Body.applyForce(r.who,c[t],e)}},y=function(){const t=Vector.perp(Vector.normalise(Vector.sub(r.v1,r.v2))),e=Vector.sub(c[c.length-1],c[c.length-2]),o=Vector.mult(t,2*Vector.dot(e,t)),i=Vector.normalise(Vector.sub(e,o));c[c.length]=Vector.add(Vector.mult(i,3e3),c[c.length-1])};let p;d();let g=r.who;if(r.dist2!==1/0){c[c.length-1]={x:r.x,y:r.y},u();for(let t=0;t<i&&(y(),d(),r.dist2!==1/0);t++)if(lastReflection=r,c[c.length-1]={x:r.x,y:r.y},n*=l,u(),t%2){if(p===r.who)break}else if(p=r.who,g===r.who)break}if(s)for(let t=1,e=c.length;t<e;++t)ctx.moveTo(c[t-1].x,c[t-1].y),ctx.lineTo(c[t].x,c[t].y);else{ctx.strokeStyle=tech.laserColor,ctx.lineWidth=2,ctx.lineDashOffset=900*Math.random(),ctx.setLineDash([50+120*Math.random(),50*Math.random()]);for(let t=1,e=c.length;t<e;++t)ctx.beginPath(),ctx.moveTo(c[t-1].x,c[t-1].y),ctx.lineTo(c[t].x,c[t].y),ctx.stroke(),ctx.globalAlpha*=l;ctx.setLineDash([]),ctx.globalAlpha=1}},AoEStunEffect(t,e,o=150+120*Math.random()){for(let i=0,s=mob.length;i<s;++i)!mob[i].alive||mob[i].isShielded||mob[i].shield||mob[i].isBadTarget||Vector.magnitude(Vector.sub(t,mob[i].position))-mob[i].radius<e&&mobs.statusStun(mob[i],o);simulation.drawList.push({x:t.x,y:t.y,radius:e,color:"rgba(0,0,0,0.1)",time:15})},laserMine(t,e={x:0,y:-8}){const o=bullet.length;bullet[o]=Bodies.polygon(t.x,t.y,3,25,{bulletType:"laser mine",angle:m.angle,friction:0,frictionAir:.025,restitution:.5,dmg:0,minDmgSpeed:2,lookFrequency:67+Math.floor(7*Math.random()),drain:.62*tech.isLaserDiode*tech.laserFieldDrain,isDetonated:!1,torqueMagnitude:3e-6*(Math.round(Math.random())?1:-1),range:1500,endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},beforeDmg(){},onEnd(){},do(){if(!(simulation.cycle%this.lookFrequency)&&m.energy>this.drain)for(let t=0,e=mob.length;t<e;++t)if(Vector.magnitude(Vector.sub(this.position,mob[t].position))<1300&&!mob[t].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[t].position).length&&0===Matter.Query.ray(body,this.position,mob[t].position).length){tech.isMineStun&&b.AoEStunEffect(this.position,1300),this.do=this.laserSpin,this.angularSpeed<.5&&(this.torque+=this.inertia*this.torqueMagnitude*200),this.endCycle=simulation.cycle+360+120,this.isDetonated=!0;break}},reflections:Math.max(0,tech.laserReflections-2),laserSpin(){if(m.energy>this.drain){m.energy-=this.drain,this.angularSpeed<.05&&(this.torque+=this.inertia*this.torqueMagnitude),ctx.strokeStyle=tech.laserColor,ctx.lineWidth=1.5,ctx.beginPath();for(let t=0;t<3;t++){const e=this.vertices[t],o=Vector.add(e,Vector.mult(Vector.normalise(Vector.sub(e,this.position)),2500));b.laser(e,o,13*tech.laserDamage,this.reflections,!0)}ctx.stroke()}this.endCycle-60<simulation.cycle&&(this.do=()=>{})}}),Matter.Body.setVelocity(bullet[o],e),Composite.add(engine.world,bullet[o])},mine(t,e,o=0){const i=bullet.length;bullet[i]=Bodies.rectangle(t.x,t.y,45,16,{angle:o,friction:1,frictionStatic:1,frictionAir:0,restitution:0,dmg:0,classType:"bullet",bulletType:"mine",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:5,stillCount:0,isArmed:!1,endCycle:1/0,lookFrequency:0,range:700,beforeDmg(){},onEnd(){this.isArmed&&b.targetedNail(this.position,tech.isMineSentry?7:22,40+10*Math.random(),1200,!0,2.2)},do(){this.force.y+=.002*this.mass;let t=Matter.Query.collides(this,map);if(t.length>0){for(let e=0;e<t.length;e++)if(t[e].bodyA.collisionFilter.category===cat.map){const o=Vector.angle(t[e].normal,{x:1,y:0});Matter.Body.setAngle(this,Math.atan2(t[e].tangent.y,t[e].tangent.x));for(let i=0;i<10;i++){if(Matter.Query.collides(this,map).length>0){o>-.2||o<-1.5?(Matter.Body.setVelocity(this,{x:0,y:0}),Matter.Body.setStatic(this,!0),this.collisionFilter.category=0,this.collisionFilter.mask=0):(Matter.Body.setVelocity(this,{x:0,y:0}),Matter.Body.setAngularVelocity(this,0)),this.arm();const t=this;setTimeout((function(){(0===Matter.Query.collides(t,map).length||Matter.Query.point(map,t.position).length>0)&&(t.endCycle=0,t.isArmed=!1,b.mine(t.position,t.velocity,t.angle))}),100,t);break}Matter.Body.setPosition(this,Vector.add(this.position,Vector.mult(t[e].normal,2)))}break}}else this.speed<1&&this.angularSpeed<.01&&!m.isBodiesAsleep&&this.stillCount++;this.stillCount>25&&this.arm()},arm(){this.collisionFilter.mask=cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield|cat.bullet,this.lookFrequency=simulation.cycle+60,this.do=function(){this.force.y+=.002*this.mass,simulation.cycle>this.lookFrequency&&(this.isArmed=!0,this.lookFrequency=55+Math.floor(22*Math.random()),simulation.drawList.push({x:this.position.x,y:this.position.y,radius:10,color:"#f00",time:4}),this.do=function(){if(this.force.y+=.002*this.mass,!(simulation.cycle%this.lookFrequency)){const t=300*Math.random();for(let e=0,o=mob.length;e<o;++e)if(!mob[e].isBadTarget&&Vector.magnitude(Vector.sub(this.position,mob[e].position))<700+mob[e].radius+t&&0===Matter.Query.ray(map,this.position,mob[e].position).length&&0===Matter.Query.ray(body,this.position,mob[e].position).length){if(tech.isMineStun&&b.AoEStunEffect(this.position,700+mob[e].radius+t),tech.isMineSentry){this.lookFrequency=8+Math.floor(3*Math.random()),this.endCycle=simulation.cycle+1020,this.do=function(){this.force.y+=.002*this.mass,simulation.cycle%this.lookFrequency||m.isBodiesAsleep||(b.targetedNail(this.position,1,45+5*Math.random(),1100,!1,2.3),simulation.cycle%(6*this.lookFrequency)||simulation.drawList.push({x:this.position.x,y:this.position.y,radius:8,color:"#fe0",time:4}))};break}this.endCycle=0;break}}})}}}),bullet[i].torque+=2e-4*bullet[i].inertia*(.5-Math.random()),Matter.Body.setVelocity(bullet[i],e),Composite.add(engine.world,bullet[i])},worm(t,e=tech.isSporeFreeze){const o=bullet.length,i=6+7.2*tech.wormSize*Math.random();if(o<500){bullet[o]=Bodies.polygon(t.x,t.y,3,3,{inertia:1/0,isFreeze:e,restitution:.5,friction:0,frictionAir:.025,thrust:(tech.isFastSpores?.001:5e-4)*(1+.5*(Math.random()-.5)),wormSize:i,wormTail:1+i,dmg:(tech.isMutualism?7:2.9)*i,lookFrequency:100+Math.floor(37*Math.random()),classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.mob|cat.mobBullet|cat.mobShield},endCycle:simulation.cycle+Math.floor((600+Math.floor(420*Math.random()))*tech.isBulletsLastLonger),minDmgSpeed:0,playerOffPosition:{x:100*(Math.random()-.5),y:100*(Math.random()-.5)},beforeDmg(t){tech.wormSurviveDmg&&t.alive?setTimeout((()=>{t.alive?this.endCycle=0:this.endCycle=simulation.cycle+Math.floor((600+Math.floor(420*Math.random()))*tech.isBulletsLastLonger)}),1):this.endCycle=0,this.isFreeze&&mobs.statusSlow(t,90)},onEnd(){tech.isMutualism&&this.isMutualismActive&&!tech.isEnergyHealth&&(m.health+=.01,m.health>m.maxHealth&&(m.health=m.maxHealth),m.displayHealth())},do(){ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y);const t=Vector.mult(Vector.normalise(this.velocity),-Math.min(100,this.wormTail*this.speed)),e=Vector.add(this.position,t);if(ctx.lineTo(e.x,e.y),ctx.lineWidth=this.wormSize,ctx.strokeStyle="#000",ctx.stroke(),this.lockedOn&&this.lockedOn.alive)this.force=Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position,this.position)),this.mass*this.thrust);else{if(!(simulation.cycle%this.lookFrequency)){this.closestTarget=null,this.lockedOn=null;let t=1/0;for(let e=0,o=mob.length;e<o;++e)if(!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length){const o=Vector.sub(this.position,mob[e].position),i=Vector.magnitude(o)*(Math.random()+.5);if(i<t&&(this.closestTarget=mob[e].position,t=i,this.lockedOn=mob[e],.3>Math.random()))break}}if(tech.isSporeFollow&&null===this.lockedOn){const t=this.position.x-m.pos.x,e=this.position.y-m.pos.y;t*t+e*e>1e4&&(this.force=Vector.mult(Vector.normalise(Vector.sub(m.pos,Vector.add(this.playerOffPosition,this.position))),this.mass*this.thrust))}else{const t=Vector.normalise(this.velocity),e=Vector.mult(Vector.rotate(t,.005*this.playerOffPosition.x),3e-6);this.force.x+=e.x,this.force.y+=e.y}}}});const s=2+1*Math.random(),a=2*Math.PI*Math.random();Matter.Body.setVelocity(bullet[o],{x:s*Math.cos(a),y:s*Math.sin(a)}),Composite.add(engine.world,bullet[o]),tech.isMutualism&&m.health>.02&&(m.health-=.01,m.displayHealth(),bullet[o].isMutualismActive=!0)}},spore(t,e=tech.isSporeFreeze){const o=bullet.length;if(o<500){bullet[o]=Bodies.polygon(t.x,t.y,4,4,{inertia:1/0,isFreeze:e,restitution:.5,angle:2*Math.random()*Math.PI,friction:0,frictionAir:.025,thrust:(tech.isFastSpores?9e-4:45e-5)*(1+.3*(Math.random()-.5)),dmg:tech.isMutualism?16.8:7,lookFrequency:100+Math.floor(117*Math.random()),classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.mob|cat.mobBullet|cat.mobShield},endCycle:simulation.cycle+Math.floor((540+Math.floor(420*Math.random()))*tech.isBulletsLastLonger),minDmgSpeed:0,playerOffPosition:{x:100*(Math.random()-.5),y:100*(Math.random()-.5)},beforeDmg(t){this.endCycle=0,this.isFreeze&&mobs.statusSlow(t,90)},onEnd(){tech.isMutualism&&this.isMutualismActive&&!tech.isEnergyHealth&&(m.health+=.005,m.health>m.maxHealth&&(m.health=m.maxHealth),m.displayHealth())},do(){if(this.lockedOn&&this.lockedOn.alive)this.force=Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position,this.position)),this.mass*this.thrust);else{if(!(simulation.cycle%this.lookFrequency)){this.closestTarget=null,this.lockedOn=null;let t=1/0;for(let e=0,o=mob.length;e<o;++e)if(!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length){const o=Vector.sub(this.position,mob[e].position),i=Vector.magnitude(o)*(Math.random()+.5);if(i<t&&(this.closestTarget=mob[e].position,t=i,this.lockedOn=mob[e],.3>Math.random()))break}}if(tech.isSporeFollow&&null===this.lockedOn){const t=this.position.x-m.pos.x,e=this.position.y-m.pos.y;t*t+e*e>1e4&&(this.force=Vector.mult(Vector.normalise(Vector.sub(m.pos,Vector.add(this.playerOffPosition,this.position))),this.mass*this.thrust))}else this.force.y+=1e-4*this.mass}}});const i=4+8*Math.random(),s=2*Math.PI*Math.random();Matter.Body.setVelocity(bullet[o],{x:i*Math.cos(s),y:i*Math.sin(s)}),Composite.add(engine.world,bullet[o]),tech.isMutualism&&m.health>.01&&(m.health-=.005,m.displayHealth(),bullet[o].isMutualismActive=!0)}},iceIX(t=0,e=m.angle+2*Math.PI*Math.random(),o={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)}){const i=bullet.length,s=9e-4,a=1-.08/tech.isBulletsLastLonger;bullet[i]=Bodies.polygon(o.x,o.y,3,18,{angle:e-Math.PI,inertia:1/0,friction:0,frictionAir:.023,restitution:.9,dmg:1,lookFrequency:14+Math.floor(8*Math.random()),endCycle:simulation.cycle+100*tech.isBulletsLastLonger+Math.floor(25*Math.random()),classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:0,lockedOn:null,isFollowMouse:!0,beforeDmg(t){mobs.statusSlow(t,180),this.endCycle=simulation.cycle,tech.iceEnergy&&!t.shield&&!t.isShielded&&t.isDropPowerUp&&t.alive&&m.immuneCycle<m.cycle&&setTimeout((()=>{t.alive||(m.energy+=.8*tech.iceEnergy)}),10)},onEnd(){},do(){if(!(simulation.cycle%this.lookFrequency)){Matter.Body.scale(this,a,a),this.lockedOn=null;let t=1/0;for(let e=0,o=mob.length;e<o;++e)if(!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length&&0===Matter.Query.ray(body,this.position,mob[e].position).length){const o=Vector.sub(this.position,mob[e].position),i=Vector.magnitude(o);i<t&&(t=i,this.lockedOn=mob[e])}}this.lockedOn?this.force=Vector.mult(Vector.normalise(Vector.sub(this.position,this.lockedOn.position)),-this.mass*s):this.force=Vector.mult(Vector.normalise(this.velocity),this.mass*s)}}),Composite.add(engine.world,bullet[i]),Matter.Body.setVelocity(bullet[i],{x:t*Math.cos(e),y:t*Math.sin(e)})},drone(t={x:m.pos.x+30*Math.cos(m.angle)+20*(Math.random()-.5),y:m.pos.y+30*Math.sin(m.angle)+20*(Math.random()-.5)},e=1){const o=bullet.length,i=.0015,s=m.angle+.4*(Math.random()-.5),a=4.5+3*Math.random();bullet[o]=Bodies.polygon(t.x,t.y,8,a,{angle:s,inertia:1/0,friction:.05,frictionAir:0,restitution:1,density:5e-4,dmg:.34+.12*tech.isDroneTeleport+.15*tech.isDroneFastLook,lookFrequency:(tech.isDroneFastLook?20:70)+Math.floor(17*Math.random()),endCycle:simulation.cycle+Math.floor((950+400*Math.random())*tech.isBulletsLastLonger*tech.droneCycleReduction)+5*a+Math.max(0,150-bullet.length),classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:0,lockedOn:null,isFollowMouse:!0,deathCycles:110+5*a,isImproved:!1,beforeDmg(t){if(tech.isIncendiary&&simulation.cycle+this.deathCycles<this.endCycle){const t=Math.max(Math.min(this.endCycle-simulation.cycle-this.deathCycles,1500),0);b.explosion(this.position,.1*t+110*this.isImproved+60*Math.random()),tech.isForeverDrones?(this.endCycle=0,b.drone({x:m.pos.x+30*(Math.random()-.5),y:m.pos.y+30*(Math.random()-.5)},5),bullet[bullet.length-1].endCycle=1/0):this.endCycle-=t}else{const e=Vector.mult(Vector.normalise(Vector.sub(this.position,t.position)),-20);Matter.Body.setVelocity(this,{x:e.x,y:e.y}),this.lockedOn=null,this.endCycle>simulation.cycle+this.deathCycles&&(this.endCycle-=60,simulation.cycle+this.deathCycles>this.endCycle&&(this.endCycle=simulation.cycle+this.deathCycles))}},onEnd(){if(tech.isDroneRespawn&&b.inventory.length){const t=b.guns[b.activeGun];"drones"===t.name&&t.ammo>0&&mob.length&&(b.drone({x:this.position.x,y:this.position.y},0),Math.random()<.25&&(b.guns[b.activeGun].ammo--,simulation.updateGunHUD()))}},do(){if(simulation.cycle+this.deathCycles>this.endCycle){this.force.y+=.0012*this.mass,this.restitution=.2;const t=.995;Matter.Body.scale(this,t,t)}else{if(this.force.y+=2e-4*this.mass,!(simulation.cycle%this.lookFrequency)){this.lockedOn=null;let t=1/0;for(let e=0,o=mob.length;e<o;++e)if(!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length&&0===Matter.Query.ray(body,this.position,mob[e].position).length){const o=Vector.sub(this.position,mob[e].position),i=Vector.magnitude(o);i<t&&(t=i,this.lockedOn=mob[e])}if(tech.isDroneTeleport&&this.lockedOn){const t=Vector.sub(this.lockedOn.position,this.position),e=Vector.magnitude(t),o=Vector.normalise(t);Matter.Body.setVelocity(this,Vector.mult(o,Math.max(20,1.5*this.speed))),ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),Matter.Body.translate(this,Vector.mult(o,Math.min(350,e-this.lockedOn.radius+10))),ctx.lineTo(this.position.x,this.position.y),ctx.lineWidth=2*a,ctx.strokeStyle="rgba(0,0,0,0.5)",ctx.stroke()}if(!this.isImproved&&!simulation.isChoosing&&!tech.isExtraMaxEnergy)if(this.lockedOn){for(let t=0,e=powerUp.length;t<e;++t)if(Vector.magnitudeSquared(Vector.sub(this.position,powerUp[t].position))<2e4&&("heal"!==powerUp[t].name||m.health<.94*m.maxHealth||tech.isDroneGrab)&&("field"!==powerUp[t].name||!tech.isSuperDeterminism)){if(ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(powerUp[t].position.x,powerUp[t].position.y),ctx.strokeStyle="#000",ctx.lineWidth=4,ctx.stroke(),powerUps.onPickUp(powerUp[t]),powerUp[t].effect(),Matter.Composite.remove(engine.world,powerUp[t]),powerUp.splice(t,1),tech.isDroneGrab){this.isImproved=!0;const t=2.25;Matter.Body.scale(this,t,t),this.lookFrequency=30+Math.floor(11*Math.random()),this.endCycle+=3e3*tech.droneCycleReduction*tech.isBulletsLastLonger}break}}else{let t=1/0;for(let e=0,o=powerUp.length;e<o;++e)if(("heal"!==powerUp[e].name||m.health<.94*m.maxHealth||tech.isDroneGrab)&&("field"!==powerUp[e].name||!tech.isSuperDeterminism)){if(Vector.magnitudeSquared(Vector.sub(this.position,powerUp[e].position))<2e4&&!simulation.isChoosing){if(ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(powerUp[e].position.x,powerUp[e].position.y),ctx.strokeStyle="#000",ctx.lineWidth=4,ctx.stroke(),powerUps.onPickUp(powerUp[e]),powerUp[e].effect(),Matter.Composite.remove(engine.world,powerUp[e]),powerUp.splice(e,1),tech.isDroneGrab){this.isImproved=!0;const t=2.25;Matter.Body.scale(this,t,t),this.lookFrequency=30+Math.floor(11*Math.random()),this.endCycle+=3e3*tech.droneCycleReduction*tech.isBulletsLastLonger}break}if(0===Matter.Query.ray(map,this.position,powerUp[e].position).length&&0===Matter.Query.ray(body,this.position,powerUp[e].position).length){const o=Vector.sub(this.position,powerUp[e].position),i=Vector.magnitude(o);i<t&&(t=i,this.lockedOn=powerUp[e])}}}}this.lockedOn?this.force=Vector.mult(Vector.normalise(Vector.sub(this.position,this.lockedOn.position)),-this.mass*i):this.force=Vector.mult(Vector.normalise(Vector.sub(this.position,simulation.mouseInGame)),-this.mass*i),this.speed>6&&Matter.Body.setVelocity(this,{x:.97*this.velocity.x,y:.97*this.velocity.y})}}}),Composite.add(engine.world,bullet[o]),Matter.Body.setVelocity(bullet[o],{x:e*Math.cos(s),y:e*Math.sin(s)})},droneRadioactive(t={x:m.pos.x+30*Math.cos(m.angle)+20*(Math.random()-.5),y:m.pos.y+30*Math.sin(m.angle)+20*(Math.random()-.5)},e=1){const o=bullet.length,i=(tech.isFastDrones?.003:.0012)+5e-4*(Math.random()-.5),s=m.angle+.4*(Math.random()-.5);bullet[o]=Bodies.polygon(t.x,t.y,8,3,{angle:s,inertia:1/0,friction:0,frictionAir:0,restitution:.4+.199*Math.random(),dmg:0,lookFrequency:120+Math.floor(23*Math.random()),endCycle:simulation.cycle+Math.floor((900+110*Math.random())*tech.isBulletsLastLonger/tech.droneRadioDamage)+15+Math.max(0,150-2*bullet.length),classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:0,speedCap:5+2*Math.random(),lockedOn:null,isFollowMouse:!0,deathCycles:125,isImproved:!1,radioRadius:0,maxRadioRadius:300+Math.floor(100*Math.random()),beforeDmg(){},onEnd(){if(tech.isDroneRespawn){const t=b.guns[b.activeGun];"drones"===t.name&&t.ammo>0&&mob.length&&(b.droneRadioactive({x:this.position.x,y:this.position.y},0),Math.random()<.25&&(b.guns[b.activeGun].ammo--,simulation.updateGunHUD()))}},do(){if(this.radioRadius=.993*this.radioRadius+.007*this.maxRadioRadius,Vector.magnitude(Vector.sub(player.position,this.position))<this.radioRadius){const t=tech.isRadioactiveResistance?5e-4:.002;m.energy>t?m.immuneCycle<m.cycle&&(m.energy-=t):(m.energy=0,simulation.dmgScale&&m.damage(tech.isRadioactiveResistance?375e-7:15e-5))}for(let t=0,e=mob.length;t<e;t++)if(Vector.magnitude(Vector.sub(mob[t].position,this.position))<this.radioRadius+mob[t].radius){let e=(.12+.04*tech.isFastDrones)*b.dmgScale*tech.droneRadioDamage;Matter.Query.ray(map,mob[t].position,this.position).length>0&&(e*=.25),mob[t].shield&&(e*=3),mob[t].damage(e),mob[t].locatePlayer()}if(ctx.beginPath(),ctx.arc(this.position.x,this.position.y,this.radioRadius,0,2*Math.PI),ctx.globalCompositeOperation="lighter",ctx.fillStyle=`rgba(28, 175, 217,${.13+.07*Math.random()})`,ctx.fill(),ctx.globalCompositeOperation="source-over",simulation.cycle+this.deathCycles>this.endCycle){this.force.y+=.0012*this.mass,this.restitution=.2;const t=.995;Matter.Body.scale(this,t,t),this.maxRadioRadius=0,this.radioRadius=.98*this.radioRadius}else{if(this.force.y+=2e-4*this.mass,!(simulation.cycle%this.lookFrequency)){this.lockedOn=null;let t=1/0;for(let e=0,o=mob.length;e<o;++e)if(!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length&&0===Matter.Query.ray(body,this.position,mob[e].position).length){const o=Vector.sub(this.position,mob[e].position),i=Vector.magnitude(o);i<t&&(t=i,this.lockedOn=mob[e])}if(!this.isImproved&&!simulation.isChoosing&&!tech.isExtraMaxEnergy)if(this.lockedOn){for(let t=0,e=powerUp.length;t<e;++t)if(Vector.magnitudeSquared(Vector.sub(this.position,powerUp[t].position))<2e4&&("heal"!==powerUp[t].name||m.health<.94*m.maxHealth||tech.isDroneGrab)&&("field"!==powerUp[t].name||!tech.isSuperDeterminism)){if(ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(powerUp[t].position.x,powerUp[t].position.y),ctx.strokeStyle="#000",ctx.lineWidth=4,ctx.stroke(),powerUps.onPickUp(powerUp[t]),powerUp[t].effect(),Matter.Composite.remove(engine.world,powerUp[t]),powerUp.splice(t,1),tech.isDroneGrab){this.isImproved=!0;const t=2.25;Matter.Body.scale(this,t,t),this.lookFrequency=30+Math.floor(11*Math.random()),this.endCycle+=1e3*tech.isBulletsLastLonger,this.maxRadioRadius*=1.25}break}}else{let t=1/0;for(let e=0,o=powerUp.length;e<o;++e)if(("heal"!==powerUp[e].name||m.health<.94*m.maxHealth||tech.isDroneGrab)&&("field"!==powerUp[e].name||!tech.isSuperDeterminism)){if(Vector.magnitudeSquared(Vector.sub(this.position,powerUp[e].position))<2e4&&!simulation.isChoosing){if(ctx.beginPath(),ctx.moveTo(this.position.x,this.position.y),ctx.lineTo(powerUp[e].position.x,powerUp[e].position.y),ctx.strokeStyle="#000",ctx.lineWidth=4,ctx.stroke(),powerUps.onPickUp(powerUp[e]),powerUp[e].effect(),Matter.Composite.remove(engine.world,powerUp[e]),powerUp.splice(e,1),tech.isDroneGrab){this.isImproved=!0;const t=2.25;Matter.Body.scale(this,t,t),this.lookFrequency=30+Math.floor(11*Math.random()),this.endCycle+=1e3*tech.isBulletsLastLonger,this.maxRadioRadius*=1.25}break}if(0===Matter.Query.ray(map,this.position,powerUp[e].position).length&&0===Matter.Query.ray(body,this.position,powerUp[e].position).length){const o=Vector.sub(this.position,powerUp[e].position),i=Vector.magnitude(o);i<t&&(t=i,this.lockedOn=powerUp[e])}}}}this.lockedOn?this.force=Vector.mult(Vector.normalise(Vector.sub(this.position,this.lockedOn.position)),-this.mass*i):this.force=Vector.mult(Vector.normalise(Vector.sub(this.position,simulation.mouseInGame)),-this.mass*i),this.speed>this.speedCap&&Matter.Body.setVelocity(this,{x:.97*this.velocity.x,y:.97*this.velocity.y})}}}),Composite.add(engine.world,bullet[o]),Matter.Body.setVelocity(bullet[o],{x:e*Math.cos(s),y:e*Math.sin(s)})},foam(t,e,o){const i=bullet.length;bullet[i]=Bodies.polygon(t.x,t.y,20,o,{density:1e-6,inertia:1/0,frictionAir:.003,dmg:0,damage:(tech.isFastFoam?.0275:.011)*(tech.isBulletTeleport?1.43:1),scale:1-.006/tech.isBulletsLastLonger*(tech.isFastFoam?1.65:1),classType:"bullet",collisionFilter:{category:cat.bullet,mask:cat.mob|cat.mobBullet},minDmgSpeed:0,endCycle:1/0,count:0,radius:o,target:null,targetVertex:null,targetRelativePosition:null,portFrequency:5+Math.floor(5*Math.random()),nextPortCycle:1/0,beforeDmg(t){if(!this.target&&t.alive){if(this.target=t,t.radius<20)this.targetRelativePosition={x:0,y:0};else if(Matter.Query.collides(this,[t]).length>0){const e=Matter.Query.collides(this,[t])[0].normal;this.targetRelativePosition=Vector.rotate(Vector.sub(Vector.sub(this.position,t.position),Vector.mult(e,-this.radius)),-t.angle)}else this.targetRelativePosition=Vector.rotate(Vector.sub(this.position,t.position),-t.angle);this.collisionFilter.category=cat.body,this.collisionFilter.mask=null;let e=1/0,o=null;for(let t=0;t<this.target.vertices.length;t++){const i=Vector.magnitude(Vector.sub(this.position,this.target.vertices[t]));i<e&&(o=t,e=i)}this.targetVertex=o}},onEnd(){},do(){if(!m.isBodiesAsleep){if(this.count<20){this.count++;const t=1.06;Matter.Body.scale(this,t,t),this.radius*=t}else Matter.Body.scale(this,this.scale,this.scale),this.radius*=this.scale,this.radius<8&&(this.endCycle=0);if(this.target&&this.target.alive){const t=Vector.rotate(this.targetRelativePosition,this.target.angle);if(this.target.isVerticesChange?Matter.Body.setPosition(this,this.target.vertices[this.targetVertex]):Matter.Body.setPosition(this,Vector.add(Vector.add(t,this.target.velocity),this.target.position)),Matter.Body.setVelocity(this.target,Vector.mult(this.target.velocity,.9)),Matter.Body.setAngularVelocity(this.target,.9*this.target.angularVelocity),this.target.isShielded){this.target.damage(b.dmgScale*this.damage,!0);const t=1-.004/tech.isBulletsLastLonger;Matter.Body.scale(this,t,t),this.radius*=t}else this.target.damage(b.dmgScale*this.damage)}else if(null!==this.target){if(this.target=null,this.collisionFilter.category=cat.bullet,this.collisionFilter.mask=cat.mob,tech.isFoamGrowOnDeath&&bullet.length<180){let t=[];for(let e=0,o=mob.length;e<o;e++){Vector.magnitudeSquared(Vector.sub(this.position,mob[e].position))<1e6&&t.push(mob[e])}const e=Math.min(.5*this.radius,9),o=bullet.length<80?2:1;for(let i=0;i<o;i++)if(t.length-i>0){const o=Math.floor(Math.random()*t.length),i=6+6*Math.random(),s=Vector.mult(Vector.normalise(Vector.sub(t[o].position,this.position)),i);b.foam(this.position,Vector.rotate(s,.5*(Math.random()-.5)),e)}else b.foam(this.position,Vector.rotate({x:15+10*Math.random(),y:0},2*Math.PI*Math.random()),e)}}else if(Matter.Query.point(map,this.position).length>0){const t=.85;Matter.Body.setVelocity(this,{x:this.velocity.x*t,y:this.velocity.y*t});const e=.96;Matter.Body.scale(this,e,e),this.radius*=e}else if(Matter.Query.point(body,this.position).length>0){const t=.9;Matter.Body.setVelocity(this,{x:this.velocity.x*t,y:this.velocity.y*t});const e=.96;Matter.Body.scale(this,e,e),this.radius*=e}else if(this.force.y+=this.mass*tech.foamGravity,tech.isFoamAttract)for(let t=0,e=mob.length;t<e;t++)if(!mob[t].isBadTarget&&Vector.magnitude(Vector.sub(mob[t].position,this.position))<375&&mob[t].alive&&0===Matter.Query.ray(map,this.position,mob[t].position).length){this.force=Vector.mult(Vector.normalise(Vector.sub(mob[t].position,this.position)),.004*this.mass);const e=.9;Matter.Body.setVelocity(this,{x:this.velocity.x*e,y:this.velocity.y*e});break}if(this.nextPortCycle<simulation.cycle){this.nextPortCycle=simulation.cycle+this.portFrequency;const t=15*Math.sqrt(this.radius)*Math.random();Matter.Body.setPosition(this,Vector.add(this.position,Vector.rotate({x:t,y:0},2*Math.PI*Math.random())))}}}}),tech.isBulletTeleport&&(bullet[i].nextPortCycle=simulation.cycle+bullet[i].portFrequency),Composite.add(engine.world,bullet[i]),Matter.Body.setVelocity(bullet[i],e)},targetedBlock(t,e=!1,o=50-Math.min(20,2*t.mass),i=1600){let s,a;for(let e=0,o=mob.length;e<o;e++)t!==mob[e]&&(a=Vector.magnitude(Vector.sub(t.position,mob[e].position)),a<i&&0===Matter.Query.ray(map,t.position,mob[e].position).length&&(s=mob[e],i=a));if(s){const e=Vector.add(s.position,Vector.mult(s.velocity,a/60)),i=Vector.mult(Vector.normalise(Vector.sub(e,t.position)),o);i.y-=Math.abs(t.position.x-s.position.x)/150,Matter.Body.setVelocity(t,i)}},targetedNail(t,e=1,o=40+10*Math.random(),i=1200,s=!0,a=1.4){const l=[];for(let e=0,o=mob.length;e<o;e++){const o=Vector.magnitude(Vector.sub(t,mob[e].position));o<i+mob[e].radius&&!mob[e].isBadTarget&&0===Matter.Query.ray(map,t,mob[e].position).length&&0===Matter.Query.ray(body,t,mob[e].position).length&&l.push(Vector.add(mob[e].position,Vector.mult(mob[e].velocity,o/60)))}for(let i=0;i<e;i++)if(l.length>0){const e=Math.floor(Math.random()*l.length),i=150/l.length,s={x:l[e].x+i*(Math.random()-.5),y:l[e].y+i*(Math.random()-.5)};b.nail(t,Vector.mult(Vector.normalise(Vector.sub(s,t)),o),a)}else if(s){const e=2*Math.PI*Math.random();b.nail(t,{x:o*Math.cos(e),y:o*Math.sin(e)},a)}},nail(t,e,o=1){o*=tech.nailSize;const i=bullet.length;bullet[i]=Bodies.rectangle(t.x,t.y,25*tech.nailSize,2*tech.nailSize,b.fireAttributes(Math.atan2(e.y,e.x))),Matter.Body.setVelocity(bullet[i],e),Composite.add(engine.world,bullet[i]),bullet[i].endCycle=simulation.cycle+60+18*Math.random(),bullet[i].dmg=tech.isNailRadiation?0:o,bullet[i].beforeDmg=function(t){tech.isNailRadiation&&mobs.statusDoT(t,o*(tech.isFastRadiation?1.3:.44),tech.isSlowRadiation?360:tech.isFastRadiation?60:180),tech.isNailCrit&&!t.shield&&Vector.dot(Vector.normalise(Vector.sub(t.position,this.position)),Vector.normalise(this.velocity))>.94&&b.explosion(this.position,150+30*Math.random())},bullet[i].do=function(){}},needle(t=m.angle){const e=bullet.length;bullet[e]=Bodies.rectangle(m.pos.x+40*Math.cos(m.angle),m.pos.y+40*Math.sin(m.angle),75*tech.nailSize,.75*tech.nailSize,b.fireAttributes(t)),Matter.Body.setDensity(bullet[e],1e-5),bullet[e].immuneList=[],bullet[e].dmg=6,tech.needleTunnel?(bullet[e].dmg*=1.2,bullet[e].endCycle=simulation.cycle+300,bullet[e].collisionFilter.mask=tech.isShieldPierce?0:cat.mobShield,bullet[e].isInMap=!1,bullet[e].do=function(){const t=Matter.Query.collides(this,mob);if(t.length&&this.speed>20){for(let e=0,o=t.length;e<o;e++)if(who=t[e].bodyA,who&&who.mob){let t=!1;for(let e=0;e<this.immuneList.length;e++)if(this.immuneList[e]===who.id){t=!0;break}if(!t){tech.isNailCrit&&!who.shield&&Vector.dot(Vector.normalise(Vector.sub(who.position,this.position)),Vector.normalise(this.velocity))>.94&&b.explosion(this.position,220*tech.nailSize+50*Math.random()),this.immuneList.push(who.id);let t=this.dmg*tech.nailSize*b.dmgScale;tech.isNailRadiation&&(mobs.statusDoT(who,(tech.isFastRadiation?6:2)*tech.nailSize,tech.isSlowRadiation?360:tech.isFastRadiation?60:180),t*=.25),tech.isCrit&&who.isStunned&&(t*=4),who.damage(t,tech.isShieldPierce),who.alive&&who.foundPlayer(),who.damageReduction&&simulation.drawList.push({x:this.position.x,y:this.position.y,radius:40*Math.log(t+1.1)*who.damageReduction+3,color:simulation.playerDmgColor,time:simulation.drawTime})}}}else Matter.Query.collides(this,map).length?(this.isInMap||(this.isInMap=!0,Matter.Body.setVelocity(this,Vector.rotate(this.velocity,.25*(Math.random()-.5))),Matter.Body.setAngle(this,Math.atan2(this.velocity.y,this.velocity.x))),Matter.Body.setPosition(this,Vector.add(this.position,Vector.mult(this.velocity,-.98)))):Matter.Query.collides(this,body).length?(Matter.Body.setAngularVelocity(this,0),Matter.Body.setPosition(this,Vector.add(this.position,Vector.mult(this.velocity,-.94)))):this.speed<30&&(this.force.y+=.001*this.mass)}):(bullet[e].endCycle=simulation.cycle+100,bullet[e].collisionFilter.mask=tech.isShieldPierce?cat.body:cat.body|cat.mobShield,bullet[e].do=function(){const t=Matter.Query.collides(this,mob);if(t.length&&this.speed>20){for(let e=0,o=t.length;e<o;e++)if(who=t[e].bodyA,who&&who.mob){let t=!1;for(let e=0;e<this.immuneList.length;e++)if(this.immuneList[e]===who.id){t=!0;break}if(!t){tech.isNailCrit&&!who.shield&&Vector.dot(Vector.normalise(Vector.sub(who.position,this.position)),Vector.normalise(this.velocity))>.94&&b.explosion(this.position,220*tech.nailSize+50*Math.random()),this.immuneList.push(who.id);let t=this.dmg*tech.nailSize*b.dmgScale;tech.isNailRadiation&&(mobs.statusDoT(who,(tech.isFastRadiation?6:2)*tech.nailSize,tech.isSlowRadiation?360:tech.isFastRadiation?60:180),t*=.25),tech.isCrit&&who.isStunned&&(t*=4),who.damage(t,tech.isShieldPierce),who.alive&&who.foundPlayer(),who.damageReduction&&simulation.drawList.push({x:this.position.x,y:this.position.y,radius:40*Math.log(t+1.1)*who.damageReduction+3,color:simulation.playerDmgColor,time:simulation.drawTime})}}}else Matter.Query.collides(this,map).length?(this.collisionFilter.mask=0,Matter.Body.setAngularVelocity(this,0),Matter.Body.setVelocity(this,{x:0,y:0}),this.do=function(){Matter.Query.collides(this,map).length||(this.force.y+=.001*this.mass)},tech.isNeedleIce&&(b.iceIX(5+5*Math.random(),2*Math.PI*Math.random(),this.position),.5<Math.random()&&b.iceIX(5+5*Math.random(),2*Math.PI*Math.random(),this.position))):this.speed<30&&(this.force.y+=.001*this.mass)});Matter.Body.setVelocity(bullet[e],{x:m.Vx/2+90*Math.cos(t),y:m.Vy/2+90*Math.sin(t)}),Composite.add(engine.world,bullet[e])},totalBots:()=>tech.dynamoBotCount+tech.foamBotCount+tech.nailBotCount+tech.laserBotCount+tech.boomBotCount+tech.orbitBotCount+tech.plasmaBotCount+tech.missileBotCount,hasBotUpgrade:()=>tech.isNailBotUpgrade+tech.isFoamBotUpgrade+tech.isBoomBotUpgrade+tech.isLaserBotUpgrade+tech.isOrbitBotUpgrade+tech.isDynamoBotUpgrade,convertBotsTo(t){const e=b.totalBots();let o=0;for(let t=0;t<tech.tech.length;t++)tech.tech[t].count&&tech.tech[t].isBot&&(o+=tech.tech[t].count,tech.removeTech(t));b.zeroBotCount(),b.clearPermanentBots();for(let e=0;e<o;e++)tech.giveTech(t);let i=null;for(let e=0;e<tech.tech.length;e++)if(tech.tech[e].name===t){i=e;break}for(let t=0,s=e-o;t<s;t++)tech.tech[i].effect()},clearPermanentBots(){for(let t=0;t<bullet.length;t++)bullet[t].botType&&bullet[t].endCycle===1/0&&(bullet[t].endCycle=0)},removeBot(){tech.nailBotCount>1?tech.nailBotCount--:tech.laserBotCount>1?tech.laserBotCount--:tech.foamBotCount>1?tech.foamBotCount--:tech.boomBotCount>1?tech.boomBotCount--:tech.orbitBotCount>1?tech.orbitBotCount--:tech.dynamoBotCount>1?tech.dynamoBotCount--:tech.missileBotCount>1?tech.missileBotCount--:tech.plasmaBotCount>1&&tech.plasmaBotCount--},zeroBotCount(){tech.dynamoBotCount=0,tech.laserBotCount=0,tech.nailBotCount=0,tech.foamBotCount=0,tech.boomBotCount=0,tech.orbitBotCount=0,tech.missileBotCount=0},respawnBots(){for(let t=0;t<tech.dynamoBotCount;t++)b.dynamoBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.laserBotCount;t++)b.laserBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.nailBotCount;t++)b.nailBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.foamBotCount;t++)b.foamBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.boomBotCount;t++)b.boomBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.orbitBotCount;t++)b.orbitBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.plasmaBotCount;t++)b.plasmaBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);for(let t=0;t<tech.missileBotCount;t++)b.missileBot({x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},!1);if(tech.isIntangible&&m.isCloak)for(let t=0;t<bullet.length;t++)bullet[t].botType&&(bullet[t].collisionFilter.mask=cat.map|cat.bullet|cat.mobBullet|cat.mobShield)},randomBot(t=player.position,e=!0,o=!0){Math.random()<.166&&o?(b.laserBot(t,e),e&&tech.laserBotCount++):Math.random()<.2?(b.dynamoBot(t,e),e&&tech.dynamoBotCount++):Math.random()<.25?(b.orbitBot(t,e),e&&tech.orbitBotCount++):Math.random()<.33?(b.nailBot(t,e),e&&tech.nailBotCount++):Math.random()<.5?(b.foamBot(t,e),e&&tech.foamBotCount++):(b.boomBot(t,e),e&&tech.boomBotCount++)},setDynamoBotDelay(){let t=0;for(let e=0;e<bullet.length;e++)"dynamo"===bullet[e].botType&&t++;let e=0;for(let o=0;o<bullet.length;o++)if("dynamo"===bullet[o].botType){e++;const i=Math.max(60-3*t,20);bullet[o].followDelay=i*e%600}},dynamoBot(t=player.position,e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.dynamoBot()");const o=bullet.length;bullet[o]=Bodies.polygon(t.x,t.y,5,10,{isUpgraded:tech.isDynamoBotUpgrade,botType:"dynamo",friction:0,frictionStatic:0,frictionAir:.02,spin:.07*(Math.random()<.5?-1:1),isSensor:!0,restitution:0,dmg:0,minDmgSpeed:0,endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:0},beforeDmg(){},onEnd(){b.setDynamoBotDelay()},followDelay:0,phase:Math.floor(60*Math.random()),do(){if(!m.isBodiesAsleep){if(m.immuneCycle<m.cycle&&!((m.cycle+this.phase)%30)&&Vector.magnitude(Vector.sub(this.position,player.position))<250&&m.immuneCycle<m.cycle&&(Matter.Body.setAngularVelocity(this,this.spin),this.isUpgraded?(m.energy+=.1,simulation.drawList.push({x:this.position.x,y:this.position.y,radius:10,color:m.fieldMeterColor,time:simulation.drawTime})):(m.energy+=.03,simulation.drawList.push({x:this.position.x,y:this.position.y,radius:5,color:m.fieldMeterColor,time:simulation.drawTime}))),!m.isCloak){const t=33;q=Matter.Query.region(mob,{min:{x:this.position.x-t,y:this.position.y-t},max:{x:this.position.x+t,y:this.position.y+t}});for(let t=0;t<q.length;t++)if(!q[t].isShielded){Matter.Body.setAngularVelocity(this,this.spin);const e=.5*b.dmgScale;q[t].damage(e),q[t].alive&&q[t].foundPlayer(),q[t].damageReduction&&simulation.drawList.push({x:this.position.x,y:this.position.y,radius:Math.sqrt(2e3*e*q[t].damageReduction)+2,color:"rgba(0,0,0,0.4)",time:simulation.drawTime})}}let t=m.history[(m.cycle-this.followDelay)%600];Matter.Body.setPosition(this,{x:t.position.x,y:t.position.y-t.yOff+24.2859})}}}),Composite.add(engine.world,bullet[o]),b.setDynamoBotDelay()},nailBot(t={x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.nailBot()");const o=bullet.length,i=m.angle,s=12+4*Math.random();bullet[o]=Bodies.polygon(t.x,t.y,4,s,{isUpgraded:tech.isNailBotUpgrade,botType:"nail",angle:i,friction:0,frictionStatic:0,frictionAir:.05,restitution:.6*(1+.5*Math.random()),dmg:0,minDmgSpeed:2,lastLookCycle:simulation.cycle+60*Math.random(),delay:Math.floor((tech.isNailBotUpgrade?21:110)*b.fireCDscale),acceleration:.005*(1+.5*Math.random()),range:60*(1+.3*Math.random())+3*b.totalBots(),endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:b.totalBots()<50?cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},beforeDmg(){},onEnd(){},do(){if(Vector.magnitude(Vector.sub(this.position,m.pos))>this.range)this.force=Vector.mult(Vector.normalise(Vector.sub(m.pos,this.position)),this.mass*this.acceleration);else if(Matter.Body.setVelocity(this,Vector.add(Vector.mult(this.velocity,.9),Vector.mult(player.velocity,.17))),this.lastLookCycle<simulation.cycle&&!m.isCloak){this.lastLookCycle=simulation.cycle+this.delay;for(let t=0,e=mob.length;t<e;t++){const e=Vector.magnitudeSquared(Vector.sub(this.position,mob[t].position));if(!mob[t].isBadTarget&&e<3e6&&0===Matter.Query.ray(map,this.position,mob[t].position).length&&0===Matter.Query.ray(body,this.position,mob[t].position).length&&!mob[t].isShielded){const o=Vector.normalise(Vector.sub(Vector.add(mob[t].position,Vector.mult(mob[t].velocity,Math.sqrt(e)/60)),this.position));if(this.isUpgraded){const t=50;b.nail(this.position,Vector.mult(o,t)),this.force=Vector.mult(o,-.018*this.mass)}else{const t=35;b.nail(this.position,Vector.mult(o,t)),this.force=Vector.mult(o,-.01*this.mass)}break}}}}}),Composite.add(engine.world,bullet[o])},missileBot(t={x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.missileBot()");const o=bullet.length;bullet[o]=Bodies.rectangle(t.x,t.y,28,11,{botType:"missile",angle:m.angle,friction:0,frictionStatic:0,frictionAir:.04,restitution:.7,dmg:0,minDmgSpeed:2,lookFrequency:27+Math.ceil(6*Math.random()),cd:0,delay:Math.floor(65*b.fireCDscale),range:70+3*b.totalBots(),endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:b.totalBots()<50?cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},beforeDmg(){},onEnd(){},do(){if(Vector.magnitude(Vector.sub(this.position,m.pos))>this.range)this.force=Vector.mult(Vector.normalise(Vector.sub(m.pos,this.position)),.006*this.mass);else if(Matter.Body.setVelocity(this,Vector.add(Vector.mult(this.velocity,.9),Vector.mult(player.velocity,.17))),this.cd<simulation.cycle&&!(simulation.cycle%this.lookFrequency)&&!m.isCloak)for(let t=0,e=mob.length;t<e;t++){const e=Vector.magnitudeSquared(Vector.sub(this.position,mob[t].position));if(mob[t].alive&&!mob[t].isBadTarget&&e>4e4&&0===Matter.Query.ray(map,this.position,mob[t].position).length){this.cd=simulation.cycle+this.delay;const e=Vector.angle(this.position,mob[t].position);if(Matter.Body.setAngle(this,e),this.torque+=4e-5*this.inertia*(Math.round(Math.random())?1:-1),this.force=Vector.mult(Vector.normalise(Vector.sub(this.position,mob[t].position)),.02*this.mass),tech.missileCount>1){const t=Math.pow(.93,tech.missileCount),o=.9*Math.sqrt(t),i={x:Math.cos(e),y:Math.sin(e)},s=Vector.mult(Vector.perp(i),.015*t/Math.sqrt(tech.missileCount));for(let t=0;t<tech.missileCount;t++)setTimeout((()=>{b.missile(this.position,e,-8,o),bullet[bullet.length-1].force.x+=s.x*(t-(tech.missileCount-1)/2),bullet[bullet.length-1].force.y+=s.y*(t-(tech.missileCount-1)/2)}),40*tech.missileCount*Math.random())}else b.missile(this.position,e,-8,.9);break}}}}),Composite.add(engine.world,bullet[o])},foamBot(t={x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.foamBot()");const o=bullet.length,i=m.angle,s=10+5*Math.random();bullet[o]=Bodies.polygon(t.x,t.y,6,s,{isUpgraded:tech.isFoamBotUpgrade,botType:"foam",angle:i,friction:0,frictionStatic:0,frictionAir:.05,restitution:.6*(1+.5*Math.random()),dmg:0,minDmgSpeed:2,lookFrequency:60+Math.floor(17*Math.random())-40*tech.isFoamBotUpgrade,cd:0,delay:Math.floor(105*b.fireCDscale),acceleration:.005*(1+.5*Math.random()),range:60*(1+.3*Math.random())+3*b.totalBots(),endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:b.totalBots()<50?cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},beforeDmg(){},onEnd(){},do(){if(Vector.magnitude(Vector.sub(this.position,m.pos))>this.range)this.force=Vector.mult(Vector.normalise(Vector.sub(m.pos,this.position)),this.mass*this.acceleration);else if(Matter.Body.setVelocity(this,Vector.add(Vector.mult(this.velocity,.9),Vector.mult(player.velocity,.17))),this.cd<simulation.cycle&&!(simulation.cycle%this.lookFrequency)&&!m.isCloak){let t;for(let e=0,o=mob.length;e<o;e++){const o=Vector.magnitudeSquared(Vector.sub(this.position,mob[e].position));if(o<1e6&&!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length){this.cd=simulation.cycle+this.delay,t=Vector.add(mob[e].position,Vector.mult(mob[e].velocity,Math.sqrt(o)/60));const i=6+7*Math.random(),s=29-.4*i,a=Vector.mult(Vector.normalise(Vector.sub(t,this.position)),s);b.foam(this.position,a,i+7*this.isUpgraded);break}}}}}),Composite.add(engine.world,bullet[o])},laserBot(t={x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.laserBot()");const o=bullet.length,i=m.angle,s=14+6*Math.random();bullet[o]=Bodies.polygon(t.x,t.y,3,s,{isUpgraded:tech.isLaserBotUpgrade,botType:"laser",angle:i,friction:0,frictionStatic:0,frictionAir:.008*(1+.3*Math.random()),restitution:.5*(1+.5*Math.random()),acceleration:.0015*(1+.3*Math.random()),playerRange:140+Math.floor(30*Math.random())+2*b.totalBots(),offPlayer:{x:0,y:0},dmg:0,minDmgSpeed:2,lookFrequency:40+Math.floor(7*Math.random())-10*tech.isLaserBotUpgrade,range:(700+450*tech.isLaserBotUpgrade)*(1+.1*Math.random()),drainThreshold:tech.isEnergyHealth?.6:.4,drain:(.5-.43*tech.isLaserBotUpgrade)*tech.laserFieldDrain*tech.isLaserDiode,laserDamage:.85+.7*tech.isLaserBotUpgrade,endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:b.totalBots()<50?cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},lockedOn:null,beforeDmg(){this.lockedOn=null},onEnd(){},do(){const t=Vector.add(Vector.add(this.offPlayer,m.pos),Vector.mult(player.velocity,20)),e=Math.max(0,Vector.magnitude(Vector.sub(this.position,t))/this.playerRange),o=Math.min(e,4)*this.mass*this.acceleration;if(this.force=Vector.mult(Vector.normalise(Vector.sub(t,this.position)),o),Matter.Body.setVelocity(this,{x:.95*this.velocity.x,y:.95*this.velocity.y}),!(simulation.cycle%this.lookFrequency)){if(this.lockedOn=null,!m.isCloak){let t=this.range;for(let e=0,o=mob.length;e<o;++e){const o=Vector.magnitude(Vector.sub(this.vertices[0],mob[e].position));o-mob[e].radius<t&&!mob[e].isShielded&&(!mob[e].isBadTarget||mob[e].isMobBullet)&&0===Matter.Query.ray(map,this.vertices[0],mob[e].position).length&&0===Matter.Query.ray(body,this.vertices[0],mob[e].position).length&&(t=o,this.lockedOn=mob[e])}}if(Math.random()<.15){const t=110+4*b.totalBots();this.offPlayer={x:t*(Math.random()-.5),y:t*(Math.random()-.5)-20}}}this.lockedOn&&this.lockedOn.alive&&m.energy>this.drainThreshold&&(m.energy-=this.drain,b.laser(this.vertices[0],this.lockedOn.position,b.dmgScale*this.laserDamage*tech.laserDamage,tech.laserReflections,!1,.4))}}),Composite.add(engine.world,bullet[o])},boomBot(t={x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.boomBot()");const o=bullet.length,i=m.angle,s=7+2*Math.random();bullet[o]=Bodies.polygon(t.x,t.y,4,s,{isUpgraded:tech.isBoomBotUpgrade,botType:"boom",angle:i,friction:0,frictionStatic:0,frictionAir:.05,restitution:1,dmg:0,minDmgSpeed:0,lookFrequency:43+Math.floor(7*Math.random())-10*tech.isBoomBotUpgrade,acceleration:.005*(1+.5*Math.random()),attackAcceleration:.012+.005*tech.isBoomBotUpgrade,range:500*(1+.1*Math.random())+320*tech.isBoomBotUpgrade,endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:b.totalBots()<50?cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},lockedOn:null,explode:0,beforeDmg(){if(this.lockedOn){const t=Math.min(136+200*this.isUpgraded,Vector.magnitude(Vector.sub(this.position,m.pos))-30);t>60&&(this.explode=t),this.lockedOn=null}},onEnd(){},do(){const t=Vector.magnitude(Vector.sub(this.position,player.position));if(t>100)this.explode&&(tech.isImmuneExplosion&&m.energy>1.43?b.explosion(this.position,this.explode):b.explosion(this.position,Math.max(0,Math.min(this.explode,(t-70)/b.explosionRange()))),this.explode=0),this.force=Vector.mult(Vector.normalise(Vector.sub(player.position,this.position)),this.mass*this.acceleration);else if(t<250&&(Matter.Body.setVelocity(this,Vector.add(Vector.mult(this.velocity,.9),Vector.mult(player.velocity,.17))),!(simulation.cycle%this.lookFrequency||m.isCloak))){this.lockedOn=null;let t=this.range;for(let e=0,o=mob.length;e<o;++e){const o=Vector.magnitude(Vector.sub(this.position,mob[e].position))-mob[e].radius;o<t&&!mob[e].isBadTarget&&0===Matter.Query.ray(map,this.position,mob[e].position).length&&0===Matter.Query.ray(body,this.position,mob[e].position).length&&(t=o,this.lockedOn=mob[e])}}if(this.lockedOn&&this.lockedOn.alive&&!m.isCloak){Vector.magnitude(Vector.sub(this.vertices[0],this.lockedOn.position))-this.lockedOn.radius<this.range&&0===Matter.Query.ray(map,this.position,this.lockedOn.position).length&&(this.force=Vector.add(this.force,Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position,this.position)),this.attackAcceleration*this.mass)))}}}),Composite.add(engine.world,bullet[o])},plasmaBot(t={x:player.position.x+50*(Math.random()-.5),y:player.position.y+50*(Math.random()-.5)},e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.plasmaBot()");const o=bullet.length,i=m.angle;bullet[o]=Bodies.polygon(t.x,t.y,5,21,{botType:"plasma",angle:i,friction:0,frictionStatic:0,frictionAir:.05,restitution:1,dmg:0,minDmgSpeed:2,lookFrequency:25,cd:0,acceleration:.009,endCycle:1/0,drainThreshold:tech.isEnergyHealth?.5:.05,classType:"bullet",collisionFilter:{category:cat.bullet,mask:b.totalBots()<50?cat.map|cat.body|cat.bullet|cat.mob|cat.mobBullet|cat.mobShield:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},lockedOn:null,beforeDmg(){this.lockedOn=null},onEnd(){},do(){if(Vector.magnitude(Vector.sub(this.position,m.pos))>150&&(this.force=Vector.mult(Vector.normalise(Vector.sub(m.pos,this.position)),this.mass*this.acceleration)),Matter.Body.setVelocity(this,Vector.add(Vector.mult(this.velocity,.9),Vector.mult(player.velocity,.17))),!(simulation.cycle%this.lookFrequency||(this.lockedOn=null,m.isCloak))){let t=1e3*tech.isPlasmaRange;for(let e=0,o=mob.length;e<o;++e){const o=Vector.magnitude(Vector.sub(this.position,mob[e].position))-mob[e].radius;o<t&&(!mob[e].isBadTarget||mob[e].isMobBullet)&&0===Matter.Query.ray(map,this.position,mob[e].position).length&&0===Matter.Query.ray(body,this.position,mob[e].position).length&&(t=o,this.lockedOn=mob[e])}}if(this.lockedOn&&this.lockedOn.alive&&m.fieldCDcycle<m.cycle){const t=Vector.sub(this.lockedOn.position,this.position),e=Vector.magnitude(t),o=Vector.normalise(t);if(e<450*tech.isPlasmaRange&&m.energy>this.drainThreshold){let t;m.energy-=35e-5+m.fieldRegen;let e=tech.isPlasmaRange*(120+300*Math.sqrt(Math.random()));const i=[{x:this.position.x,y:this.position.y},{x:this.position.x+e*o.x,y:this.position.y+e*o.y}],s=function(e,o,i){for(let s=0;s<i.length;++s){let a=i[s].vertices;const l=a.length-1;for(let n=0;n<l;n++)if(results=simulation.checkLineIntersection(e,o,a[n],a[n+1]),results.onLine1&&results.onLine2){const o=e.x-results.x,l=e.y-results.y,r=o*o+l*l;r<t.dist2&&(!i[s].mob||i[s].alive)&&(t={x:results.x,y:results.y,dist2:r,who:i[s],v1:a[n],v2:a[n+1]})}if(results=simulation.checkLineIntersection(e,o,a[0],a[l]),results.onLine1&&results.onLine2){const o=e.x-results.x,n=e.y-results.y,r=o*o+n*n;r<t.dist2&&(!i[s].mob||i[s].alive)&&(t={x:results.x,y:results.y,dist2:r,who:i[s],v1:a[0],v2:a[l]})}}};if(t={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null},s(i[0],i[1],mob),s(i[0],i[1],map),s(i[0],i[1],body),t.dist2!=1/0)if(i[i.length-1]={x:t.x,y:t.y},t.who.alive){const e=.6*b.dmgScale;t.who.damage(e),t.who.locatePlayer();const o=Vector.mult(Vector.normalise(Vector.sub(m.pos,i[1])),-.01*Math.min(5,t.who.mass));Matter.Body.applyForce(t.who,i[1],o),Matter.Body.setVelocity(t.who,{x:.7*t.who.velocity.x,y:.7*t.who.velocity.y}),t.who.damageReduction&&simulation.drawList.push({x:i[1].x,y:i[1].y,radius:Math.sqrt(2e3*e*t.who.damageReduction)+2,color:"rgba(255,0,255,0.2)",time:4*simulation.drawTime})}else if(!t.who.isStatic){const e=Vector.mult(Vector.normalise(Vector.sub(m.pos,i[1])),-.007*Math.sqrt(Math.sqrt(t.who.mass)));Matter.Body.applyForce(t.who,i[1],e)}ctx.beginPath(),ctx.moveTo(i[0].x,i[0].y),ctx.lineTo(i[1].x,i[1].y),ctx.strokeStyle="rgba(255,0,255,0.1)",ctx.lineWidth=14,ctx.stroke(),ctx.strokeStyle="#f0f",ctx.lineWidth=2,ctx.stroke();let a=this.position.x+20*o.x,l=this.position.y+20*o.y;ctx.beginPath(),ctx.moveTo(a,l);const n=Vector.magnitude(Vector.sub(i[0],i[1]))/5;for(let t=0;t<4;t++)a+=n*(o.x+1.5*(Math.random()-.5)),l+=n*(o.y+1.5*(Math.random()-.5)),ctx.lineTo(a,l);ctx.lineWidth=2*Math.random(),ctx.stroke()}}}}),Composite.add(engine.world,bullet[o])},orbitBot(t=player.position,e=!0){e&&simulation.makeTextLog("<span class='color-var'>b</span>.orbitBot()");const o=bullet.length;bullet[o]=Bodies.polygon(t.x,t.y,9,12,{isUpgraded:tech.isOrbitBotUpgrade,botType:"orbit",friction:0,frictionStatic:0,frictionAir:1,isStatic:!0,isSensor:!0,restitution:0,dmg:0,minDmgSpeed:0,endCycle:1/0,classType:"bullet",collisionFilter:{category:cat.bullet,mask:0},beforeDmg(){},onEnd(){let t=0;for(let e=0;e<bullet.length;e++)"orbit"===bullet[e].botType&&bullet[e]!==this&&t++;let e=0;for(let o=0;o<bullet.length;o++)"orbit"===bullet[o].botType&&bullet[o]!==this&&(bullet[o].phase=e/t*2*Math.PI,e++)},range:190+120*tech.isOrbitBotUpgrade,orbitalSpeed:0,phase:2*Math.PI*Math.random(),do(){if(!m.isCloak&&!m.isBodiesAsleep){const t=33;q=Matter.Query.region(mob,{min:{x:this.position.x-t,y:this.position.y-t},max:{x:this.position.x+t,y:this.position.y+t}});for(let t=0;t<q.length;t++)if(!q[t].isShielded){mobs.statusStun(q[t],180);const e=.4*b.dmgScale*(this.isUpgraded?4:1)*(tech.isCrit?4:1);q[t].damage(e),q[t].alive&&q[t].foundPlayer(),q[t].damageReduction&&simulation.drawList.push({x:this.position.x,y:this.position.y,radius:Math.sqrt(2e3*e*q[t].damageReduction)+2,color:"rgba(0,0,0,0.4)",time:simulation.drawTime})}}const t=simulation.cycle*this.orbitalSpeed+this.phase,e={x:Math.cos(t),y:Math.sin(t)};Matter.Body.setPosition(this,Vector.add(m.pos,Vector.mult(e,this.range)))}}),bullet[o].orbitalSpeed=Math.sqrt(.25/bullet[o].range),Composite.add(engine.world,bullet[o]);let i=0;for(let t=0;t<bullet.length;t++)"orbit"===bullet[t].botType&&i++;let s=0;for(let t=0;t<bullet.length;t++)"orbit"===bullet[t].botType&&(bullet[t].phase=s/i*2*Math.PI,s++)},guns:[{name:"nail gun",description:"use compressed air to fire a stream of <strong>nails</strong><br><strong><em>delay</em></strong> after firing <strong>decreases</strong> as you shoot",ammo:0,ammoPack:45,defaultAmmoPack:45,recordedAmmo:0,have:!1,nextFireCycle:0,startingHoldCycle:0,chooseFireMethod(){tech.nailRecoil?tech.isRivets?this.fire=this.fireRecoilRivets:this.fire=this.fireRecoilNails:tech.isRivets?this.fire=this.fireRivets:tech.isDarts?this.fire=this.fireDarts:tech.isNeedles?this.fire=this.fireNeedles:tech.nailInstantFireRate?this.fire=this.fireInstantFireRate:this.fire=this.fireNormal},do(){},fire(){},fireDarts(){const t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)};m.fireCDcycle=m.cycle+10*b.fireCDscale,b.dart(t,m.angle)},fireRecoilNails(){this.nextFireCycle+1<m.cycle&&(this.startingHoldCycle=m.cycle);const t=Math.max(11-.08*(m.cycle-this.startingHoldCycle),1);if(this.nextFireCycle=m.cycle+t*b.fireCDscale,m.fireCDcycle=m.cycle+Math.floor(t*b.fireCDscale),this.baseFire(m.angle+(Math.random()-.5)*(input.down?.1:.13)/t,45+6*Math.random()),m.onGround)if(input.down){const t=.006;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle),Matter.Body.setVelocity(player,{x:.5*player.velocity.x,y:.5*player.velocity.y})}else{const t=.03;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle),Matter.Body.setVelocity(player,{x:.8*player.velocity.x,y:.8*player.velocity.y})}else player.force.x-=.06*Math.cos(m.angle)*Math.min(1,3/(.1+Math.abs(player.velocity.x))),player.force.y-=.006*Math.sin(m.angle)},fireNormal(){this.nextFireCycle+1<m.cycle&&(this.startingHoldCycle=m.cycle);const t=Math.max(11-.06*(m.cycle-this.startingHoldCycle),2);this.nextFireCycle=m.cycle+t*b.fireCDscale,m.fireCDcycle=m.cycle+Math.floor(t*b.fireCDscale),this.baseFire(m.angle+(Math.random()-.5)*(Math.random()-.5)*(input.down?1.35:3.2)/t)},fireNeedles(){if(input.down){function t(){simulation.paused||m.isBodiesAsleep?requestAnimationFrame(t):(e++,e%2&&b.needle(),e<5&&m.alive&&requestAnimationFrame(t))}m.fireCDcycle=m.cycle+38*b.fireCDscale,b.needle();let e=-1;requestAnimationFrame(t)}else{function t(){simulation.paused||m.isBodiesAsleep?requestAnimationFrame(t):(e++,e%2&&b.needle(),e<3&&m.alive&&requestAnimationFrame(t))}m.fireCDcycle=m.cycle+28*b.fireCDscale,b.needle();let e=-1;requestAnimationFrame(t)}},fireRivets(){m.fireCDcycle=m.cycle+Math.floor((input.down?25:17)*b.fireCDscale);const t=bullet.length,e=8*tech.nailSize;bullet[t]=Bodies.rectangle(m.pos.x+35*Math.cos(m.angle),m.pos.y+35*Math.sin(m.angle),5*e,e,b.fireAttributes(m.angle)),bullet[t].dmg=tech.isNailRadiation?0:2.75,Matter.Body.setDensity(bullet[t],.002),Composite.add(engine.world,bullet[t]);const o=input.down?55:44;if(Matter.Body.setVelocity(bullet[t],{x:o*Math.cos(m.angle),y:o*Math.sin(m.angle)}),bullet[t].endCycle=simulation.cycle+180,bullet[t].beforeDmg=function(t){tech.isNailCrit&&!t.shield&&Vector.dot(Vector.normalise(Vector.sub(t.position,this.position)),Vector.normalise(this.velocity))>.94&&b.explosion(this.position,300+30*Math.random()),tech.isNailRadiation&&mobs.statusDoT(t,7*(tech.isFastRadiation?.7:.24),tech.isSlowRadiation?360:tech.isFastRadiation?60:180)},bullet[t].minDmgSpeed=10,bullet[t].frictionAir=.006,bullet[t].do=function(){if(this.force.y+=8e-4*this.mass,this.speed>7){const t={x:Math.cos(this.angle),y:Math.sin(this.angle)},e=.002*this.mass;Vector.cross(Vector.normalise(this.velocity),t)<0?this.torque+=e:this.torque-=e}},b.muzzleFlash(30),m.onGround)if(input.down){const t=.01;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle)}else{const t=.02;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle)}else{const t=.01;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle)*.5}},fireRecoilRivets(){this.nextFireCycle+1<m.cycle&&(this.startingHoldCycle=m.cycle);const t=Math.max(25-.14*(m.cycle-this.startingHoldCycle),6);this.nextFireCycle=m.cycle+t*b.fireCDscale,m.fireCDcycle=m.cycle+Math.floor(t*b.fireCDscale);const e=bullet.length,o=8*tech.nailSize;bullet[e]=Bodies.rectangle(m.pos.x+35*Math.cos(m.angle),m.pos.y+35*Math.sin(m.angle),5*o,o,b.fireAttributes(m.angle)),bullet[e].dmg=tech.isNailRadiation?0:2.75,Matter.Body.setDensity(bullet[e],.002),Composite.add(engine.world,bullet[e]);const i=input.down?60:50;if(Matter.Body.setVelocity(bullet[e],{x:i*Math.cos(m.angle),y:i*Math.sin(m.angle)}),bullet[e].endCycle=simulation.cycle+180,bullet[e].beforeDmg=function(t){tech.isNailCrit&&!t.shield&&Vector.dot(Vector.normalise(Vector.sub(t.position,this.position)),Vector.normalise(this.velocity))>.94&&b.explosion(this.position,300+30*Math.random()),tech.isNailRadiation&&mobs.statusDoT(t,7*(tech.isFastRadiation?.7:.24),tech.isSlowRadiation?360:tech.isFastRadiation?60:180)},bullet[e].minDmgSpeed=10,bullet[e].frictionAir=.006,bullet[e].do=function(){if(this.force.y+=8e-4*this.mass,this.speed>7){const t={x:Math.cos(this.angle),y:Math.sin(this.angle)},e=.002*this.mass;Vector.cross(Vector.normalise(this.velocity),t)<0?this.torque+=e:this.torque-=e}},b.muzzleFlash(30),m.onGround)if(input.down){const t=.03;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle),Matter.Body.setVelocity(player,{x:.4*player.velocity.x,y:.4*player.velocity.y})}else{const t=.1;player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle),Matter.Body.setVelocity(player,{x:.7*player.velocity.x,y:.7*player.velocity.y})}else player.force.x-=.2*Math.cos(m.angle)*Math.min(1,3/(.1+Math.abs(player.velocity.x))),player.force.y-=.02*Math.sin(m.angle)},fireInstantFireRate(){m.fireCDcycle=m.cycle+Math.floor(2*b.fireCDscale),this.baseFire(m.angle+(Math.random()-.5)*(Math.random()-.5)*(input.down?1.35:3.2)/2)},baseFire(t,e=30+6*Math.random()){b.nail({x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},{x:m.Vx/2+e*Math.cos(t),y:m.Vy/2+e*Math.sin(t)}),tech.isIceCrystals&&(bullet[bullet.length-1].beforeDmg=function(t){mobs.statusSlow(t,60),tech.isNailRadiation&&mobs.statusDoT(t,1*(tech.isFastRadiation?1.3:.44),tech.isSlowRadiation?360:tech.isFastRadiation?60:180),tech.isNailCrit&&!t.shield&&Vector.dot(Vector.normalise(Vector.sub(t.position,this.position)),Vector.normalise(this.velocity))>.94&&b.explosion(this.position,150+30*Math.random())},m.energy<.01?m.fireCDcycle=m.cycle+60:m.energy-=m.fieldRegen+.008)}},{name:"shotgun",description:"fire a wide <strong>burst</strong> of short range <strong> bullets</strong>",ammo:0,ammoPack:4,defaultAmmoPack:4,have:!1,do(){},fire(){let t,e;if(input.down?(e=.65,m.fireCDcycle=m.cycle+Math.floor(60*b.fireCDscale),tech.isShotgunImmune&&m.immuneCycle<m.cycle+Math.floor(60*b.fireCDscale)&&(m.immuneCycle=m.cycle+Math.floor(60*b.fireCDscale)),t=.01):(m.fireCDcycle=m.cycle+Math.floor(47*b.fireCDscale),tech.isShotgunImmune&&m.immuneCycle<m.cycle+Math.floor(47*b.fireCDscale)&&(m.immuneCycle=m.cycle+Math.floor(47*b.fireCDscale)),e=1.3,t=.1),tech.isShotgunReversed?(player.force.x+=4*t*Math.cos(m.angle),player.force.y+=4*t*Math.sin(m.angle)-6*player.mass*simulation.g):tech.isShotgunRecoil?(m.fireCDcycle-=45*b.fireCDscale*.66,player.force.x-=2*t*Math.cos(m.angle),player.force.y-=2*t*Math.sin(m.angle)):(player.force.x-=t*Math.cos(m.angle),player.force.y-=t*Math.sin(m.angle)*.5),b.muzzleFlash(35),tech.isSlugShot){const t=bullet.length;bullet[t]=Bodies.rectangle(m.pos.x+35*Math.cos(m.angle),m.pos.y+35*Math.sin(m.angle),60*tech.nailSize,27*tech.nailSize,b.fireAttributes(m.angle)),Matter.Body.setDensity(bullet[t],.007*(tech.isShotgunReversed?1.6:1)),Composite.add(engine.world,bullet[t]);const e=input.down?50:37;Matter.Body.setVelocity(bullet[t],{x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)}),tech.isIncendiary?(bullet[t].endCycle=simulation.cycle+60,bullet[t].onEnd=function(){b.explosion(this.position,300+60*(Math.random()-.5))},bullet[t].beforeDmg=function(){this.endCycle=0}):bullet[t].endCycle=simulation.cycle+180,bullet[t].minDmgSpeed=7,bullet[t].frictionAir=.006,bullet[t].turnMag=.04*Math.pow(tech.nailSize,3.75),bullet[t].do=function(){if(this.force.y+=.0022*this.mass,this.speed>6){const t={x:Math.cos(this.angle),y:Math.sin(this.angle)};Vector.cross(Vector.normalise(this.velocity),t)<0?this.torque+=this.turnMag:this.torque-=this.turnMag}},tech.fragments&&(bullet[t].beforeDmg=function(){this.speed>4&&(b.targetedNail(this.position,7*tech.fragments*tech.nailSize),this.endCycle=0)})}else if(tech.isIncendiary){e*=.15;const t=Math.floor(input.down?10:7),o=10,i=(input.down?.4:1.3)/o;let s=m.angle-i*o/2;for(let a=0;a<o;a++){s+=i;const o=bullet.length;bullet[o]=Bodies.rectangle(m.pos.x+50*Math.cos(m.angle),m.pos.y+50*Math.sin(m.angle),17,4,b.fireAttributes(s));const a=t+4*Math.random();bullet[o].endCycle=2*a+simulation.cycle;const l=25*a/t,n=s+(Math.random()-.5)*e;Matter.Body.setVelocity(bullet[o],{x:l*Math.cos(n),y:l*Math.sin(n)}),bullet[o].onEnd=function(){b.explosion(this.position,150*(tech.isShotgunReversed?1.5:1)+40*(Math.random()-.5))},bullet[o].beforeDmg=function(){this.endCycle=0},bullet[o].do=function(){},Composite.add(engine.world,bullet[o])}}else if(tech.isNailShot){e*=.65;const t=2*(tech.isShotgunReversed?1.6:1);if(input.down)for(let o=0;o<17;o++){speed=38+15*Math.random();const o=m.angle+(Math.random()-.5)*e,i={x:m.pos.x+35*Math.cos(m.angle)+15*(Math.random()-.5),y:m.pos.y+35*Math.sin(m.angle)+15*(Math.random()-.5)};b.nail(i,{x:speed*Math.cos(o),y:speed*Math.sin(o)},t)}else for(let o=0;o<17;o++){speed=38+15*Math.random();const o=m.angle+(Math.random()-.5)*e,i={x:m.pos.x+35*Math.cos(m.angle)+15*(Math.random()-.5),y:m.pos.y+35*Math.sin(m.angle)+15*(Math.random()-.5)};b.nail(i,{x:speed*Math.cos(o),y:speed*Math.sin(o)},t)}}else if(tech.isWormShot){const t={x:m.pos.x+35*Math.cos(m.angle),y:m.pos.y+35*Math.sin(m.angle)},e=input.down?.04:.08,o=3*(tech.isShotgunReversed?1.6:1)+Math.random();let i=m.angle-(o-1)*e*.5;for(let s=0;s<o;s++){b.worm(t);const o=(16+20*input.down)*(1+.15*Math.random());Matter.Body.setVelocity(bullet[bullet.length-1],{x:o*Math.cos(i),y:o*Math.sin(i)}),i+=e}}else if(tech.isIceShot){const t=input.down?.7:1.2;for(let e=0,o=16*(tech.isShotgunReversed?1.6:1);e<o;e++)b.iceIX(25+20*Math.random(),m.angle+t*(Math.random()-.5))}else if(tech.isFoamShot){const t=input.down?.35:.7,e={x:m.pos.x+25*Math.cos(m.angle),y:m.pos.y+25*Math.sin(m.angle)},o=13*(tech.isShotgunReversed?1.6:1);for(let i=0;i<o;i++){const o=25+12*Math.random(),i=m.angle+t*(Math.random()-.5);b.foam(e,{x:o*Math.cos(i),y:o*Math.sin(i)},5+8*Math.random())}}else if(tech.isNeedleShot){const t=9*(tech.isShotgunReversed?1.6:1),e=input.down?.03:.05;let o=m.angle-(t-1)*e*.5;for(let i=0;i<t;i++)b.needle(o),o+=e}else{const t=22;for(let o=0;o<17;o++){const o=bullet.length,i=m.angle+(Math.random()-.5)*e;bullet[o]=Bodies.rectangle(m.pos.x+35*Math.cos(m.angle)+15*(Math.random()-.5),m.pos.y+35*Math.sin(m.angle)+15*(Math.random()-.5),t,t,b.fireAttributes(i)),Composite.add(engine.world,bullet[o]);const s=52+8*Math.random();Matter.Body.setVelocity(bullet[o],{x:s*Math.cos(i),y:s*Math.sin(i)}),bullet[o].endCycle=simulation.cycle+40,bullet[o].minDmgSpeed=15,tech.isShotgunReversed&&Matter.Body.setDensity(bullet[o],.0016),bullet[o].frictionAir=.034,bullet[o].do=function(){if(!m.isBodiesAsleep){const t=1-.034/tech.isBulletsLastLonger;Matter.Body.scale(this,t,t)}}}}}},{name:"super balls",description:"fire <strong>3</strong> balls in a wide arc<br>balls <strong>bounce</strong> with no momentum loss",ammo:0,ammoPack:10,have:!1,do(){},fireOne(){const t=input.down?43:36;m.fireCDcycle=m.cycle+Math.floor((input.down?23:15)*b.fireCDscale);let e=m.angle;const o=bullet.length;bullet[o]=Bodies.polygon(m.pos.x+30*Math.cos(m.angle),m.pos.y+30*Math.sin(m.angle),12,21*tech.bulletSize,b.fireAttributes(e,!1)),Composite.add(engine.world,bullet[o]),Matter.Body.setVelocity(bullet[o],{x:t*Math.cos(e),y:t*Math.sin(e)}),bullet[o].endCycle=simulation.cycle+Math.floor(300+90*Math.random()),bullet[o].minDmgSpeed=0,bullet[o].restitution=1,bullet[o].friction=0,bullet[o].do=function(){this.force.y+=.0012*this.mass},bullet[o].beforeDmg=function(t){mobs.statusStun(t,180),tech.isIncendiary&&(b.explosion(this.position,280*this.mass),this.endCycle=0)}},fireMulti(){const t=input.down?43:36;m.fireCDcycle=m.cycle+Math.floor((input.down?23:15)*b.fireCDscale);const e=input.down?.08:.13,o=3+Math.floor(tech.extraSuperBalls*Math.random()),i=11*tech.bulletSize;let s=m.angle-e*(o-1)/2;for(let a=0;a<o;a++){const o=bullet.length;bullet[o]=Bodies.polygon(m.pos.x+30*Math.cos(m.angle),m.pos.y+30*Math.sin(m.angle),12,i,b.fireAttributes(s,!1)),Composite.add(engine.world,bullet[o]),Matter.Body.setVelocity(bullet[o],{x:t*Math.cos(s),y:t*Math.sin(s)}),bullet[o].endCycle=simulation.cycle+Math.floor((300+90*Math.random())*tech.isBulletsLastLonger),bullet[o].minDmgSpeed=0,bullet[o].restitution=.99,bullet[o].friction=0,bullet[o].do=function(){this.force.y+=.001*this.mass},bullet[o].beforeDmg=function(){tech.isIncendiary&&(b.explosion(this.position,320*this.mass+70*Math.random()),this.endCycle=0)},s+=e}},fireQueue(){const t=input.down?43:36,e=m.angle,o=m.pos.x,i=m.pos.y,s=3+Math.floor(tech.extraSuperBalls*Math.random()),a=Math.floor((input.down?18:12)*b.fireCDscale);m.fireCDcycle=m.cycle+a;const l=()=>{const s=bullet.length;bullet[s]=Bodies.polygon(o,i,12,11*tech.bulletSize,b.fireAttributes(e,!1)),Composite.add(engine.world,bullet[s]),Matter.Body.setVelocity(bullet[s],{x:t*Math.cos(e),y:t*Math.sin(e)}),bullet[s].endCycle=simulation.cycle+Math.floor(330*tech.isBulletsLastLonger),bullet[s].minDmgSpeed=0,bullet[s].restitution=.99,bullet[s].friction=0,bullet[s].do=function(){this.force.y+=.001*this.mass},bullet[s].beforeDmg=function(){tech.isIncendiary&&(b.explosion(this.position,320*this.mass+70*Math.random()),this.endCycle=0)},m.fireCDcycle=m.cycle+a};let n=0;requestAnimationFrame((function t(){simulation.paused||m.isBodiesAsleep?requestAnimationFrame(t):(n++,n%2&&l(),n<2*s&&m.alive&&requestAnimationFrame(t))}))},chooseFireMethod(){tech.oneSuperBall?this.fire=this.fireOne:tech.superBallDelay?this.fire=this.fireQueue:this.fire=this.fireMulti},fire(){}},{name:"matter wave",description:"emit a <strong>wave packet</strong> of oscillating particles<br>that propagates through <strong>solids</strong>",ammo:0,ammoPack:120,defaultAmmoPack:120,have:!1,wavePacketCycle:0,delay:40,propagationRate:20,waves:[],chooseFireMethod(){tech.is360Longitudinal?(this.fire=this.fire360Longitudinal,this.do=this.do360Longitudinal):tech.isLongitudinal?(this.fire=this.fireLongitudinal,this.do=this.doLongitudinal):(this.fire=this.fireTransverse,this.do=this.doTransverse)},do(){},do360Longitudinal(){ctx.strokeStyle="rgba(0,0,0,0.6)",ctx.lineWidth=2*tech.wavePacketDamage,ctx.beginPath();const t=700*Math.sqrt(tech.isBulletsLastLonger)/Math.sqrt(.5*tech.waveReflections),e=2*b.dmgScale*tech.wavePacketDamage*tech.waveBeamDamage*(tech.isBulletTeleport?1.43:1);for(let o=this.waves.length-1;o>-1;o--){if(ctx.moveTo(this.waves[o].position.x+this.waves[o].radius,this.waves[o].position.y),ctx.arc(this.waves[o].position.x,this.waves[o].position.y,this.waves[o].radius,0,2*Math.PI),!m.isBodiesAsleep){if(tech.isBulletTeleport&&Math.random()<.04){const t=400*Math.random();this.waves[o].position=Vector.add(this.waves[o].position,{x:t*(Math.random()-.5),y:t*(Math.random()-.5)})}for(let t=0,i=mob.length;t<i;t++){const i=Vector.magnitude(Vector.sub(this.waves[o].position,mob[t].position)),s=mob[t].radius+30;if(i+s>this.waves[o].radius&&i-s<this.waves[o].radius&&(mob[t].isBadTarget||(mob[t].force.x+=.01*(Math.random()-.5)*mob[t].mass,mob[t].force.y+=.01*(Math.random()-.5)*mob[t].mass),!mob[t].isShielded)){Matter.Body.setVelocity(mob[t],{x:.95*mob[t].velocity.x,y:.95*mob[t].velocity.y});let o=mob[t].vertices;const i=50+.15*mob[t].radius;ctx.moveTo(o[0].x+i*(Math.random()-.5),o[0].y+i*(Math.random()-.5));for(let t=1;t<o.length;t++)ctx.lineTo(o[t].x+i*(Math.random()-.5),o[t].y+i*(Math.random()-.5));ctx.lineTo(o[0].x+i*(Math.random()-.5),o[0].y+i*(Math.random()-.5)),mob[t].locatePlayer(),mob[t].damage(e/Math.sqrt(mob[t].radius))}}for(let t=0,e=body.length;t<e;t++){const e=Vector.magnitude(Vector.sub(this.waves[o].position,body[t].position)),i=20;if(e+i>this.waves[o].radius&&e-i<this.waves[o].radius){body[t].force.x+=.01*(Math.random()-.5)*body[t].mass,body[t].force.y+=(.01*(Math.random()-.5)-.25*simulation.g)*body[t].mass;let e=body[t].vertices;const o=25;ctx.moveTo(e[0].x+o*(Math.random()-.5),e[0].y+o*(Math.random()-.5));for(let t=1;t<e.length;t++)ctx.lineTo(e[t].x+o*(Math.random()-.5),e[t].y+o*(Math.random()-.5));ctx.lineTo(e[0].x+o*(Math.random()-.5),e[0].y+o*(Math.random()-.5))}}this.waves[o].radius+=tech.waveBeamSpeed*this.waves[o].expanding}this.waves[o].radius>t?(this.waves[o].expanding=-1,this.waves[o].reflection--,this.waves[o].reflection<1&&this.waves.splice(o,1)):this.waves[o].radius<25&&(this.waves[o].expanding=1,this.waves[o].reflection--,this.waves[o].reflection<1&&this.waves.splice(o,1))}ctx.stroke()},fire360Longitudinal(){m.fireCDcycle=m.cycle+Math.floor((input.down?3:8)*b.fireCDscale),this.waves.push({position:{x:m.pos.x,y:m.pos.y},radius:25,reflection:tech.waveReflections,expanding:!0})},doLongitudinal(){ctx.strokeStyle="rgba(0,0,0,0.6)",ctx.lineWidth=2*tech.wavePacketDamage,ctx.beginPath();const t=1100*tech.isBulletsLastLonger/Math.sqrt(.5*tech.waveReflections),e=2*b.dmgScale*tech.wavePacketDamage*tech.waveBeamDamage*(tech.isBulletTeleport?1.43:1);for(let o=this.waves.length-1;o>-1;o--){const i=Vector.add(this.waves[o].position,Vector.mult(this.waves[o].unit1,this.waves[o].radius)),s=Vector.add(this.waves[o].position,Vector.mult(this.waves[o].unit2,this.waves[o].radius));if(ctx.moveTo(i.x,i.y),ctx.arc(this.waves[o].position.x,this.waves[o].position.y,this.waves[o].radius,this.waves[o].angle,this.waves[o].angle+this.waves[o].arc),!m.isBodiesAsleep){if(tech.isBulletTeleport&&Math.random()<.05)if(Math.random()<.5);else{this.waves[o].arc*=1+1*(Math.random()-.5);const t=this.waves[o].arc/2,e=m.angle+.5*(Math.random()-.5);this.waves[o].angle=e-t,this.waves[o].unit1={x:Math.cos(e-t),y:Math.sin(e-t)},this.waves[o].unit2={x:Math.cos(e+t),y:Math.sin(e+t)}}let t=Matter.Query.ray(mob,i,s,50);for(let o=0;o<t.length;o++){const i=t[o].body;if(i.isBadTarget||(i.force.x+=.01*(Math.random()-.5)*i.mass,i.force.y+=.01*(Math.random()-.5)*i.mass),!i.isShielded){Matter.Body.setVelocity(i,{x:.95*i.velocity.x,y:.95*i.velocity.y});let t=i.vertices;const o=50+.15*i.radius;ctx.moveTo(t[0].x+o*(Math.random()-.5),t[0].y+o*(Math.random()-.5));for(let e=1;e<t.length;e++)ctx.lineTo(t[e].x+o*(Math.random()-.5),t[e].y+o*(Math.random()-.5));ctx.lineTo(t[0].x+o*(Math.random()-.5),t[0].y+o*(Math.random()-.5)),i.locatePlayer(),i.damage(e/Math.sqrt(i.radius))}}t=Matter.Query.ray(body,i,s,50);for(let e=0;e<t.length;e++){const o=t[e].body;o.force.x+=.01*(Math.random()-.5)*o.mass,o.force.y+=(.01*(Math.random()-.5)-.25*simulation.g)*o.mass;let i=o.vertices;const s=25;ctx.moveTo(i[0].x+s*(Math.random()-.5),i[0].y+s*(Math.random()-.5));for(let t=1;t<i.length;t++)ctx.lineTo(i[t].x+s*(Math.random()-.5),i[t].y+s*(Math.random()-.5));ctx.lineTo(i[0].x+s*(Math.random()-.5),i[0].y+s*(Math.random()-.5))}this.waves[o].radius+=2*tech.waveBeamSpeed*this.waves[o].expanding}this.waves[o].radius>t?(this.waves[o].expanding=-1,this.waves[o].reflection--,this.waves[o].reflection<1&&this.waves.splice(o,1)):this.waves[o].radius<25&&(this.waves[o].expanding=1,this.waves[o].reflection--,this.waves[o].reflection<1&&this.waves.splice(o,1))}ctx.stroke()},fireLongitudinal(){m.fireCDcycle=m.cycle+Math.floor((input.down?3:8)*b.fireCDscale);const t=input.down?.0785:.275;this.waves.push({position:{x:m.pos.x+25*Math.cos(m.angle),y:m.pos.y+25*Math.sin(m.angle)},angle:m.angle-t,unit1:{x:Math.cos(m.angle-t),y:Math.sin(m.angle-t)},unit2:{x:Math.cos(m.angle+t),y:Math.sin(m.angle+t)},arc:2*t,radius:25,reflection:tech.waveReflections,expanding:1})},doTransverse(){this.wavePacketCycle&&!input.fire&&(this.wavePacketCycle=0,m.fireCDcycle=m.cycle+Math.floor(this.delay*b.fireCDscale))},fireTransverse(){totalCycles=Math.floor(150.5*tech.waveReflections*tech.isBulletsLastLonger/Math.sqrt(.5*tech.waveReflections));const t=bullet.length;bullet[t]=Bodies.polygon(m.pos.x+25*Math.cos(m.angle),m.pos.y+25*Math.sin(m.angle),5,4,{angle:m.angle,cycle:-.5,endCycle:simulation.cycle+totalCycles,inertia:1/0,frictionAir:0,slow:0,amplitude:(input.down?5:10)*(this.wavePacketCycle%2?-1:1)*Math.sin(.088*(this.wavePacketCycle+1)),minDmgSpeed:0,dmg:b.dmgScale*tech.waveBeamDamage*tech.wavePacketDamage*(tech.isBulletTeleport?1.43:1),classType:"bullet",collisionFilter:{category:0,mask:0},beforeDmg(){},onEnd(){},do(){},query(){let t=1;if(Matter.Query.point(map,this.position).length)t=e;else{let e=Matter.Query.point(body,this.position);e.length&&(t=o,Matter.Body.setPosition(this,Vector.add(this.position,e[0].velocity)))}t!==this.slow&&(this.slow=t,Matter.Body.setVelocity(this,Vector.mult(Vector.normalise(this.velocity),tech.waveBeamSpeed*t))),q=Matter.Query.point(mob,this.position);for(let t=0;t<q.length;t++){let e=this.dmg;q[t].damage(e),q[t].alive&&q[t].foundPlayer(),Matter.Body.setVelocity(q[t],Vector.mult(q[t].velocity,.9)),this.endCycle=0,q[t].damageReduction&&simulation.drawList.push({x:this.position.x,y:this.position.y,radius:40*Math.log(e+1.1)*q[t].damageReduction+3,color:"rgba(0,0,0,0.4)",time:simulation.drawTime})}},wiggle(){this.cycle++;const t=Vector.mult(i,this.amplitude*Math.cos(this.cycle*tech.waveFrequency));Matter.Body.setPosition(this,Vector.add(this.position,t))}}),tech.isBulletTeleport&&(bullet[t].wiggle=function(){this.cycle++;const t=Vector.mult(i,this.amplitude*Math.cos(this.cycle*tech.waveFrequency));if(Math.random()<.005)if(Math.random()<.33){const e=500*Math.random();Matter.Body.setPosition(this,Vector.add({x:e*(Math.random()-.5),y:e*(Math.random()-.5)},Vector.add(this.position,t)))}else{const e=Vector.mult(this.velocity,50*(Math.random()-.5));Matter.Body.setPosition(this,Vector.add(e,Vector.add(this.position,t)))}else Matter.Body.setPosition(this,Vector.add(this.position,t))});let e=.1,o=.25;tech.isPhaseVelocity&&(e=3,o=1.9,bullet[t].dmg*=1.15),tech.waveReflections?(bullet[t].reflectCycle=totalCycles/tech.waveReflections,bullet[t].do=function(){m.isBodiesAsleep||(this.query(),this.cycle>this.reflectCycle&&(this.reflectCycle+=totalCycles/tech.waveReflections,Matter.Body.setVelocity(this,Vector.mult(this.velocity,-1))),this.wiggle())}):bullet[t].do=function(){m.isBodiesAsleep||(this.query(),this.wiggle())},Composite.add(engine.world,bullet[t]),Matter.Body.setVelocity(bullet[t],{x:tech.waveBeamSpeed*Math.cos(m.angle),y:tech.waveBeamSpeed*Math.sin(m.angle)});const i=Vector.normalise(Vector.perp(bullet[t].velocity));this.wavePacketCycle++,this.wavePacketCycle>35&&(m.fireCDcycle=m.cycle+Math.floor(this.delay*b.fireCDscale),this.wavePacketCycle=0)}},{name:"missiles",description:"launch <strong>homing</strong> missiles that <strong class='color-e'>explode</strong><br>crouch to <strong>rapidly</strong> launch smaller missiles",ammo:0,ammoPack:4,have:!1,fireCycle:0,do(){},fire(){const t=Math.pow(.9,tech.missileCount);if(input.down)if(m.fireCDcycle=m.cycle+10*b.fireCDscale/t,tech.missileCount>1)for(let e=0;e<tech.missileCount;e++)setTimeout((()=>{const o={x:m.pos.x,y:m.pos.y-40};b.missile(o,-Math.PI/2+.2*(Math.random()-.5)*Math.sqrt(tech.missileCount),-2,Math.sqrt(t)),bullet[bullet.length-1].force.x+=.025*t*(e-(tech.missileCount-1)/2)}),20*tech.missileCount*Math.random());else{const t={x:m.pos.x,y:m.pos.y-40};b.missile(t,-Math.PI/2+.2*(Math.random()-.5),-2)}else{m.fireCDcycle=m.cycle+50*b.fireCDscale/t;const e={x:Math.cos(m.angle),y:Math.sin(m.angle)},o=Vector.mult(Vector.perp(e),.08*t/Math.sqrt(tech.missileCount));if(tech.missileCount>1)for(let i=0;i<tech.missileCount;i++)setTimeout((()=>{const s={x:m.pos.x+40*e.x,y:m.pos.y+40*e.y};b.missile(s,m.angle,0,Math.sqrt(t)),bullet[bullet.length-1].force.x+=o.x*(i-(tech.missileCount-1)/2),bullet[bullet.length-1].force.y+=o.y*(i-(tech.missileCount-1)/2)}),40*tech.missileCount*Math.random());else{const t={x:m.pos.x+40*e.x,y:m.pos.y+40*e.y};b.missile(t,m.angle,0)}}}},{name:"grenades",description:"lob a single <strong>bouncy</strong> projectile<br><strong class='color-e'>explodes</strong> on <strong>contact</strong> or after one second",ammo:0,ammoPack:5,have:!1,do(){},fire(){const t=Math.pow(.93,tech.missileCount);m.fireCDcycle=m.cycle+Math.floor((input.down?40:30)*b.fireCDscale/t);const e={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},o=input.down?.12:.2;let i=m.angle-o*(tech.missileCount-1)/2;for(let s=0;s<tech.missileCount;s++)b.grenade(e,i,t),i+=o}},{name:"spores",description:"fire a <strong class='color-p' style='letter-spacing: 2px;'>sporangium</strong> that discharges <strong class='color-p' style='letter-spacing: 2px;'>spores</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spores</strong> seek out nearby mobs",ammo:0,ammoPack:2.3,have:!1,do(){},fire(){const t=bullet.length,e=m.angle;bullet[t]=Bodies.polygon(m.pos.x+30*Math.cos(m.angle),m.pos.y+30*Math.sin(m.angle),20,4.5,b.fireAttributes(e,!1)),b.fireProps(input.down?45:25,input.down?30:16,e,t),Matter.Body.setDensity(bullet[t],1e-6),bullet[t].endCycle=simulation.cycle+480+Math.max(0,120-2*bullet.length),bullet[t].frictionAir=0,bullet[t].friction=.5,bullet[t].radius=4.5,bullet[t].maxRadius=30,bullet[t].restitution=.3,bullet[t].minDmgSpeed=0,bullet[t].totalSpores=8+2*tech.isFastSpores+2*tech.isSporeFreeze*(tech.isSporeWorm?.5:1),bullet[t].stuck=function(){},bullet[t].beforeDmg=function(){},bullet[t].do=function(){function t(t){t.collisionFilter.mask=0,Matter.Body.setVelocity(t,{x:0,y:0}),t.do=t.grow}const e=Matter.Query.collides(this,mob);if(e.length)t(this),this.stuckTo=e[0].bodyA,this.stuckTo.isVerticesChange?this.stuckToRelativePosition={x:0,y:0}:this.stuckToRelativePosition=Vector.rotate(Vector.sub(this.position,this.stuckTo.position),-this.stuckTo.angle),this.stuck=function(){if(this.stuckTo&&this.stuckTo.alive){const t=Vector.rotate(this.stuckToRelativePosition,this.stuckTo.angle);Matter.Body.setPosition(this,Vector.add(Vector.add(t,this.stuckTo.velocity),this.stuckTo.position)),Matter.Body.setVelocity(this,this.stuckTo.velocity)}else this.collisionFilter.mask=cat.map,this.stuck=function(){this.force.y+=6e-4*this.mass}};else{const e=Matter.Query.collides(this,body);e.length?(e[0].bodyA.isNonStick?this.do=this.grow:(t(this),this.stuckTo=e[0].bodyA,this.stuckToRelativePosition=Vector.rotate(Vector.sub(this.position,this.stuckTo.position),-this.stuckTo.angle)),this.stuck=function(){if(this.stuckTo){const t=Vector.rotate(this.stuckToRelativePosition,this.stuckTo.angle);Matter.Body.setPosition(this,Vector.add(Vector.add(t,this.stuckTo.velocity),this.stuckTo.position))}else this.force.y+=6e-4*this.mass}):Matter.Query.collides(this,map).length?t(this):this.force.y+=6e-4*this.mass}ctx.fillStyle="rgba(0,200,125,0.16)",ctx.beginPath(),ctx.arc(this.position.x,this.position.y,this.maxRadius,0,2*Math.PI),ctx.fill()},bullet[t].grow=function(){if(this.stuck(),!m.isBodiesAsleep){let t=1.01;!tech.isSporeGrowth||simulation.cycle%40?(this.stuckTo&&this.stuckTo.alive&&(t=1.03),Matter.Body.scale(this,t,t),this.radius*=t,this.radius>this.maxRadius&&(this.endCycle=0)):(tech.isSporeWorm?simulation.cycle%80||b.worm(this.position):b.spore(this.position),t=.96,this.stuckTo&&this.stuckTo.alive&&(t=.9),Matter.Body.scale(this,t,t),this.radius*=t)}ctx.fillStyle="rgba(0,200,125,0.16)",ctx.beginPath(),ctx.arc(this.position.x,this.position.y,this.maxRadius,0,2*Math.PI),ctx.fill()},bullet[t].onEnd=function(){if(tech.isSporeWorm)for(let t=0,e=.5*this.totalSpores;t<e;t++)b.worm(this.position);else for(let t=0;t<this.totalSpores;t++)b.spore(this.position)}}},{name:"drones",description:"deploy drones that <strong>crash</strong> into mobs<br>crashes reduce their <strong>lifespan</strong> by 1 second",ammo:0,ammoPack:14.5,defaultAmmoPack:14.5,have:!1,do(){},fire(){tech.isDroneRadioactive?input.down?(b.droneRadioactive({x:m.pos.x+30*Math.cos(m.angle)+10*(Math.random()-.5),y:m.pos.y+30*Math.sin(m.angle)+10*(Math.random()-.5)},45),m.fireCDcycle=m.cycle+Math.floor(50*b.fireCDscale)):(b.droneRadioactive({x:m.pos.x+30*Math.cos(m.angle)+10*(Math.random()-.5),y:m.pos.y+30*Math.sin(m.angle)+10*(Math.random()-.5)},10),m.fireCDcycle=m.cycle+Math.floor(25*b.fireCDscale)):input.down?(b.drone({x:m.pos.x+30*Math.cos(m.angle)+10*(Math.random()-.5),y:m.pos.y+30*Math.sin(m.angle)+10*(Math.random()-.5)},55),m.fireCDcycle=m.cycle+Math.floor(10*b.fireCDscale)):(b.drone({x:m.pos.x+30*Math.cos(m.angle)+10*(Math.random()-.5),y:m.pos.y+30*Math.sin(m.angle)+10*(Math.random()-.5)},20),m.fireCDcycle=m.cycle+Math.floor(5*b.fireCDscale))}},{name:"foam",description:"spray bubbly foam that <strong>sticks</strong> to mobs<br><strong class='color-s'>slows</strong> mobs and does <strong class='color-d'>damage</strong> over time",ammo:0,ammoPack:22,have:!1,charge:0,isDischarge:!1,do(){if(this.charge>0){ctx.fillStyle="rgba(0,50,50,0.3)",ctx.beginPath();const t=10*Math.sqrt(this.charge),e=11+t;if(ctx.arc(m.pos.x+e*Math.cos(m.angle),m.pos.y+e*Math.sin(m.angle),t,0,2*Math.PI),ctx.fill(),this.isDischarge){this.charge--;const t=(input.down?.05:.6)*(Math.random()-.5),e=5+8*Math.random()+12*(tech.isAmmoFoamSize&&this.ammo<300),o=18-.4*e,i=m.angle+.15*(Math.random()-.5),s={x:o*Math.cos(i),y:o*Math.sin(i)},a={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)};tech.foamFutureFire?(simulation.drawList.push({x:a.x,y:a.y,radius:5,color:"rgba(0,50,50,0.3)",time:15*tech.foamFutureFire}),setTimeout((()=>{simulation.paused||(b.foam(a,Vector.rotate(s,t),e),bullet[bullet.length-1].damage*=1+.7*tech.foamFutureFire)}),250*tech.foamFutureFire)):b.foam(a,Vector.rotate(s,t),e),m.fireCDcycle=m.cycle+1}else input.fire||(this.isDischarge=!0)}else this.isDischarge&&(m.fireCDcycle=m.cycle+Math.floor(25*b.fireCDscale)),this.isDischarge=!1},fire(){tech.isCapacitor&&0===this.charge&&b.guns[b.activeGun].ammo>20&&(this.charge=20,b.guns[b.activeGun].ammo-=20,simulation.updateGunHUD()),this.charge++,m.fireCDcycle=m.cycle+Math.floor(1+.3*this.charge)}},{name:"harpoon",description:"fire a <strong>self-steering</strong> harpoon that uses <strong class='color-f'>energy</strong><br>to <strong>retract</strong> and refund its <strong class='color-ammo'>ammo</strong> cost",ammo:0,ammoPack:1,have:!1,do(){},fire(){const t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},e={distance:1e4,target:null},o={x:Math.cos(m.angle),y:Math.sin(m.angle)},i=tech.isLargeHarpoon?1+.1*Math.sqrt(this.ammo):1,s=7*(tech.isFilament?1+.01*Math.min(110,this.ammo):1)*Math.sqrt(i);if(input.down)if(tech.isRailGun){const t=bullet.length,e=3+.1*tech.isLargeHarpoon*Math.sqrt(this.ammo);bullet[t]=Bodies.rectangle(0,0,.015,.0015,{vertexGoal:[{x:-40*e,y:2*e,index:0,isInternal:!1},{x:-40*e,y:-2*e,index:1,isInternal:!1},{x:50*e,y:-3*e,index:3,isInternal:!1},{x:30*e,y:2*e,index:4,isInternal:!1}],density:.03,restitution:0,frictionAir:0,dmg:0,classType:"bullet",collisionFilter:{category:0,mask:cat.map|cat.body|cat.mob|cat.mobBullet|cat.mobShield},minDmgSpeed:5,beforeDmg(t){if(tech.isShieldPierce&&t.isShielded&&(t.isShielded=!1,requestAnimationFrame((()=>{t.isShielded=!0}))),t.shield&&!tech.isShieldPierce){for(let e=0,o=mob.length;e<o;e++)if(mob[e].id===t.shieldTargetID){Matter.Body.setVelocity(mob[e],Vector.mult(Vector.normalise(this.velocity),10));break}Matter.Body.setVelocity(this,{x:-.4*this.velocity.x,y:-.4*this.velocity.y})}else tech.fragments&&this.speed>10&&(b.targetedNail(this.position,17*tech.fragments),this.endCycle=0)},onEnd(){}}),m.fireCDcycle=1/0,Composite.add(engine.world,bullet[t]),bullet[t].endCycle=1/0,bullet[t].charge=0,bullet[t].do=function(){if(m.energy<.005&&!tech.isRailEnergyGain)return m.energy+=.05+.2*this.charge,m.fireCDcycle=m.cycle+120,this.endCycle=0,void b.refundAmmo();if(!input.fire&&this.charge>.6){Matter.Body.setVertices(this,this.vertexGoal),m.fireCDcycle=m.cycle+2,this.endCycle=simulation.cycle+140,this.collisionFilter.category=cat.bullet,Matter.Body.setPosition(this,{x:m.pos.x,y:m.pos.y}),Matter.Body.setAngle(this,m.angle);const t=120;Matter.Body.setVelocity(this,{x:m.Vx/2+t*this.charge*Math.cos(m.angle),y:m.Vy/2+t*this.charge*Math.sin(m.angle)}),this.do=function(){this.force.y+=3e-4*this.mass/this.charge};const e=(input.down?.1:.5)*this.charge*this.charge;player.force.x-=e*Math.cos(m.angle),player.force.y-=e*Math.sin(m.angle)*.35,function(t){for(let e=0,o=mob.length;e<o;++e){const o=Vector.sub(mob[e].position,m.pos),i=Vector.magnitude(o);if(i<t){const s=Math.min(t-i,1500),a=Vector.mult(Vector.normalise(o),.001*Math.sqrt(s)*mob[e].mass);mob[e].force.x+=a.x,mob[e].force.y+=a.y}}for(let e=0,o=body.length;e<o;++e){const o=Vector.sub(body[e].position,m.pos),i=Vector.magnitude(o);if(i<t){const s=Math.min(t-i,500),a=Vector.mult(Vector.normalise(o),.002*Math.sqrt(s)*body[e].mass);body[e].force.x+=a.x,body[e].force.y+=a.y-body[e].mass*simulation.g*1.5}}}(1200*this.charge)}else{tech.isFireMoveLock&&(Matter.Body.setVelocity(player,{x:0,y:-55*player.mass*simulation.g}),player.force.x=0,player.force.y=0),m.fireCDcycle=1/0;const e=this.charge;let o,i=tech.isCapacitor?.93:Math.min(.998,.985*(.98+.02*b.fireCDscale));this.charge=this.charge*i+1-i,m.energy+=(this.charge-e)*(tech.isRailEnergyGain?10:-.5);let s=3e3;const a=m.angle,l=[{x:m.pos.x+20*Math.cos(a),y:m.pos.y+20*Math.sin(a)},{x:m.pos.x+s*Math.cos(a),y:m.pos.y+s*Math.sin(a)}],n=function(t,e,i){for(let s=0;s<i.length;++s){let a=i[s].vertices;const l=a.length-1;for(let n=0;n<l;n++)if(results=simulation.checkLineIntersection(t,e,a[n],a[n+1]),results.onLine1&&results.onLine2){const e=t.x-results.x,l=t.y-results.y,r=e*e+l*l;r<o.dist2&&(o={x:results.x,y:results.y,dist2:r,who:i[s],v1:a[n],v2:a[n+1]})}if(results=simulation.checkLineIntersection(t,e,a[0],a[l]),results.onLine1&&results.onLine2){const e=t.x-results.x,n=t.y-results.y,r=e*e+n*n;r<o.dist2&&(o={x:results.x,y:results.y,dist2:r,who:i[s],v1:a[0],v2:a[l]})}}};o={x:null,y:null,dist2:1/0,who:null,v1:null,v2:null},n(l[0],l[1],mob),n(l[0],l[1],map),n(l[0],l[1],body),o.dist2!=1/0&&(l[l.length-1]={x:o.x,y:o.y}),ctx.beginPath(),ctx.moveTo(l[0].x,l[0].y),ctx.lineTo(l[1].x,l[1].y),ctx.strokeStyle="rgba(100,0,180,0.7)",ctx.lineWidth=1*this.charge,ctx.setLineDash([10,20]),ctx.stroke(),ctx.setLineDash([]);const r=m.pos.x,c=m.pos.y,h={x:Math.cos(m.angle),y:Math.sin(m.angle)},d=Vector.perp(h);function t(t,e){ctx.moveTo(r,c),ctx.bezierCurveTo(r+h.x*t,c+h.y*t,r+h.x*t+d.x*e,c+h.y*t+d.y*e,r+d.x*e,c+d.y*e),ctx.bezierCurveTo(r-h.x*t+d.x*e,c-h.y*t+d.y*e,r-h.x*t,c-h.y*t,r,c)}ctx.fillStyle="rgba(50,0,100,0.05)";for(let e=3;e<7;e++){const o=8*e*e*this.charge*(.93+.07*Math.random()),i=6*e*e*this.charge*(.93+.07*Math.random());ctx.beginPath(),t(o,i),t(o,-i),ctx.fill()}}}}else{for(let i=0,s=mob.length;i<s;++i)if(mob[i].alive&&!mob[i].isBadTarget&&0===Matter.Query.ray(map,m.pos,mob[i].position).length){const s=Vector.dot(o,Vector.normalise(Vector.sub(mob[i].position,m.pos))),a=Vector.magnitude(Vector.sub(t,mob[i].position));a<e.distance&&s>.95&&a*s*s*s*s>880&&(e.distance=a,e.target=mob[i])}b.harpoon(t,e.target,m.angle,i,!1,15),m.fireCDcycle=m.cycle+50*b.fireCDscale}else if(tech.extraHarpoons){const e=450*(tech.isFilament?1+.005*Math.min(110,this.ammo):1);let a=0;for(let l=0,n=mob.length;l<n;++l)if(mob[l].alive&&!mob[l].isBadTarget&&!mob[l].shield&&0===Matter.Query.ray(map,m.pos,mob[l].position).length){const n=Vector.dot(o,Vector.normalise(Vector.sub(mob[l].position,m.pos)));if(Vector.magnitude(Vector.sub(t,mob[l].position))<e&&n>.7&&this.ammo>0&&(this.ammo--,b.harpoon(t,mob[l],m.angle,i,!0,s),a++,a>tech.extraHarpoons))break}if(a<tech.extraHarpoons+1){const e=.1,o=tech.extraHarpoons+1-a;let l=m.angle-e*(o-1)/2;for(let a=0;a<o;a++)this.ammo>0&&(this.ammo--,b.harpoon(t,null,l,i,!0,s),l+=e)}this.ammo++,simulation.updateGunHUD(),m.fireCDcycle=m.cycle+90}else{for(let i=0,s=mob.length;i<s;++i)if(mob[i].alive&&!mob[i].isBadTarget&&0===Matter.Query.ray(map,m.pos,mob[i].position).length){const s=Vector.dot(o,Vector.normalise(Vector.sub(mob[i].position,m.pos))),a=Vector.magnitude(Vector.sub(t,mob[i].position));a<e.distance&&s>.88&&(e.distance=a,e.target=mob[i])}b.harpoon(t,e.target,m.angle,i,!0,s),m.fireCDcycle=m.cycle+90}const a=Vector.mult(Vector.normalise(Vector.sub(t,m.pos)),input.down?.015:.035);player.force.x-=a.x,player.force.y-=a.y,tech.harpoonDensity=.008}},{name:"mine",description:"toss a <strong>proximity</strong> mine that <strong>sticks</strong> to walls<br>refund <strong>undetonated</strong> mines on <strong>exiting</strong> a level",ammo:0,ammoPack:1.25,have:!1,do(){if(!input.field&&input.down&&!tech.isLaserMine){const t=60,e=40,o={x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)};ctx.strokeStyle="rgba(68, 68, 68, 0.2)",ctx.lineWidth=2,ctx.beginPath();for(let e=1.5,i=19;e<i+1;e++){const s=t*e/i;ctx.lineTo(m.pos.x+s*o.x,m.pos.y+s*o.y+.34*s*s)}ctx.stroke()}},fire(){if(input.down)if(tech.isLaserMine){const t=30,e={x:t*Math.cos(m.angle),y:t*Math.sin(m.angle)};b.laserMine(m.pos,e),m.fireCDcycle=m.cycle+Math.floor(65*b.fireCDscale)}else{const t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)};let e=36;Matter.Query.point(map,t).length>0&&(e=-2),b.mine(t,{x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)},0),m.fireCDcycle=m.cycle+Math.floor(55*b.fireCDscale)}else{const t={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)};let e=23;Matter.Query.point(map,t).length>0&&(e=-2),b.mine(t,{x:e*Math.cos(m.angle),y:e*Math.sin(m.angle)},0),m.fireCDcycle=m.cycle+Math.floor(35*b.fireCDscale)}}},{name:"laser",description:"emit a <strong>beam</strong> of collimated coherent <strong class='color-laser'>light</strong><br>drains <strong class='color-f'>energy</strong> instead of ammunition",ammo:0,ammoPack:1/0,have:!1,charge:0,do(){},fire(){},chooseFireMethod(){if(this.do=()=>{},tech.isPulseLaser)if(this.fire=()=>{const t=.01*tech.isLaserDiode*(tech.isCapacitor?10:1);m.energy>t&&this.charge<50*m.maxEnergy&&(m.energy-=t,this.charge+=100*t)},tech.historyLaser){const t=1+tech.historyLaser,e=Math.ceil(30-2*tech.historyLaser);this.do=()=>{if(this.charge>0){const o=4.1*Math.sqrt(this.charge);ctx.beginPath();for(let i=0;i<t;i++){const t=m.history[(m.cycle-i*e)%600],s=t.yOff-24.2859;ctx.moveTo(t.position.x,t.position.y-s),ctx.ellipse(t.position.x,t.position.y-s,o,.65*o,t.angle,0,2*Math.PI)}if(ctx.fillStyle=1===tech.isLaserDiode?`rgba(255,0,0,${.09*Math.sqrt(this.charge)})`:`rgba(0,0,255,${.09*Math.sqrt(this.charge)})`,ctx.fill(),!input.fire){if(this.charge>5){m.fireCDcycle=m.cycle+Math.floor(35*b.fireCDscale);for(let o=0;o<t;o++){const t=m.history[(m.cycle-o*e)%600],i=t.yOff-24.2859;b.pulse(1.65*this.charge,t.angle,{x:t.position.x,y:t.position.y-i})}}this.charge=0}}}}else this.do=()=>{if(this.charge>0&&(ctx.beginPath(),ctx.arc(m.pos.x,m.pos.y,4.2*Math.sqrt(this.charge),0,2*Math.PI),ctx.fillStyle=1===tech.isLaserDiode?`rgba(255,0,0,${.09*Math.sqrt(this.charge)})`:`rgba(0,0,255,${.09*Math.sqrt(this.charge)})`,ctx.fill(),!input.fire)){if(this.charge>5)if(m.fireCDcycle=m.cycle+Math.floor(35*b.fireCDscale),tech.beamSplitter){const t=input.down?.15:.35,e=m.angle-tech.beamSplitter*t/2;for(let o=0;o<1+tech.beamSplitter;o++)b.pulse(this.charge,e+o*t)}else b.pulse(1.8*this.charge,m.angle);this.charge=0}};else tech.beamSplitter?this.fire=this.fireSplit:tech.historyLaser?this.fire=this.fireHistory:tech.isWideLaser?this.fire=this.fireWideBeam:this.fire=this.fireLaser},fireLaser(){m.energy<tech.laserFieldDrain?m.fireCDcycle=m.cycle+100:(m.fireCDcycle=m.cycle,m.energy-=m.fieldRegen+tech.laserFieldDrain*tech.isLaserDiode,b.laser())},firePulse(){},fireSplit(){if(m.energy<tech.laserFieldDrain)m.fireCDcycle=m.cycle+100;else{m.fireCDcycle=m.cycle,m.energy-=m.fieldRegen+tech.laserFieldDrain*tech.isLaserDiode;let t=tech.laserDamage;const e={x:m.pos.x+20*Math.cos(m.angle),y:m.pos.y+20*Math.sin(m.angle)},o=input.down?.15:.35,i=m.angle-tech.beamSplitter*o/2;for(let s=0;s<1+tech.beamSplitter;s++)b.laser(e,{x:e.x+3e3*Math.cos(i+s*o),y:e.y+3e3*Math.sin(i+s*o)},t,tech.laserReflections,!1)}},fireWideBeam(){if(m.energy<tech.laserFieldDrain)m.fireCDcycle=m.cycle+100;else{m.fireCDcycle=m.cycle,m.energy-=m.fieldRegen+tech.laserFieldDrain*tech.isLaserDiode;const t={x:5e3*Math.cos(m.angle),y:5e3*Math.sin(m.angle)},e={x:7.5*Math.cos(m.angle+Math.PI/2),y:7.5*Math.sin(m.angle+Math.PI/2)},o={x:7.5*Math.cos(m.angle-Math.PI/2),y:7.5*Math.sin(m.angle-Math.PI/2)},i=.7*tech.laserDamage,s={x:m.pos.x+30*Math.cos(m.angle),y:m.pos.y+30*Math.sin(m.angle)},a={x:m.pos.x+15*Math.cos(m.angle),y:m.pos.y+15*Math.sin(m.angle)};ctx.strokeStyle=tech.laserColor,ctx.lineWidth=8,ctx.globalAlpha=.5,ctx.beginPath(),0===Matter.Query.ray(map,a,s).length&&0===Matter.Query.ray(body,a,s).length&&b.laser(a,{x:a.x+t.x,y:a.y+t.y},i,0,!0,.3);for(let l=1;l<tech.wideLaser;l++){let n=Vector.add(s,{x:l*e.x,y:l*e.y});0===Matter.Query.ray(map,a,n).length&&0===Matter.Query.ray(body,a,n).length&&(ctx.moveTo(a.x,a.y),ctx.lineTo(n.x,n.y),b.laser(n,{x:n.x+t.x,y:n.y+t.y},i,0,!0,.3)),n=Vector.add(s,{x:l*o.x,y:l*o.y}),0===Matter.Query.ray(map,a,n).length&&0===Matter.Query.ray(body,a,n).length&&(ctx.moveTo(a.x,a.y),ctx.lineTo(n.x,n.y),b.laser(n,{x:n.x+t.x,y:n.y+t.y},i,0,!0,.3))}ctx.stroke(),ctx.globalAlpha=1}},fireHistory(){if(m.energy<tech.laserFieldDrain)m.fireCDcycle=m.cycle+100;else{m.fireCDcycle=m.cycle,m.energy-=m.fieldRegen+tech.laserFieldDrain*tech.isLaserDiode;const t=.4*tech.laserDamage,e=Math.ceil(5.2-.2*tech.historyLaser);ctx.beginPath(),b.laser({x:m.pos.x+20*Math.cos(m.angle),y:m.pos.y+20*Math.sin(m.angle)},{x:m.pos.x+3e3*Math.cos(m.angle),y:m.pos.y+3e3*Math.sin(m.angle)},t,0,!0,.2);for(let o=1,i=5+5*tech.historyLaser;o<i;o++){const i=m.history[(m.cycle-o*e)%600],s=i.yOff-24.2859;b.laser({x:i.position.x+20*Math.cos(i.angle),y:i.position.y+20*Math.sin(i.angle)-s},{x:i.position.x+3e3*Math.cos(i.angle),y:i.position.y+3e3*Math.sin(i.angle)-s},t,0,!0,.2)}ctx.strokeStyle=tech.laserColor,ctx.lineWidth=1,ctx.stroke()}}}]};