diff --git a/.DS_Store b/.DS_Store index b6a3ab9..bd2f5c8 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/img/amplitude.webp b/img/amplitude.webp index 6e4e39b..202f93d 100644 Binary files a/img/amplitude.webp and b/img/amplitude.webp differ diff --git a/img/gun/wave.webp b/img/gun/wave.webp index fb115db..0c2e709 100644 Binary files a/img/gun/wave.webp and b/img/gun/wave.webp differ diff --git a/img/junk.webp b/img/junk.webp new file mode 100644 index 0000000..af38107 Binary files /dev/null and b/img/junk.webp differ diff --git a/img/propagation.webp b/img/propagation.webp index 7f8fe3c..c47af7f 100644 Binary files a/img/propagation.webp and b/img/propagation.webp differ diff --git a/index.html b/index.html index 7b27943..afe321a 100644 --- a/index.html +++ b/index.html @@ -25,7 +25,6 @@
-
diff --git a/js/bullet.js b/js/bullet.js index 9e5d1ac..168a2ad 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -547,7 +547,7 @@ const b = { y: where.y + range * Math.sin(angle) } ]; - const vertexCollision = function (v1, v1End, domain) { + const vertexCollision = function(v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -883,7 +883,7 @@ const b = { }, setGrenadeMode() { - grenadeDefault = function (where = { + grenadeDefault = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { @@ -893,7 +893,7 @@ const b = { bullet[me].explodeRad = 300 * size + 100 * tech.isBlockExplode; bullet[me].onEnd = b.grenadeEnd bullet[me].minDmgSpeed = 1; - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; speed = input.down ? 43 : 32 @@ -903,12 +903,12 @@ const b = { }); bullet[me].endCycle = simulation.cycle + Math.floor(input.down ? 120 : 80) * tech.isBulletsLastLonger; bullet[me].restitution = 0.4; - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0025; //extra gravity for harder arcs }; Composite.add(engine.world, bullet[me]); //add bullet to world } - grenadeRPG = function (where = { + grenadeRPG = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { @@ -918,7 +918,7 @@ const b = { bullet[me].explodeRad = 300 * size + 100 * tech.isBlockExplode; bullet[me].onEnd = b.grenadeEnd bullet[me].minDmgSpeed = 1; - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; speed = input.down ? 46 : 32 @@ -935,7 +935,7 @@ const b = { x: bullet[me].mass * MAG * Math.cos(angle), y: bullet[me].mass * MAG * Math.sin(angle) } - bullet[me].do = function () { + bullet[me].do = function() { this.force.x += this.thrust.x; this.force.y += this.thrust.y; if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { @@ -943,7 +943,7 @@ const b = { } }; } - grenadeRPGVacuum = function (where = { + grenadeRPGVacuum = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { @@ -953,7 +953,7 @@ const b = { bullet[me].explodeRad = 350 * size + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100 bullet[me].onEnd = b.grenadeEnd bullet[me].minDmgSpeed = 1; - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; speed = input.down ? 46 : 32 @@ -970,7 +970,7 @@ const b = { x: bullet[me].mass * MAG * Math.cos(angle), y: bullet[me].mass * MAG * Math.sin(angle) } - bullet[me].suck = function () { + bullet[me].suck = function() { const suck = (who, radius = this.explodeRad * 3.2) => { for (i = 0, len = who.length; i < len; i++) { const sub = Vector.sub(this.position, who[i].position); @@ -1010,7 +1010,7 @@ const b = { ctx.arc(this.position.x, this.position.y, radius, 0, 2 * Math.PI); ctx.fill(); } - bullet[me].do = function () { + bullet[me].do = function() { if (simulation.cycle > this.endCycle - this.suckCycles) { //suck this.do = this.suck } else if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { @@ -1022,7 +1022,7 @@ const b = { } }; } - grenadeVacuum = function (where = { + grenadeVacuum = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { @@ -1031,11 +1031,11 @@ const b = { Matter.Body.setDensity(bullet[me], 0.0002); bullet[me].explodeRad = 350 * size + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100 bullet[me].onEnd = b.grenadeEnd - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; bullet[me].restitution = 0.4; - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0025; //extra gravity for harder arcs const suckCycles = 40 @@ -1097,7 +1097,7 @@ const b = { Composite.add(engine.world, bullet[me]); //add bullet to world } - grenadeNeutron = function (where = { + grenadeNeutron = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { @@ -1132,9 +1132,9 @@ const b = { } } - bullet[me].beforeDmg = function () {}; - bullet[me].stuck = function () {}; - bullet[me].do = function () { + bullet[me].beforeDmg = function() {}; + bullet[me].stuck = function() {}; + bullet[me].do = function() { const onCollide = () => { this.collisionFilter.mask = 0; //non collide with everything Matter.Body.setVelocity(this, { @@ -1161,14 +1161,14 @@ const b = { //find the relative position for when the mob is at angle zero by undoing the mobs rotation this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle) } - this.stuck = function () { + this.stuck = function() { if (this.stuckTo && this.stuckTo.alive) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck } else { this.collisionFilter.mask = cat.map | cat.body | cat.player | cat.mob; //non collide with everything but map - this.stuck = function () { + this.stuck = function() { this.force.y += this.mass * 0.001; } } @@ -1184,7 +1184,7 @@ const b = { } else { this.do = this.radiationMode; } - this.stuck = function () { + this.stuck = function() { if (this.stuckTo) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) @@ -1205,7 +1205,7 @@ const b = { } } } - bullet[me].radiationMode = function () { //the do code after the bullet is stuck on something, projects a damaging radiation field + bullet[me].radiationMode = function() { //the do code after the bullet is stuck on something, projects a damaging radiation field this.stuck(); //runs different code based on what the bullet is stuck to this.damageRadius = this.damageRadius * 0.85 + 0.15 * this.maxDamageRadius //smooth radius towards max this.maxDamageRadius -= this.radiusDecay @@ -1267,9 +1267,9 @@ const b = { if (tech.isNeutronBomb) { b.grenade = grenadeNeutron if (tech.isRPG) { - b.guns[5].do = function () {} + b.guns[5].do = function() {} } else { - b.guns[5].do = function () { + b.guns[5].do = function() { if (!input.field && input.down) { const cycles = 80 const speed = input.down ? 35 : 20 //input.down ? 43 : 32 @@ -1290,7 +1290,7 @@ const b = { } } } else if (tech.isRPG) { - b.guns[5].do = function () {} + b.guns[5].do = function() {} if (tech.isVacuumBomb) { b.grenade = grenadeRPGVacuum } else { @@ -1298,7 +1298,7 @@ const b = { } } else if (tech.isVacuumBomb) { b.grenade = grenadeVacuum - b.guns[5].do = function () { + b.guns[5].do = function() { if (!input.field && input.down) { const cycles = Math.floor(input.down ? 50 : 30) //30 const speed = input.down ? 44 : 35 @@ -1318,7 +1318,7 @@ const b = { } } else { b.grenade = grenadeDefault - b.guns[5].do = function () { + b.guns[5].do = function() { if (!input.field && input.down) { const cycles = Math.floor(input.down ? 120 : 80) //30 const speed = input.down ? 43 : 32 @@ -2043,24 +2043,24 @@ const b = { y: m.Vy / 2 + 600 * thrust * Math.sin(bullet[me].angle) }); bullet[me].frictionAir = 0.002 - bullet[me].do = function () { + bullet[me].do = function() { if (this.speed < 20) this.force.y += 0.0005 * this.mass; this.draw(); } } if (tech.isHarpoonPowerUp && bullet[me].density > 0.01) { if (isReturn) { - bullet[me].draw = function () { + bullet[me].draw = function() { this.drawToggleHarpoon() this.drawString() } } else { - bullet[me].draw = function () { + bullet[me].draw = function() { this.drawToggleHarpoon() } } } else if (isReturn) { - bullet[me].draw = function () { + bullet[me].draw = function() { this.drawString() } } @@ -2250,7 +2250,7 @@ const b = { const transverse = Vector.normalise(Vector.perp(bullet[me].velocity)) if (180 - Math.abs(Math.abs(b.lastAngle - m.angle) - 180) > 0.13 || !b.wasExtruderOn) { bullet[me].isBranch = true; //don't draw stroke for this bullet - bullet[me].do = function () { + bullet[me].do = function() { if (this.endCycle < simulation.cycle + 1) this.isWave = false } } @@ -2281,7 +2281,7 @@ const b = { y: m.pos.y + range * Math.sin(m.angle) } ]; - const vertexCollision = function (v1, v1End, domain) { + const vertexCollision = function(v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -2420,7 +2420,7 @@ const b = { x: whereEnd.x, y: whereEnd.y }]; - const vertexCollision = function (v1, v1End, domain) { + const vertexCollision = function(v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -2461,7 +2461,7 @@ const b = { } }; - const checkForCollisions = function () { + const checkForCollisions = function() { best = { x: 1, y: 1, @@ -2474,7 +2474,7 @@ const b = { vertexCollision(path[path.length - 2], path[path.length - 1], map); vertexCollision(path[path.length - 2], path[path.length - 1], body); }; - const laserHitMob = function () { + const laserHitMob = function() { if (best.who.alive) { best.who.locatePlayer(); if (best.who.damageReduction) { @@ -2520,7 +2520,7 @@ const b = { Matter.Body.applyForce(best.who, path[index], force) } }; - const reflection = function () { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector + const reflection = function() { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector const n = Vector.perp(Vector.normalise(Vector.sub(best.v1, best.v2))); const d = Vector.sub(path[path.length - 1], path[path.length - 2]); const nn = Vector.mult(n, 2 * Vector.dot(d, n)); @@ -2828,7 +2828,7 @@ const b = { arm() { this.collisionFilter.mask = cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield | cat.bullet //can now collide with other bullets this.lookFrequency = simulation.cycle + 60 - this.do = function () { //overwrite the do method for this bullet + this.do = function() { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (simulation.cycle > this.lookFrequency) { this.isArmed = true @@ -2840,7 +2840,7 @@ const b = { color: "#f00", time: 4 }); - this.do = function () { //overwrite the do method for this bullet + this.do = function() { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (!(simulation.cycle % this.lookFrequency)) { //find mob targets const random = 300 * Math.random() @@ -2855,7 +2855,7 @@ const b = { if (tech.isMineSentry) { this.lookFrequency = 6 this.endCycle = simulation.cycle + 1020 - this.do = function () { //overwrite the do method for this bullet + this.do = function() { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (!(simulation.cycle % this.lookFrequency)) { //find mob targets this.endCycle -= 5 @@ -3455,7 +3455,7 @@ const b = { ctx.stroke(); } //power ups - if (!this.isImproved && !simulation.isChoosing && !tech.isExtraMaxEnergy) { + if (!this.isImproved && !simulation.isChoosing) { if (this.lockedOn) { for (let i = 0, len = powerUp.length; i < len; ++i) { //grab, but don't lock onto nearby power up if ( @@ -3665,7 +3665,7 @@ const b = { } } //power ups - if (!this.isImproved && !simulation.isChoosing && !tech.isExtraMaxEnergy) { + if (!this.isImproved && !simulation.isChoosing) { if (this.lockedOn) { //grab, but don't lock onto nearby power up for (let i = 0, len = powerUp.length; i < len; ++i) { @@ -4200,7 +4200,7 @@ const b = { Composite.add(engine.world, bullet[me]); //add bullet to world bullet[me].endCycle = simulation.cycle + 60 + 18 * Math.random(); bullet[me].dmg = tech.isNailRadiation ? 0 : dmg - bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech + bullet[me].beforeDmg = function(who) { //beforeDmg is rewritten with ice crystal tech if (tech.isNailRadiation) mobs.statusDoT(who, dmg * (tech.isFastRadiation ? 1.3 : 0.44), tech.isSlowRadiation ? 360 : (tech.isFastRadiation ? 60 : 180)) // one tick every 30 cycles if (tech.isNailCrit) { if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { @@ -4209,7 +4209,7 @@ const b = { } this.ricochet(who) }; - bullet[me].ricochet = function (who) { //use for normal nails, and ice crystal nails + bullet[me].ricochet = function(who) { //use for normal nails, and ice crystal nails if (tech.isRicochet) { const targets = [] //target nearby mobs for (let i = 0, len = mob.length; i < len; i++) { @@ -4234,7 +4234,7 @@ const b = { this.dmg += 2 } } - bullet[me].do = function () {}; + bullet[me].do = function() {}; }, needle(angle = m.angle) { const me = bullet.length; @@ -4248,7 +4248,7 @@ const b = { bullet[me].collisionFilter.mask = tech.isShieldPierce ? 0 : cat.mobShield // bullet[me].turnRate = 0.005 * (Math.random() - 0.5) bullet[me].isInMap = false - bullet[me].do = function () { + bullet[me].do = function() { const whom = Matter.Query.collides(this, mob) if (whom.length && this.speed > 20) { //if touching a mob for (let i = 0, len = whom.length; i < len; i++) { @@ -4306,7 +4306,7 @@ const b = { } else { bullet[me].endCycle = simulation.cycle + 100; bullet[me].collisionFilter.mask = tech.isShieldPierce ? cat.body : cat.body | cat.mobShield - bullet[me].do = function () { + bullet[me].do = function() { const whom = Matter.Query.collides(this, mob) if (whom.length && this.speed > 20) { //if touching a mob for (let i = 0, len = whom.length; i < len; i++) { @@ -4354,7 +4354,7 @@ const b = { x: 0, y: 0 }); - this.do = function () { + this.do = function() { if (!Matter.Query.collides(this, map).length) this.force.y += this.mass * 0.001; } if (tech.isNeedleIce) { @@ -4989,7 +4989,7 @@ const b = { y: this.lockedOn.position.y }]; - const vertexCollision = function (v1, v1End, domain) { + const vertexCollision = function(v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -5030,7 +5030,7 @@ const b = { } }; - const checkForCollisions = function () { + const checkForCollisions = function() { best = { x: 1, y: 1, @@ -5043,7 +5043,7 @@ const b = { vertexCollision(path[path.length - 2], path[path.length - 1], map); vertexCollision(path[path.length - 2], path[path.length - 1], body); }; - const laserHitMob = function () { + const laserHitMob = function() { if (best.who.alive) { best.who.locatePlayer(); if (best.who.damageReduction) { @@ -5089,7 +5089,7 @@ const b = { Matter.Body.applyForce(best.who, path[index], force) } }; - const reflection = function () { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector + const reflection = function() { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector const n = Vector.perp(Vector.normalise(Vector.sub(best.v1, best.v2))); const d = Vector.sub(path[path.length - 1], path[path.length - 2]); const nn = Vector.mult(n, 2 * Vector.dot(d, n)); @@ -5316,7 +5316,7 @@ const b = { y: this.position.y + range * unit.y } ]; - const vertexCollision = function (v1, v1End, domain) { + const vertexCollision = function(v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -5665,7 +5665,7 @@ const b = { }); bullet[me].endCycle = simulation.cycle + 180 - bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech + bullet[me].beforeDmg = function(who) { //beforeDmg is rewritten with ice crystal tech if (tech.isIncendiary) { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion b.explosion(this.position, 100 + (Math.random() - 0.5) * 20); //makes bullet do explosive damage at end @@ -5684,7 +5684,7 @@ const b = { bullet[me].minDmgSpeed = 10 bullet[me].frictionAir = 0.006; - bullet[me].rotateToVelocity = function () { //rotates bullet to face current velocity? + bullet[me].rotateToVelocity = function() { //rotates bullet to face current velocity? if (this.speed > 7) { const facing = { x: Math.cos(this.angle), @@ -5699,7 +5699,7 @@ const b = { } }; if (tech.isIncendiary) { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0008 this.rotateToVelocity() //collide with map @@ -5709,7 +5709,7 @@ const b = { } }; } else { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0008 this.rotateToVelocity() }; @@ -5751,7 +5751,7 @@ const b = { y: SPEED * Math.sin(m.angle) }); bullet[me].endCycle = simulation.cycle + 180 - bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech + bullet[me].beforeDmg = function(who) { //beforeDmg is rewritten with ice crystal tech if (tech.isIncendiary) { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion b.explosion(this.position, 100 + (Math.random() - 0.5) * 20); //makes bullet do explosive damage at end @@ -5770,7 +5770,7 @@ const b = { bullet[me].minDmgSpeed = 10 bullet[me].frictionAir = 0.006; - bullet[me].rotateToVelocity = function () { //rotates bullet to face current velocity? + bullet[me].rotateToVelocity = function() { //rotates bullet to face current velocity? if (this.speed > 7) { const facing = { x: Math.cos(this.angle), @@ -5785,7 +5785,7 @@ const b = { } }; if (tech.isIncendiary) { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0008 this.rotateToVelocity() //collide with map @@ -5795,7 +5795,7 @@ const b = { } }; } else { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0008 this.rotateToVelocity() }; @@ -5841,7 +5841,7 @@ const b = { y: m.Vy / 2 + speed * Math.sin(angle) }) //position, velocity, damage if (tech.isIceCrystals) { - bullet[bullet.length - 1].beforeDmg = function (who) { + bullet[bullet.length - 1].beforeDmg = function(who) { mobs.statusSlow(who, 60) if (tech.isNailRadiation) mobs.statusDoT(who, 1 * (tech.isFastRadiation ? 1.3 : 0.44), tech.isSlowRadiation ? 360 : (tech.isFastRadiation ? 60 : 180)) // one tick every 30 cycles if (tech.isNailCrit) { @@ -5910,7 +5910,7 @@ const b = { if (tech.isShotgunReversed) Matter.Body.setDensity(bullet[me], 0.0015) // bullet[me].restitution = 0.4 bullet[me].frictionAir = 0.034; - bullet[me].do = function () { + bullet[me].do = function() { const scale = 1 - 0.034 / tech.isBulletsLastLonger Matter.Body.scale(this, scale, scale); }; @@ -5933,10 +5933,10 @@ const b = { }); if (tech.isIncendiary) { bullet[me].endCycle = simulation.cycle + 60 - bullet[me].onEnd = function () { + bullet[me].onEnd = function() { b.explosion(this.position, 360 + (Math.random() - 0.5) * 60); //makes bullet do explosive damage at end } - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion }; } else { @@ -5946,7 +5946,7 @@ const b = { // bullet[me].restitution = 0.4 bullet[me].frictionAir = 0.004; bullet[me].turnMag = 0.04 * Math.pow(tech.bulletSize, 3.75) - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.002 if (this.speed > 6) { //rotates bullet to face current velocity? const facing = { @@ -5963,7 +5963,7 @@ const b = { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion } }; - bullet[me].beforeDmg = function (who) { + bullet[me].beforeDmg = function(who) { if (this.speed > 4) { if (tech.fragments) { b.targetedNail(this.position, 6 * tech.fragments * tech.bulletSize) @@ -5992,13 +5992,13 @@ const b = { x: speed * Math.cos(dirOff), y: speed * Math.sin(dirOff) }); - bullet[me].onEnd = function () { + bullet[me].onEnd = function() { b.explosion(this.position, 150 * (tech.isShotgunReversed ? 1.4 : 1) + (Math.random() - 0.5) * 40); //makes bullet do explosive damage at end } - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion }; - bullet[me].do = function () { + bullet[me].do = function() { if (Matter.Query.collides(this, map).length) this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion } Composite.add(engine.world, bullet[me]); //add bullet to world @@ -6127,11 +6127,11 @@ const b = { bullet[me].minDmgSpeed = 0; bullet[me].restitution = 1; bullet[me].friction = 0; - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; }; if (tech.isIncendiary) { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; if (Matter.Query.collides(this, map).length) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -6139,11 +6139,11 @@ const b = { } }; } else { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; }; } - bullet[me].beforeDmg = function (who) { + bullet[me].beforeDmg = function(who) { mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) if (tech.isIncendiary) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -6184,7 +6184,7 @@ const b = { bullet[me].restitution = 0.99; bullet[me].friction = 0; if (tech.isIncendiary) { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; if (Matter.Query.collides(this, map).length) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -6192,11 +6192,11 @@ const b = { } }; } else { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; }; } - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { if (tech.isIncendiary) { b.explosion(this.position, this.mass * 320 + 70 * Math.random()); //makes bullet do explosive damage at end this.endCycle = 0 @@ -6239,7 +6239,7 @@ const b = { bullet[me].restitution = 0.99; bullet[me].friction = 0; if (tech.isIncendiary) { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; if (Matter.Query.collides(this, map).length) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -6247,11 +6247,11 @@ const b = { } }; } else { - bullet[me].do = function () { + bullet[me].do = function() { this.force.y += this.mass * 0.0012; }; } - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { if (tech.isIncendiary) { b.explosion(this.position, this.mass * 320 + 70 * Math.random()); //makes bullet do explosive damage at end this.endCycle = 0 @@ -6645,7 +6645,7 @@ const b = { } }); if (tech.isBulletTeleport) { - bullet[me].wiggle = function () { + bullet[me].wiggle = function() { this.cycle++ const where = Vector.mult(transverse, this.amplitude * Math.cos(this.cycle * tech.waveFrequency)) if (Math.random() < 0.005) { @@ -6674,7 +6674,7 @@ const b = { } if (tech.waveReflections) { bullet[me].reflectCycle = totalCycles / tech.waveReflections //tech.waveLengthRange - bullet[me].do = function () { + bullet[me].do = function() { this.query() if (this.cycle > this.reflectCycle) { this.reflectCycle += totalCycles / tech.waveReflections @@ -6684,7 +6684,7 @@ const b = { this.wiggle() } } else { - bullet[me].do = function () { + bullet[me].do = function() { this.query() this.wiggle(); } @@ -6860,9 +6860,9 @@ const b = { bullet[me].restitution = 0.3; bullet[me].minDmgSpeed = 0; bullet[me].totalSpores = 8 + 2 * tech.isSporeFreeze + 4 * tech.isSporeColony - bullet[me].stuck = function () {}; - bullet[me].beforeDmg = function () {}; - bullet[me].do = function () { + bullet[me].stuck = function() {}; + bullet[me].beforeDmg = function() {}; + bullet[me].do = function() { function onCollide(that) { that.collisionFilter.mask = 0; //non collide with everything Matter.Body.setVelocity(that, { @@ -6886,14 +6886,14 @@ const b = { //find the relative position for when the mob is at angle zero by undoing the mobs rotation this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle) } - this.stuck = function () { + this.stuck = function() { if (this.stuckTo && this.stuckTo.alive) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck } else { this.collisionFilter.mask = cat.map; //non collide with everything but map - this.stuck = function () { + this.stuck = function() { this.force.y += this.mass * 0.0006; } } @@ -6909,7 +6909,7 @@ const b = { } else { this.do = this.grow; } - this.stuck = function () { + this.stuck = function() { if (this.stuckTo) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) @@ -6932,7 +6932,7 @@ const b = { ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI); ctx.fill(); } - bullet[me].grow = function () { + bullet[me].grow = function() { this.stuck(); //runs different code based on what the bullet is stuck to let scale = 1.01 if (tech.isSporeGrowth && !(simulation.cycle % 40)) { //release a spore @@ -6967,7 +6967,7 @@ const b = { ctx.fill(); }; //spawn bullets on end - bullet[me].onEnd = function () { + bullet[me].onEnd = function() { let count = 0 //used in for loop below const things = [ diff --git a/js/index.js b/js/index.js index 09ec3ba..679bd70 100644 --- a/js/index.js +++ b/js/index.js @@ -14,7 +14,7 @@ Math.hash = s => { document.getElementById("seed").placeholder = Math.initialSeed = String(Math.floor(Date.now() % 100000)) Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it -Math.seededRandom = function (min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined +Math.seededRandom = function(min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined Math.seed = (Math.seed * 9301 + 49297) % 233280; return min + Math.seed / 233280 * (max - min); } @@ -100,7 +100,7 @@ const color = { //light //difficulty is 0 easy, 1 normal, 2 hard, 4 why function getUrlVars() { let vars = {}; - window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, k, v) { + window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, k, v) { vars[k] = v; }); return vars; @@ -202,7 +202,7 @@ const ctx = canvas.getContext("2d"); document.body.style.backgroundColor = "#fff"; //disable pop up menu on right click -document.oncontextmenu = function () { +document.oncontextmenu = function() { return false; } @@ -412,7 +412,7 @@ ${simulation.isCheating ? "

lore disabled": ""} // } else { // text += `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` // } - const style = localSettings.isHideImages ? `style="height:auto;"` : `style = "background-image: url('img/${tech.tech[i].name}.webp');"` + const style = (localSettings.isHideImages || tech.tech[i].isJunk) ? `style="height:auto;"` : `style = "background-image: url('img/${tech.tech[i].name}.webp');"` const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; if (tech.tech[i].isNonRefundable) { text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` @@ -542,10 +542,10 @@ ${simulation.isCheating ? "

lore disabled": ""} }, 50); } } - //update tech text //disable not allowed tech + //update tech text for (let i = 0, len = tech.tech.length; i < len; i++) { const techID = document.getElementById("tech-" + i) - if ((!tech.tech[i].isJunk || localSettings.isJunkExperiment)) { //!tech.tech[i].isNonRefundable && //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! does removing this cause problems???? + if ((!tech.tech[i].isJunk || localSettings.isJunkExperiment) && !tech.tech[i].isLore) { if (tech.tech[i].allowed() || isAllowed || tech.tech[i].count > 0) { if (tech.tech[i].isFieldTech) { techID.classList.remove('experiment-grid-hide'); @@ -559,28 +559,20 @@ ${simulation.isCheating ? "

lore disabled": ""} } else { techID.innerHTML = build.techText(i) } - //deselect selected tech options if you don't have the tech any more // for example: when bot techs are converted after a bot upgrade tech is taken if (tech.tech[i].count === 0 && techID.classList.contains("build-tech-selected")) techID.classList.remove("build-tech-selected"); - if (techID.classList.contains("experiment-grid-disabled")) { techID.classList.remove("experiment-grid-disabled"); techID.setAttribute("onClick", `javascript: build.choosePowerUp(${i},'tech')`); } - // } else if (tech.tech[i].isGunTech || tech.tech[i].isFieldTech) { - // techID.classList.add('experiment-grid-hide'); - } else { //disabled color - // techID.innerHTML = `
${tech.tech[i].name}
requires: ${tech.tech[i].requires}` - // techID.innerHTML = `
${tech.tech[i].name}
requires: ${tech.tech[i].requires}` + } else { //disabled color for disabled tech techID.innerHTML = `
${tech.tech[i].name}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}` - // console.log(techID) if (!techID.classList.contains("experiment-grid-disabled")) { techID.classList.add("experiment-grid-disabled"); techID.onclick = null } if (tech.tech[i].count > 0) tech.removeTech(i) if (techID.classList.contains("build-tech-selected")) techID.classList.remove("build-tech-selected"); - if (tech.tech[i].isFieldTech) { techID.innerHTML = build.fieldTechText(i) } else if (tech.tech[i].isGunTech) { @@ -652,9 +644,8 @@ ${simulation.isCheating ? "

lore disabled": ""} // text += `
  ${build.nameLink(b.guns[i].name)}
${b.guns[i].description}
` } for (let i = 0, len = tech.tech.length; i < len; i++) { - if (!tech.tech[i].isJunk || localSettings.isJunkExperiment) { - const style = localSettings.isHideImages ? hideStyle : `style="background-image: url('img/${tech.tech[i].name}.webp');"` - + if ((!tech.tech[i].isJunk || localSettings.isJunkExperiment) && !tech.tech[i].isLore) { + const style = (localSettings.isHideImages || tech.tech[i].isJunk) ? hideStyle : `style="background-image: url('img/${tech.tech[i].name}.webp');"` if (tech.tech[i].allowed() && (!tech.tech[i].isNonRefundable || localSettings.isJunkExperiment)) { // || tech.tech[i].name === "+1 cardinality") { //|| tech.tech[i].name === "leveraged investment" text += `
` } else { //disabled @@ -749,17 +740,17 @@ ${simulation.isCheating ? "

lore disabled": ""} } console.log('n-gon build URL copied to clipboard.\nPaste into browser address bar.') console.log(url) - navigator.clipboard.writeText(url).then(function () { + navigator.clipboard.writeText(url).then(function() { /* clipboard successfully set */ if (isCustom) { - setTimeout(function () { + setTimeout(function() { alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.') }, 300); } - }, function () { + }, function() { /* clipboard write failed */ if (isCustom) { - setTimeout(function () { + setTimeout(function() { alert('copy failed') }, 300); } @@ -984,14 +975,14 @@ document.getElementById("control-table").addEventListener('click', (event) => { window.addEventListener("keydown", input.setKeys); } }); -document.getElementById("control-details").addEventListener("toggle", function () { +document.getElementById("control-details").addEventListener("toggle", function() { input.controlTextUpdate() input.endKeySensing(); }) document.getElementById("control-reset").addEventListener('click', input.setDefault); -window.addEventListener("keyup", function (event) { +window.addEventListener("keyup", function(event) { switch (event.code) { case input.key.right: case "ArrowRight": @@ -1018,7 +1009,7 @@ window.addEventListener("keyup", function (event) { } }); -window.addEventListener("keydown", function (event) { +window.addEventListener("keydown", function(event) { // console.log(event.code) switch (event.code) { case input.key.right: @@ -1055,7 +1046,7 @@ window.addEventListener("keydown", function (event) { case input.key.pause: if (!simulation.isChoosing && input.isPauseKeyReady && m.alive) { input.isPauseKeyReady = false - setTimeout(function () { + setTimeout(function() { input.isPauseKeyReady = true }, 300); if (simulation.paused) { @@ -1499,10 +1490,10 @@ document.getElementById("difficulty-select").addEventListener("input", () => { }); -document.getElementById("updates").addEventListener("toggle", function () { +document.getElementById("updates").addEventListener("toggle", function() { function loadJSON(path, success, error) { //generic function to get JSON var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function () { + xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { if (success) @@ -1521,7 +1512,7 @@ document.getElementById("updates").addEventListener("toggle", function () { /// https://api.github.com/repos/landgreen/n-gon/stats/commit_activity loadJSON('https://api.github.com/repos/landgreen/n-gon/commits', - function (data) { + function(data) { // console.log(data) for (let i = 0, len = 20; i < len; i++) { text += "" + data[i].commit.author.date.substr(0, 10) + " - "; //+ "
" @@ -1530,7 +1521,7 @@ document.getElementById("updates").addEventListener("toggle", function () { } document.getElementById("updates-div").innerHTML = text.replace(/\n/g, "
") }, - function (xhr) { + function(xhr) { console.error(xhr); } ); diff --git a/js/level.js b/js/level.js index 52dcb73..f12b5e2 100644 --- a/js/level.js +++ b/js/level.js @@ -21,15 +21,15 @@ const level = { // level.difficultyIncrease(30 * 4) //30 is near max on hard //60 is near max on why // m.maxHealth = m.health = 100 // tech.isRerollDamage = true - // powerUps.research.changeRerolls(5) + // powerUps.research.changeRerolls(20) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 // m.couplingChange(5) - // m.setField("time dilation") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave plasma torch + // m.setField("perfect diamagnetism") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave plasma torch // simulation.molecularMode = 2 // m.damage(0.1); - // b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser - // b.giveGuns("wave") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser + // b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser + // b.giveGuns("spores") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.guns[0].ammo = 10000 // tech.giveTech("alternator") // tech.giveTech("posture") @@ -100,19 +100,6 @@ const level = { m.resetHistory(); spawn.quantumEraserCheck(); //remove mobs from tech: quantum eraser - //used for generalist and pigeonhole principle - tech.buffedGun++ - if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0; - if (tech.isGunCycle) { - b.inventoryGun = tech.buffedGun; - simulation.switchGun(); - } - if (tech.isGunChoice && Number.isInteger(tech.buffedGun) && b.inventory.length) { - var gun = b.guns[b.inventory[tech.buffedGun]].name - simulation.makeTextLog(`pigeonhole principle: +${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for ${gun}`, 600); - } - - if (tech.isForeverDrones) { if (tech.isDroneRadioactive) { for (let i = 0; i < tech.isForeverDrones * 0.25; i++) { @@ -132,29 +119,7 @@ const level = { } } } - if (tech.isExtraMaxEnergy) { - tech.healMaxEnergyBonus += 0.1 * powerUps.totalPowerUps //Math.min(0.02 * powerUps.totalPowerUps, 0.51) - m.setMaxEnergy(); - } - if (tech.isSwitchReality) { - simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`); - m.switchWorlds() - simulation.trails() - powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); - } - if (tech.isHealLowHealth) { - // if (tech.isEnergyHealth) { - // var len = Math.ceil((m.maxEnergy - m.energy) / 0.33) - // } else { - // var len = Math.ceil((m.maxHealth - m.health) / 0.33) - // } - if (tech.isEnergyHealth) { - var len = 3 * (1 - m.energy / m.maxEnergy) //as a percent - } else { - var len = 3 * (1 - m.health / m.maxHealth) //as a percent - } - for (let i = 0; i < len; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "heal", false); - } + if (tech.isMACHO) spawn.MACHO() for (let i = 0; i < tech.wimpCount; i++) { spawn.WIMP() @@ -175,15 +140,40 @@ const level = { m.eyeFillColor = m.fieldMeterColor simulation.makeTextLog(`tech.isFlipFlopOn = true`); } - if (tech.isSpawnExitTech) { - for (let i = 0; i < 2; i++) powerUps.spawn(level.exit.x + 10 * (Math.random() - 0.5), level.exit.y - 100 + 10 * (Math.random() - 0.5), "tech", false) //exit - } // if (m.plasmaBall) m.plasmaBall.reset() if (m.plasmaBall) m.plasmaBall.fire() if (localSettings.entanglement && localSettings.entanglement.levelName === level.levels[level.onLevel]) { const flip = localSettings.entanglement.isHorizontalFlipped === simulation.isHorizontalFlipped ? 1 : -1 powerUps.directSpawn(flip * localSettings.entanglement.position.x, localSettings.entanglement.position.y, "entanglement", false); } + level.newLevelOrPhase() + }, + newLevelOrPhase() { //runs on each new level but also on final boss phases + //used for generalist and pigeonhole principle + tech.buffedGun++ + if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0; + if (tech.isGunCycle) { + b.inventoryGun = tech.buffedGun; + simulation.switchGun(); + } + if (tech.isGunChoice && Number.isInteger(tech.buffedGun) && b.inventory.length) { + var gun = b.guns[b.inventory[tech.buffedGun]].name + simulation.makeTextLog(`pigeonhole principle: +${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for ${gun}`, 600); + } + if (tech.isSwitchReality) { + simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`); + m.switchWorlds() + simulation.trails() + powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); + } + if (tech.isHealLowHealth) { + if (tech.isEnergyHealth) { + var len = 3 * (1 - m.energy / m.maxEnergy) //as a percent + } else { + var len = 3 * (1 - m.health / m.maxHealth) //as a percent + } + for (let i = 0; i < len; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "heal", false); + } }, trainingText(say) { simulation.lastLogTime = 0; //clear previous messages @@ -267,7 +257,7 @@ const level = { document.getElementById("health-bg").style.display = "none" document.getElementById("text-log").style.opacity = 0; //fade out any active text logs document.getElementById("fade-out").style.opacity = 1; //slowly fades out - setTimeout(function () { + setTimeout(function() { simulation.paused = true; level.disableExit = false; engine.world.bodies.forEach((body) => { @@ -557,7 +547,7 @@ const level = { x: who.position.x, y: who.position.y } - who.rotate = function () { + who.rotate = function() { if (!m.isBodiesAsleep) { Matter.Body.applyForce(this, { x: this.position.x + 100, @@ -1279,7 +1269,7 @@ const level = { y: 0 }, angleB) - draw = function () { + draw = function() { ctx.beginPath(); //portal let v = this.vertices; ctx.moveTo(v[0].x, v[0].y); @@ -1289,7 +1279,7 @@ const level = { ctx.fillStyle = this.color ctx.fill(); } - query = function (isRemoveBlocks = false) { + query = function(isRemoveBlocks = false) { if (Matter.Query.collides(this, [player]).length === 0) { //not touching player if (player.isInPortal === this) player.isInPortal = null } else if (player.isInPortal !== this) { //touching player @@ -1943,7 +1933,7 @@ const level = { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false - fireBlock = function (xPos, yPos) { + fireBlock = function(xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random()); const bodyBullet = body[body.length - 1] @@ -2000,7 +1990,7 @@ const level = { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false - fireBlock = function (xPos, yPos) { + fireBlock = function(xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random()); const bodyBullet = body[body.length - 1] @@ -3009,7 +2999,7 @@ const level = { // spawn.starter(1900, -500, 200) //big boy // for (let i = 0; i < 10; ++i) spawn.launcher(1900, -500) - spawn.suckerBoss(1900, -500) + // spawn.suckerBoss(1900, -500) // spawn.launcherBoss(3200, -500) // spawn.laserTargetingBoss(1700, -500) // spawn.powerUpBoss(1900, -500) @@ -7436,11 +7426,11 @@ const level = { body[body.length] = part4; body[body.length] = part5; body[body.length] = part6; - setTimeout(function () { + setTimeout(function() { chair.collisionFilter.category = cat.body; chair.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); - setTimeout(function () { + setTimeout(function() { chair2.collisionFilter.category = cat.body; chair2.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); @@ -7495,7 +7485,7 @@ const level = { body[body.length] = rightUpperLeg body[body.length] = rightLowerArm body[body.length] = rightUpperArm - setTimeout(function () { + setTimeout(function() { person.collisionFilter.category = cat.body; person.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); @@ -8960,7 +8950,7 @@ const level = { body[body.length] = part1; body[body.length] = part2; body[body.length] = part3; - setTimeout(function () { + setTimeout(function() { compoundParts.collisionFilter.category = cat.body; compoundParts.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); @@ -10225,19 +10215,19 @@ const level = { simulation.makeTextLog(`temple by Scar1337`); const V = Vector; - const Equation = (function () { + const Equation = (function() { function Equation(a, b, c) { this.a = a; this.b = b; this.c = c; } - Equation.prototype.getXfromY = function (y) { + Equation.prototype.getXfromY = function(y) { return (-this.b * y - this.c) / this.a; } - Equation.prototype.getYfromX = function (x) { + Equation.prototype.getYfromX = function(x) { return (-this.a * x - this.c) / this.b; } - Equation.fromPoints = function (v1, v2) { + Equation.fromPoints = function(v1, v2) { if (v1.x === v2.x) return new Equation(1, 0, -v1.x); if (v1.y === v2.y) return new Equation(0, 1, -v1.y); const d = (v2.y - v1.y) / (v2.x - v1.x); @@ -10245,7 +10235,7 @@ const level = { }; return Equation; })(); - const Rect = (function () { + const Rect = (function() { function Rect(x, y, w, h) { this.pos = { x, @@ -10254,14 +10244,14 @@ const level = { this.width = w; this.height = h; } - Rect.prototype.has = function ({ + Rect.prototype.has = function({ x, y }) { return x >= this.pos.x && x <= this.pos.x + this.width && y >= this.pos.y && y <= this.pos.y + this.height; } - Rect.prototype.hasLine = function (eq) { + Rect.prototype.hasLine = function(eq) { const leftInter = eq.getYfromX(this.pos.x); const rightInter = eq.getYfromX(this.pos.x + this.width); const topInter = eq.getXfromY(this.pos.y); @@ -10269,7 +10259,7 @@ const level = { (rightInter >= this.pos.y && rightInter <= this.pos.y + this.height) || (topInter >= this.pos.x && topInter <= this.pos.x + this.width); } - Rect.prototype.addToMap = function () { + Rect.prototype.addToMap = function() { spawn.mapRect(this.pos.x, this.pos.y, this.width, this.height); } Object.defineProperty(Rect.prototype, "midPos", { @@ -10280,10 +10270,10 @@ const level = { }); } }); - Rect.fromBounds = function (min, max) { + Rect.fromBounds = function(min, max) { return new Rect(min.x, min.y, max.x - min.x, max.y - min.y); } - Rect.prototype.isCollidingWith = function (other) { + Rect.prototype.isCollidingWith = function(other) { const tc = { p1: [this.pos.x, this.pos.y], p2: [this.pos.x + this.width, this.pos.y + this.height] @@ -10344,14 +10334,14 @@ const level = { me.attackCycle = 0; me.lastAttackCycle = 0; Matter.Body.setDensity(me, 0.012); // extra dense, normal is 0.001 // makes effective life much larger - me.onDeath = function () { + me.onDeath = function() { // applying forces to player doesn't seem to work inside this method, not sure why powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); }; me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); - me.do = function () { + me.do = function() { // keep it slow, to stop issues from explosion knock backs if (this.speed > 1) { Matter.Body.setVelocity(this, { @@ -10448,13 +10438,13 @@ const level = { me.attackCycle = 0; me.maxAttackCycle = isDark ? 90 : 240; Matter.Body.setDensity(me, 0.006); // extra dense, normal is 0.001 // makes effective life much larger - me.onDeath = function () { + me.onDeath = function() { powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); }; me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); - me.do = function () { + me.do = function() { // keep it slow, to stop issues from explosion knock backs if (this.speed > 2) { Matter.Body.setVelocity(this, { @@ -10506,12 +10496,12 @@ const level = { me.maxAttackCycle = 10; me.inertia = Infinity; } - me.do = isDark ? function () { + me.do = isDark ? function() { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 }); - } : function () { + } : function() { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 @@ -10551,7 +10541,7 @@ const level = { let me = mob[mob.length - 1]; me.fill = "#ace"; me.damageReduction = 0; - me.onDeath = function () { + me.onDeath = function() { //damage player if in range if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage @@ -10565,7 +10555,7 @@ const level = { time: simulation.drawTime }); }; - me.do = function () { + me.do = function() { this.timeLimit(); ctx.beginPath(); //draw explosion outline ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay @@ -10599,7 +10589,7 @@ const level = { me.lastAttackCycle = 0; me.spawnCycle = 0; Matter.Body.setDensity(me, 0.08); //extra dense //normal is 0.001 //makes effective life much larger - me.onDeath = function () { + me.onDeath = function() { for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i] !== this) { @@ -10618,7 +10608,7 @@ const level = { }; me.nextHealthThreshold = 0.75; me.trapCycle = 0; - me.onDamage = function () { + me.onDamage = function() { if (this.health < this.nextHealthThreshold) { this.health = this.nextHealthThreshold - 0.01 this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25 @@ -10641,7 +10631,7 @@ const level = { radius: 500, id: 2 }]; - me.ring = function () { + me.ring = function() { if (this.isInvulnerable) return; ctx.lineWidth = 10; for (const ring of this.rings) { @@ -10653,7 +10643,7 @@ const level = { DrawTools.arcOut(this.position.x, this.position.y, radius, 0, Math.PI * 2); } } - me.horizon = function () { + me.horizon = function() { if (this.isInvulnerable) return this.fill = "#f00"; // eventHorizon waves in and out const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)); @@ -10708,7 +10698,7 @@ const level = { DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); } } - me.periodicSpawns = function () { + me.periodicSpawns = function() { if (this.isInvulnerable) return; this.spawnCycle++; // Spawn annoying purple thing(s) that chases the player @@ -10748,7 +10738,7 @@ const level = { spawn.allowShields = true; } } - me.invulnerableTrap = function () { + me.invulnerableTrap = function() { if (this.trapCycle < 1) return; this.trapCycle++; // 24 is just an arbitrarily large number @@ -10800,7 +10790,7 @@ const level = { ctx.fillText("!", 2700, -14350); ctx.shadowBlur = 0; } - me.do = function () { + me.do = function() { this.checkStatus(); this.horizon(); this.ring(); @@ -10821,7 +10811,7 @@ const level = { let bounds = []; let mobPositionsQueue = Array.from(Array(10), () => []); m.oldDeath = m.death; - m.death = function () { + m.death = function() { if (!tech.isImmortal) { requestAnimationFrame(() => color.map = "#444"); m.death = m.oldDeath; @@ -10932,7 +10922,7 @@ const level = { spawn.mapRect(-500, -8250, 800, 20); for (let i = 0; i < 2; i++) spawn.mapRect(-250, -8400 + 150 * i, 500, 60); const room2SlimePit = level.hazard(-400, -8410, 800, 1090); - room2SlimePit.logic = function () { + room2SlimePit.logic = function() { if (this.height > 0 && Matter.Query.region([player], this).length) { if (m.immuneCycle < m.cycle) { // Trolled @@ -10972,7 +10962,7 @@ const level = { }); } } - room2SlimePit.draw = function () { + room2SlimePit.draw = function() { if (this.isOn) { ctx.fillStyle = "hsla(160, 100%, 35%, 0.75)"; ctx.fillRect(this.min.x, this.min.y, this.width, this.height); @@ -11174,7 +11164,7 @@ const level = { } }, room2GeneratedPath: { - rects: (function () { + rects: (function() { const rects = []; for (let i = 0; i < 4; i++) { rects.push(new Rect(-1405 + (i & 1) * 200, -9700 + i * 300, 205, 30)); @@ -11205,16 +11195,16 @@ const level = { } }, room3Rotors: { - rotor1: (function () { + rotor1: (function() { const rotor = level.spinner(900, -13700, 200, 30); - rotor.rotate = function () { + rotor.rotate = function() { Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity + 0.01) * 0.9) } return rotor; })(), - rotor2: (function () { + rotor2: (function() { const rotor = level.spinner(2700, -13700, 200, 30); - rotor.rotate = function () { + rotor.rotate = function() { Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity - 0.01) * 0.9) } return rotor; @@ -12170,7 +12160,7 @@ const level = { me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob | cat.bullet me.g = simulation.g me.leaveBody = me.isDropPowerUp = false - me.do = function () { + me.do = function() { this.gravity() // apply shock damage when touching the map, if it's fast if (this.speed > 5) { @@ -12185,7 +12175,7 @@ const level = { this.fill = `rgb(${232 * this.health}, 191, 40)` } - me.onDeath = function () { + me.onDeath = function() { const END = Math.floor(input.down ? 10 : 7) const totalBullets = 10 const angleStep = (input.down ? 0.4 : 1.3) / totalBullets @@ -12209,16 +12199,16 @@ const level = { x: speed * Math.cos(dirOff), y: speed * Math.sin(dirOff) }) - bullet[me].onEnd = function () { + bullet[me].onEnd = function() { b.explosion( this.position, 150 + (Math.random() - 0.5) * 40 ) //makes bullet do explosive damage at end } - bullet[me].beforeDmg = function () { + bullet[me].beforeDmg = function() { this.endCycle = 0 //bullet ends cycle after hitting a mob and triggers explosion } - bullet[me].do = function () {} + bullet[me].do = function() {} Composite.add(engine.world, bullet[me]) //add bullet to world } // barrels drop a ton of ammo and some heals, scales up with difficulty because I have mercy @@ -12326,7 +12316,7 @@ const level = { mobs.spawn(x, y + chainLength + radius * 2, 4, trappedMob.radius + 50, 'rgba(150, 255, 150, 0.3)') const cage = mob[mob.length - 1] cage.g = simulation.g - cage.do = function () { + cage.do = function() { this.gravity() } // label it @@ -12624,7 +12614,7 @@ const level = { const color = `rgba(${150 + 105 * charge}, 81, 50, 0.6)` mobs.spawn(origin.x, origin.y, 12, 20 + 20 * charge, color) const me = mob[mob.length - 1] - me.end = function () { + me.end = function() { simulation.drawList.push({ // some nice graphics x: this.position.x, @@ -12647,7 +12637,7 @@ const level = { me.life = 0 me.isDropPowerUp = false me.leaveBody = false - me.do = function () { + me.do = function() { // die on collision with the map if (Matter.Query.collides(this, map).length > 0) { this.end() @@ -12710,7 +12700,7 @@ const level = { me.bossPos = null // the position that the mob remembers when charging me.density = me.density * 2 Matter.Body.setDensity(me, 0.0022 * 3 + 0.0002 * Math.sqrt(simulation.difficulty)) //extra dense - me.do = function () { + me.do = function() { // if the boss is dead, die if (!parentBoss.alive) { this.death() @@ -12778,7 +12768,7 @@ const level = { // draw energy bar drawEnergyBar(this) } - me.onDeath = function () { + me.onDeath = function() { // remove itself from the list const beacons = parentBoss.energyBeacons beacons.splice(beacons.indexOf(this), 1) @@ -12823,7 +12813,7 @@ const level = { me.showHealthBar = false me.collisionFilter.category = cat.mobBullet me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet - me.do = function () { + me.do = function() { this.alwaysSeePlayer() this.attraction() this.timeLimit() @@ -12854,7 +12844,7 @@ const level = { // ctx.fillStyle = 'rgba(252, 0, 143, 1)' // ctx.fillText(~~this.score, this.position.x - this.radius, this.position.y - this.radius) } - me.onHit = function () { + me.onHit = function() { // hitting the player gives a 50 points score bonus this.score += 50 this.score += this.mass * 2 // bigger mass = bigger damage, add that too @@ -12862,7 +12852,7 @@ const level = { this.hitPlayer = true this.explode(this.mass) } - me.onDeath = function () { + me.onDeath = function() { if (!this.hitPlayer) { // if it didn't hit the player, give it a score based on its distance this.score += 10000 / this.distanceToPlayer() @@ -12916,7 +12906,7 @@ const level = { me.laserRange = radius * 4 Matter.Body.setDensity(me, 0.0022 * 4 + 0.0002 * Math.sqrt(simulation.difficulty)) //extra dense //normal is 0.001 //makes effective life much larger - me.onDeath = function () { + me.onDeath = function() { if (spawnBossPowerUp) { powerUps.spawnBossPowerUp(this.position.x, this.position.y) const amount = ~~(5 * Math.random() * simulation.difficulty / 10) * 2 @@ -12935,8 +12925,8 @@ const level = { // stop spawning barrels bossInit = false } - me.onDamage = function () {} - me.spawnBeacon = function () { + me.onDamage = function() {} + me.spawnBeacon = function() { // the vertex to spawn the beacon from const vert = this.vertices[~~(Math.random() * this.vertices.length)] // the position should be a little to the side to prevent crashing into the boss @@ -12952,7 +12942,7 @@ const level = { y: this.velocity.y + velocity.y }) } - me.spawnOrbs = function () { + me.spawnOrbs = function() { Matter.Body.setAngularVelocity(this, 0.11) // sort the vertices by the distance to the player const sorted = [...this.vertices].sort(dist2) @@ -13009,7 +12999,7 @@ const level = { }) } } - me.do = function () { + me.do = function() { this.seePlayerCheck() this.checkStatus() this.attraction() diff --git a/js/player.js b/js/player.js index 7110e5b..7c6a54a 100644 --- a/js/player.js +++ b/js/player.js @@ -423,7 +423,7 @@ const m = { m.health = 1; // m.addHealth(1) - simulation.wipe = function () { //set wipe to have trails + simulation.wipe = function() { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } @@ -433,8 +433,8 @@ const m = { m.switchWorlds() const swapPeriod = 1000 for (let i = 0, len = 5; i < len; i++) { - setTimeout(function () { - simulation.wipe = function () { //set wipe to have trails + setTimeout(function() { + simulation.wipe = function() { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } @@ -444,14 +444,14 @@ const m = { simulation.isTextLogOpen = true; simulation.makeTextLog(`simulation.amplitude = 0.${len - i - 1}`, swapPeriod); simulation.isTextLogOpen = false; - simulation.wipe = function () { //set wipe to have trails + simulation.wipe = function() { //set wipe to have trails ctx.fillStyle = `rgba(255,255,255,${(i + 1) * (i + 1) * 0.006})`; ctx.fillRect(0, 0, canvas.width, canvas.height); } }, (i + 1) * swapPeriod); } - setTimeout(function () { - simulation.wipe = function () { //set wipe to normal + setTimeout(function() { + simulation.wipe = function() { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } simulation.isTextLogOpen = true; @@ -467,7 +467,7 @@ const m = { document.getElementById("text-log").style.opacity = 0; //fade out any active text logs document.getElementById("fade-out").style.opacity = 0.9; //slowly fade to 90% white on top of canvas // build.shareURL(false) - setTimeout(function () { + setTimeout(function() { Composite.clear(engine.world); Engine.clear(engine); simulation.splashReturn(); @@ -642,7 +642,7 @@ const m = { if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles let isDrawPlayer = true - const shortPause = function () { + const shortPause = function() { if (m.defaultFPSCycle < m.cycle) { //back to default values simulation.fpsCap = simulation.fpsCapDefault simulation.fpsInterval = 1000 / simulation.fpsCap; @@ -716,13 +716,13 @@ const m = { for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); m.energy = m.maxEnergy if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds - simulation.wipe = function () { //set wipe to have trails + simulation.wipe = function() { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0.03)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } - setTimeout(function () { + setTimeout(function() { tech.maxDuplicationEvent() - simulation.wipe = function () { //set wipe to normal + simulation.wipe = function() { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } }, 3000); @@ -745,13 +745,13 @@ const m = {
${powerUps.research.count}`) for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds - simulation.wipe = function () { //set wipe to have trails + simulation.wipe = function() { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0.03)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } - setTimeout(function () { + setTimeout(function() { tech.maxDuplicationEvent() - simulation.wipe = function () { //set wipe to normal + simulation.wipe = function() { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } }, 3000); @@ -771,7 +771,7 @@ const m = { if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding // m.holdingMassScale = 0.5 for most fields if (m.isCloak) m.fireCDcycle = m.cycle //forced exit cloak } - const normalFPS = function () { + const normalFPS = function() { if (m.defaultFPSCycle < m.cycle) { //back to default values simulation.fpsCap = simulation.fpsCapDefault simulation.fpsInterval = 1000 / simulation.fpsCap; @@ -1058,7 +1058,7 @@ const m = { ctx.fillRect(xOff, yOff, range * m.energy, 10); } }, - drawRegenEnergyCloaking: function () { + drawRegenEnergyCloaking: function() { if (m.energy < m.maxEnergy) { // replaces m.drawRegenEnergy() with custom code m.regenEnergy(); const xOff = m.pos.x - m.radius * m.maxEnergy @@ -1090,11 +1090,11 @@ const m = { m.fieldRegen *= 0.6 } }, - regenEnergy: function () { //used in drawRegenEnergy // rewritten by some tech + regenEnergy: function() { //used in drawRegenEnergy // rewritten by some tech if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 }, - regenEnergyDefault: function () { + regenEnergyDefault: function() { if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 }, @@ -1279,7 +1279,7 @@ const m = { m.holdingTarget.friction = m.holdingTarget.frictionStatic = m.holdingTarget.frictionAir = 0.001 } //check every second to see if player is away from thrown body, and make solid - const solid = function (that) { + const solid = function(that) { const dx = that.position.x - player.position.x; const dy = that.position.y - player.position.y; if (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) { @@ -1311,7 +1311,7 @@ const m = { m.definePlayerMass() //return to normal player mass if (tech.isAddBlockMass) { - const expand = function (that, massLimit) { + const expand = function(that, massLimit) { if (that.mass < massLimit) { const scale = 1.05; Matter.Body.scale(that, scale, scale); @@ -1698,7 +1698,7 @@ const m = { description: `use energy to deflect mobs
generate 6 energy per second`, //
100 max energy effect: () => { - m.hold = function () { + m.hold = function() { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -1796,7 +1796,7 @@ const m = { } else { m.harmonicShield = m.harmonicAtomic } - m.hold = function () { + m.hold = function() { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -1976,7 +1976,7 @@ const m = { } } } - m.hold = function () { + m.hold = function() { const wave = Math.sin(m.cycle * 0.022); m.fieldRange = 180 + 12 * wave + 100 * tech.isBigField m.fieldArc = 0.35 + 0.045 * wave + 0.065 * tech.isBigField //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) @@ -1987,8 +1987,12 @@ const m = { m.throwBlock(); } else if (input.field) { //not hold but field button is pressed //float while field is on + // console.log(m.angle, Math.abs(m.angle + Math.PI / 2)) + + // + const angleReduction = 0.1 + (Math.PI / 2 - Math.min(Math.PI / 2, Math.abs(m.angle + Math.PI / 2))) if (player.velocity.y > 1) { - player.force.y -= (tech.isBigField ? 0.87 : 0.7) * player.mass * simulation.g; + player.force.y -= angleReduction * (tech.isBigField ? 0.87 : 0.7) * player.mass * simulation.g; Matter.Body.setVelocity(player, { x: player.velocity.x, y: 0.98 * player.velocity.y @@ -2084,7 +2088,7 @@ const m = { m.fieldHarmReduction = 0.45; //55% reduction m.fieldDrawRadius = 0; - m.hold = function () { + m.hold = function() { m.airSpeedLimit = 125 //5 * player.mass * player.mass m.FxAir = 0.016 if (m.isHolding) { @@ -2234,7 +2238,7 @@ const m = { effect: () => { m.fieldMeterColor = "#ff0" m.eyeFillColor = m.fieldMeterColor - m.hold = function () { + m.hold = function() { if (m.energy > m.maxEnergy - 0.02 && m.fieldCDcycle < m.cycle && !input.field && bullet.length < 300 && (m.cycle % 2)) { if (simulation.molecularMode === 0) { if (tech.isSporeFlea) { @@ -2621,7 +2625,7 @@ const m = { Composite.add(engine.world, m.plasmaBall); // m.plasmaBall.startingVertices = m.plasmaBall.vertices.slice(); - m.hold = function () { + m.hold = function() { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -2712,7 +2716,7 @@ const m = { m.plasmaBall.do() } } else if (tech.isExtruder) { - m.hold = function () { + m.hold = function() { b.isExtruderOn = false if (m.isHolding) { m.drawHold(m.holdingTarget); @@ -2754,7 +2758,7 @@ const m = { ctx.stroke(); } } else { - m.hold = function () { + m.hold = function() { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -2818,7 +2822,7 @@ const m = { if (tech.isRewindField) { this.rewindCount = 0 m.grabPowerUpRange2 = 300000 - m.hold = function () { + m.hold = function() { // console.log(m.fieldCDcycle) m.grabPowerUp(); // //grab power ups @@ -2914,7 +2918,7 @@ const m = { } else { m.fieldFire = true; m.isBodiesAsleep = false; - m.hold = function () { + m.hold = function() { if (m.isHolding) { m.wakeCheck(); m.drawHold(m.holdingTarget); @@ -2981,7 +2985,7 @@ const m = { m.isSneakAttack = true; m.sneakAttackCycle = 0; m.enterCloakCycle = 0; - m.drawCloak = function () { + m.drawCloak = function() { m.fieldPhase += 0.007 const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5) ctx.beginPath(); @@ -2995,7 +2999,7 @@ const m = { ctx.globalCompositeOperation = "source-over"; ctx.clip(); } - m.hold = function () { + m.hold = function() { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -3275,7 +3279,7 @@ const m = { m.fieldOn = false; m.fieldRadius = 0; m.drop(); - m.hold = function () { + m.hold = function() { if (input.field) { if (m.fieldCDcycle < m.cycle) { const scale = 25 @@ -3459,7 +3463,7 @@ const m = { //wormholes attract blocks and power ups
description: "use energy to tunnel through a wormhole
+3% chance to duplicate spawned power ups
generate 6 energy per second", //
bullets may also traverse wormholes drain: 0, - effect: function () { + effect: function() { m.fieldMeterColor = "#bbf" //"#0c5" m.eyeFillColor = m.fieldMeterColor @@ -3467,7 +3471,7 @@ const m = { m.fieldRange = 0 powerUps.setDupChance(); //needed after adjusting duplication chance - m.hold = function () { + m.hold = function() { // m.hole = { //this is reset with each new field, but I'm leaving it here for reference // isOn: false, // isReady: true, diff --git a/js/powerup.js b/js/powerup.js index 91eccd6..d386473 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -322,7 +322,7 @@ const powerUps = { document.getElementById("choose-grid").style.visibility = "visible" requestAnimationFrame(() => { - ctx.fillStyle = `rgba(221,221,221,0.6)`; + ctx.fillStyle = `rgba(150,150,150,0.6)`; //`rgba(221,221,221,0.6)`; ctx.fillRect(0, 0, canvas.width, canvas.height); }); // document.getElementById("pause-grid-right").style.opacity = "0.7" @@ -378,9 +378,6 @@ const powerUps = { // document.getElementById("choose-grid").style.display = "none" document.getElementById("choose-grid").style.visibility = "hidden" document.getElementById("choose-grid").style.opacity = "0" - // document.getElementById("choose-background").style.display = "none" - document.getElementById("choose-background").style.visibility = "hidden" - document.getElementById("choose-background").style.opacity = "0" document.body.style.cursor = "none"; // document.body.style.overflow = "hidden" @@ -623,21 +620,21 @@ const powerUps = { if (tech.isSuperDeterminism) { return `
` } else if (tech.isCancelTech) { - return `
randomize
` + return `
randomize
` } else { - return `
cancel
` + return `
cancel
` } }, researchText(type) { let text = "" if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { - text += `
` // style = "margin-left: 192px; margin-right: -192px;" + text += `
` // style = "margin-left: 192px; margin-right: -192px;" tech.junkResearchNumber = Math.ceil(4 * Math.random()) text += `
` for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` text += `
  pseudoscience
` } else if (powerUps.research.count > 0) { - text += `
` // style = "margin-left: 192px; margin-right: -192px;" + text += `
` // style = "margin-left: 192px; margin-right: -192px;" text += `
` for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` text += `
  ${tech.isResearchReality?"alternate reality": "research"}
` @@ -649,7 +646,6 @@ const powerUps = { hideStyle: `style="height:auto; border: none; background-color: transparent;"`, gunText(choose, click) { const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/gun/${b.guns[choose].name}.webp');"` - return `
  ${b.guns[choose].name}
@@ -657,16 +653,14 @@ const powerUps = { }, fieldText(choose, click) { const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/field/${m.fieldUpgrades[choose].name}${choose === 0 ? Math.floor(Math.random()*10) : ""}.webp');"` - return `
  ${m.fieldUpgrades[choose].name}
${m.fieldUpgrades[choose].description}
` }, techText(choose, click) { - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` - return `
  ${tech.tech[choose].name} ${techCountText}
@@ -674,9 +668,8 @@ const powerUps = { }, fieldTechText(choose, click) { - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` - return `
@@ -688,9 +681,8 @@ const powerUps = { ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` }, gunTechText(choose, click) { - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` - return `
@@ -702,28 +694,33 @@ const powerUps = { ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` }, junkTechText(choose, click) { - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; - const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-size: contain;background-repeat: no-repeat;"` + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-size: contain;background-repeat: no-repeat;background-image: url('img/junk.webp');"` if (!localSettings.isHideImages) { - setTimeout(() => { //pull image from web search if no url - if (tech.tech[choose].url === undefined) { + setTimeout(() => { //delay so that the html element exists + if (tech.tech[choose].url === undefined) { //if on url has been set yet const url = "https://images.search.yahoo.com/search/images?p=" + tech.tech[choose].name; - fetch(url) + fetch(url, { signal: AbortSignal.timeout(1000) }) //give up if it takes over 1 second .then((response) => response.text()) .then((html) => { const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); const elements = doc.getElementsByClassName("ld"); - // console.log(JSON.parse(elements[i].getAttribute("data")).iurl) - tech.tech[choose].url = JSON.parse(elements[i].getAttribute("data")).iurl - document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')` + // console.log(i, elements[i].getAttribute("data"), JSON.parse(elements[i].getAttribute("data")).iurl) + const index = Math.floor(Math.random() * 4) //randomly choose from the first 4 images + if (parseInt(JSON.parse(elements[index].getAttribute("data")).s.slice(0, -2)) < 500) { //make sure it isn't too big + tech.tech[choose].url = JSON.parse(elements[index].getAttribute("data")).iurl //store the url + document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')` //make the url the background image + } else if (parseInt(JSON.parse(elements[index + 1].getAttribute("data")).s.slice(0, -2)) < 500) { //try a different images and see if it is smaller + tech.tech[choose].url = JSON.parse(elements[index + 1].getAttribute("data")).iurl + document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')` + } }); } else { document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')` } - }, 100); + }, 1); } - return `
  ${tech.tech[choose].name} ${techCountText}
@@ -731,7 +728,6 @@ const powerUps = { }, incoherentTechText(choose, click) { // text += `
${tech.tech[choose].name} - incoherent
` - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` return `
@@ -801,7 +797,7 @@ const powerUps = { // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` text += `
@@ -880,7 +876,7 @@ const powerUps = { // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` text += `
@@ -1001,7 +997,7 @@ const powerUps = { // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` text += `
diff --git a/js/simulation.js b/js/simulation.js index 60ee67f..08b86b3 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -546,16 +546,16 @@ const simulation = { const swapPeriod = 150 const len = 30 for (let i = 0; i < len; i++) { - setTimeout(function () { - simulation.wipe = function () { //set wipe to have trails + setTimeout(function() { + simulation.wipe = function() { //set wipe to have trails ctx.fillStyle = `rgba(221,221,221,${i*i*0.0005 +0.0025})`; ctx.fillRect(0, 0, canvas.width, canvas.height); } }, (i) * swapPeriod); } - setTimeout(function () { - simulation.wipe = function () { //set wipe to normal + setTimeout(function() { + simulation.wipe = function() { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } }, len * swapPeriod); @@ -616,14 +616,11 @@ const simulation = { simulation.clearTimeouts(); simulation.onTitlePage = true; - document.getElementById("splash").onclick = function () { + document.getElementById("splash").onclick = function() { simulation.startGame(); }; - // document.getElementById("choose-grid").style.display = "none" document.getElementById("choose-grid").style.visibility = "hidden" document.getElementById("choose-grid").style.opacity = "0" - document.getElementById("choose-background").style.visibility = "hidden" - document.getElementById("choose-background").style.opacity = "0" document.getElementById("info").style.display = "inline"; document.getElementById("info").style.opacity = "0"; document.getElementById("experiment-button").style.display = "inline" @@ -782,7 +779,7 @@ const simulation = { // m.maxEnergy = 1 // m.energy = 1 input.isPauseKeyReady = true - simulation.wipe = function () { //set wipe to normal + simulation.wipe = function() { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } m.hole.isOn = false @@ -863,7 +860,7 @@ const simulation = { requestAnimationFrame(cycle); //starts game loop }, clearTimeouts() { - let id = window.setTimeout(function () {}, 0); + let id = window.setTimeout(function() {}, 0); while (id--) { window.clearTimeout(id); // will do nothing if no timeout with id is present } @@ -1200,7 +1197,7 @@ const simulation = { } if (tech.cyclicImmunity && m.immuneCycle < m.cycle + tech.cyclicImmunity) m.immuneCycle = m.cycle + tech.cyclicImmunity; //player is immune to damage for 60 cycles - fallCheck = function (who, save = false) { + fallCheck = function(who, save = false) { let i = who.length; while (i--) { if (who[i].position.y > simulation.fallHeight) { @@ -1584,9 +1581,9 @@ const simulation = { outHTML += "
" + simulation.constructMapString[i] + "
" } console.log(out) - navigator.clipboard.writeText(out).then(function () { + navigator.clipboard.writeText(out).then(function() { /* clipboard successfully set */ - }, function () { + }, function() { /* clipboard write failed */ console.log('copy failed') }); diff --git a/js/spawn.js b/js/spawn.js index a8bd0d7..ad22719 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -397,6 +397,8 @@ const spawn = { //spawn 6 mobs me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; //fire a bullet from each vertex for (let i = 0; i < 6; i++) me.spawnMobs(i) + + level.newLevelOrPhase() //run some new level tech effects } ctx.beginPath(); //draw invulnerable let vertices = this.vertices; @@ -499,36 +501,32 @@ const spawn = { { name: "mines", bombCycle: 0, - bombInterval: 55 - 2 * simulation.difficultyMode, + bombInterval: 10 - simulation.difficultyMode, do() { const yOff = 120 this.bombCycle++ - if (!(this.bombCycle % this.bombInterval) && (this.bombCycle & 60) > 30) { //mines above player + if (!(this.bombCycle % this.bombInterval) && (this.bombCycle % 660) > 330) { //mines above player if (simulation.isHorizontalFlipped) { - if (this.bombCycle > 120) { //wait 2 seconds before targeted mines drop - const x = m.pos.x + 200 * (Math.random() - 0.5) - if (x > -750) { //mines above player IN tunnel - spawn.mine(Math.min(Math.max(-730, x), 100), -450 - yOff * Math.random()) //player in main room - mob[mob.length - 1].fallHeight = -209 - } else { //mines above player NOT in tunnel - spawn.mine(Math.min(Math.max(-5375, x), -765), -1500 - yOff * Math.random()) //player in tunnel - mob[mob.length - 1].fallHeight = -9 - } + const x = m.pos.x + 200 * (Math.random() - 0.5) + if (x > -750) { //mines above player IN tunnel + spawn.mine(Math.min(Math.max(-730, x), 100), -450 - yOff * Math.random()) //player in main room + mob[mob.length - 1].fallHeight = -209 + } else { //mines above player NOT in tunnel + spawn.mine(Math.min(Math.max(-5375, x), -765), -1500 - yOff * Math.random()) //player in tunnel + mob[mob.length - 1].fallHeight = -9 } if (Math.random() < 0.5) { spawn.mine(-5350 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines mob[mob.length - 1].fallHeight = -9 } } else { - if (this.bombCycle > 120) { //wait 2 seconds before targeted mines drop - const x = m.pos.x + 200 * (Math.random() - 0.5) - if (x < 750) { //mines above player IN tunnel - spawn.mine(Math.min(Math.max(-100, x), 735), -450 - yOff * Math.random()) //player in main room - mob[mob.length - 1].fallHeight = -209 - } else { //mines above player NOT in tunnel - spawn.mine(Math.min(Math.max(760, x), 5375), -1500 - yOff * Math.random()) //player in tunnel - mob[mob.length - 1].fallHeight = -9 - } + const x = m.pos.x + 200 * (Math.random() - 0.5) + if (x < 750) { //mines above player IN tunnel + spawn.mine(Math.min(Math.max(-100, x), 735), -450 - yOff * Math.random()) //player in main room + mob[mob.length - 1].fallHeight = -209 + } else { //mines above player NOT in tunnel + spawn.mine(Math.min(Math.max(760, x), 5375), -1500 - yOff * Math.random()) //player in tunnel + mob[mob.length - 1].fallHeight = -9 } if (Math.random() < 0.5) { //random mines, but not in tunnel spawn.mine(800 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines @@ -561,12 +559,17 @@ const spawn = { }, { name: "orbiters", - spawnRate: 42 - 2 * simulation.difficultyMode, + spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode), + orbitersCycle: 0, do() { - if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { + this.orbitersCycle++ + if (!(this.orbitersCycle % this.spawnRate) && (this.orbitersCycle % 660) > 600 && mob.length < me.maxMobs) { const speed = (0.01 + 0.0005 * simulation.difficultyMode) * ((Math.random() < 0.5) ? 0.85 : -1.15) const phase = 0 //Math.floor(2 * Math.random()) * Math.PI - me.orbitalNoVelocity(me, 360 + 2150 * Math.random(), 0.1 * Math.random() + phase, speed) // orbital(who, radius, phase, speed) + //find distance to play and set orbs at that range + const dist = me.distanceToPlayer() + //360 + 2150 * Math.random() + me.orbitalNoVelocity(me, dist + 900 * (Math.random() - 0.5), 0.1 * Math.random() + phase, speed) // orbital(who, radius, phase, speed) } }, enter() {}, @@ -706,6 +709,7 @@ const spawn = { this.damageReductionDecay(); for (let i = 0; i < this.totalModes; i++) this.mode[i].do() } + // this.mode[5].do() //deelete this // this.cycle++; // this.mode[4].do() // this.mode[7].do() @@ -1537,16 +1541,18 @@ const spawn = { zombie(x, y, radius, sides, color) { //mob that attacks other mobs mobs.spawn(x, y, sides, radius, color); let me = mob[mob.length - 1]; + me.damageReduction = 0.5 //take less damage + // Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback me.isZombie = true + me.isBadTarget = true; me.isDropPowerUp = false; me.showHealthBar = false; me.stroke = "#83a" me.accelMag = 0.0015 me.frictionAir = 0.01 - // me.repulsionRange = 400000 + radius * radius; //squared + // me.collisionFilter.mask = cat.player | cat.map | cat.body // me.memory = 120; me.seeAtDistance2 = 1000000 //1000 vision range - // Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback me.do = function() { this.zombieHealthBar(); this.lookForMobTargets(); @@ -1556,15 +1562,31 @@ const spawn = { me.mobSearchIndex = 0; me.target = null me.lookForMobTargets = function() { - if (this.target && !this.target.alive) this.target = null - if (this.target === null && !(simulation.cycle % 10) && mob.length > 1) { //if you have no target - this.mobSearchIndex++ //look for a different mob index every time - if (this.mobSearchIndex > mob.length - 1) this.mobSearchIndex = 0 + if (!(simulation.cycle % 10)) { + if (this.target === null) { //if you have no target + this.mobSearchIndex++ //look for a different mob index every time + if (this.mobSearchIndex > mob.length - 1) this.mobSearchIndex = 0 + if ( + mob.length > 1 && + !mob[this.mobSearchIndex].isZombie && + (Vector.magnitudeSquared(Vector.sub(this.position, mob[this.mobSearchIndex].position)) < this.seeAtDistance2 && Matter.Query.ray(map, this.position, mob[this.mobSearchIndex].position).length === 0) + ) { + this.target = mob[this.mobSearchIndex] + } else if (Math.random() < 0.05 && (Vector.magnitudeSquared(Vector.sub(this.position, player.position)) < this.seeAtDistance2 || Matter.Query.ray(map, this.position, player.position).length === 0)) { + this.target = player + this.isBadTarget = false; + } + } + } + //chance to forget target + if (!(simulation.cycle % this.memory) && this.target) { if ( - !mob[this.mobSearchIndex].isZombie && - (Vector.magnitudeSquared(Vector.sub(this.position, mob[this.mobSearchIndex].position)) < this.seeAtDistance2 || Matter.Query.ray(map, this.position, mob[this.mobSearchIndex].position).length === 0) + (this.target && this.target !== player && !this.target.alive) || + Vector.magnitudeSquared(Vector.sub(this.position, this.target.position)) > this.seeAtDistance2 || + Matter.Query.ray(map, this.position, this.target.position).length !== 0 ) { - this.target = mob[this.mobSearchIndex] + if (this.target === player) this.isBadTarget = true + this.target = null } } } @@ -1600,13 +1622,11 @@ const spawn = { const force = Vector.mult(Vector.normalise(Vector.sub(who.position, this.position)), 0.03 * this.mass) this.force.x -= force.x; this.force.y -= force.y; - this.target = null //look for a new target - - const dmg = 0.3 * m.dmgScale who.damage(dmg); + who.locatePlayer(); simulation.drawList.push({ x: this.position.x, y: this.position.y, diff --git a/js/tech.js b/js/tech.js index e6e3196..0e56f47 100644 --- a/js/tech.js +++ b/js/tech.js @@ -1854,7 +1854,7 @@ const tech = { description: `toggle ON and OFF after a collision
unlock advanced tech that runs if ON`, nameInfo: "", addNameInfo() { - setTimeout(function () { + setTimeout(function() { if (document.getElementById("tech-flip-flop")) { if (tech.isFlipFlopOn) { document.getElementById("tech-flip-flop").innerHTML = ` = ON` @@ -2005,7 +2005,7 @@ const tech = { description: `toggle ON and OFF after picking up a power up
unlock advanced tech that runs if ON`, nameInfo: "", addNameInfo() { - setTimeout(function () { + setTimeout(function() { if (document.getElementById("tech-switch")) { if (tech.isFlipFlopOn) { document.getElementById("tech-switch").innerHTML = ` = ON` @@ -2408,42 +2408,6 @@ const tech = { } } }, - // { - // name: "weak interaction", - // description: "for each unused power up at the end of a level
+10 maximum energy", // (up to 51 health per level)", - // maxCount: 1, - // count: 0, - // frequency: 1, - // frequencyDefault: 1, - // allowed() { - // return !tech.isDroneGrab - // }, - // requires: "not delivery drone", - // effect() { - // tech.isExtraMaxEnergy = true; //tracked by tech.extraMaxHealth - // }, - // remove() { - // tech.isExtraMaxEnergy = false; - // } - // }, - // { - // name: "electroweak interaction", - // description: "unused power ups at the end of a level
are still activated (selections are random)", - // maxCount: 1, - // count: 0, - // frequency: 2, - // frequencyDefault: 2, - // allowed() { - // return tech.isExtraMaxEnergy - // }, - // requires: "weak interaction", - // effect() { - // tech.isEndLevelPowerUp = true; - // }, - // remove() { - // tech.isEndLevelPowerUp = false; - // } - // }, { name: "electronegativity", descriptionFunction() { @@ -2609,7 +2573,7 @@ const tech = { requires: "not parasitism", effect() { tech.isCrouchRegen = true; //only used to check for requirements - m.regenEnergy = function () { + m.regenEnergy = function() { if (m.immuneCycle < m.cycle && m.crouch) m.energy += 7 * m.fieldRegen; if (m.energy < 0) m.energy = 0 } @@ -2650,7 +2614,7 @@ const tech = { requires: "not inductive charging", effect() { tech.isDamageAfterKillNoRegen = true; - m.regenEnergy = function () { + m.regenEnergy = function() { if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 } @@ -3011,7 +2975,7 @@ const tech = { name: "anthropic principle", nameInfo: "", addNameInfo() { - setTimeout(function () { + setTimeout(function() { powerUps.research.changeRerolls(0) }, 1000); }, @@ -3030,7 +2994,7 @@ const tech = { effect() { tech.isDeathAvoid = true; tech.isDeathAvoidedThisLevel = false; - setTimeout(function () { + setTimeout(function() { powerUps.research.changeRerolls(0) }, 1000); }, @@ -8421,7 +8385,7 @@ const tech = { const loop = () => { if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) { const dmg = Math.floor(33 * Math.random()) * 0.01 - this.text = `+${(dmg*100).toFixed(0).padStart(2, '0')}% damage` + this.text = `+${(dmg*100).toFixed(0).padStart(2, '0')}% damage
 ` this.damage = 1 + dmg if (document.getElementById(`damage-JUNK-id${this.id}`)) document.getElementById(`damage-JUNK-id${this.id}`).innerHTML = this.text setTimeout(() => { @@ -8548,7 +8512,7 @@ const tech = { }, { name: "meteor shower", - description: "take a shower, but meteors instead of water", + description: "take a shower, but meteors instead of water
 ", maxCount: 1, count: 0, frequency: 0, @@ -8559,7 +8523,7 @@ const tech = { effect() { setInterval(() => { - fireBlock = function (xPos, yPos) { + fireBlock = function(xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random()); const bodyBullet = body[index] @@ -8694,7 +8658,7 @@ const tech = { // }, { name: "discount", - description: "get 3 random JUNKtech for the price of 1!", + description: "get 3 random JUNKtech for the price of 1!
 ", maxCount: 1, count: 0, frequency: 0, @@ -8763,7 +8727,7 @@ const tech = { }, { name: "harvest", - description: "convert all the mobs on this level into ammo", + description: "convert all the mobs on this level into ammo
 ", maxCount: 1, count: 0, frequency: 0, @@ -8788,19 +8752,6 @@ const tech = { }, remove() {} }, - { - name: " ", - description: "", - maxCount: 1, - count: 0, - frequency: 0, - frequencyDefault: 0, - isJunk: true, - allowed: () => true, - requires: "", - effect() {}, - remove() {} - }, { name: "brainstorm", description: "the tech choice menu randomizes
every 0.5 seconds for 10 seconds", @@ -8843,7 +8794,7 @@ const tech = { }, { name: "palantír", - description: `see far away lands`, + description: `see far away lands
 `, maxCount: 1, count: 0, frequency: 0, @@ -8874,7 +8825,7 @@ const tech = { }, { name: "motion sickness", - description: `disable camera smoothing`, + description: `disable camera smoothing
 `, maxCount: 1, count: 0, frequency: 0, @@ -8907,7 +8858,7 @@ const tech = { }, { name: "facsimile", - description: `inserts a copy of your current level into the level list`, + description: `inserts a copy of your current level into the level list
 `, maxCount: 1, count: 0, frequency: 0, @@ -8943,7 +8894,7 @@ const tech = { }, { name: "bounce", - description: "you bounce off things. It's annoying, but not that bad.", + description: "you bounce off things. It's annoying, but not that bad.
 ", maxCount: 1, count: 0, frequency: 0, @@ -8961,7 +8912,7 @@ const tech = { }, { name: "mouth", - description: "mobs have a non functional mouth", + description: "mobs have a non functional mouth
 ", maxCount: 1, count: 0, frequency: 0, @@ -9007,7 +8958,7 @@ const tech = { }, { name: "all-stars", - description: "make all mobs look like stars", + description: "make all mobs look like stars
 ", maxCount: 1, count: 0, frequency: 0, @@ -9068,7 +9019,7 @@ const tech = { // }, { name: "true colors", - description: `set all power ups to their real world colors`, + description: `set all power ups to their real world colors
 `, maxCount: 1, count: 0, frequency: 0, @@ -9283,7 +9234,7 @@ const tech = { }, { name: "not a bug", - description: "initiate a totally safe game crash for 10 seconds", + description: "initiate a totally safe game crash for 10 seconds
 ", maxCount: 1, count: 0, frequency: 0, @@ -9310,7 +9261,7 @@ const tech = { }, { name: "spinor", - description: "the direction you aim is determined by your position", + description: "the direction you aim is determined by your position
 ", maxCount: 1, count: 0, frequency: 0, @@ -9321,7 +9272,7 @@ const tech = { }, requires: "", effect() { - m.look = function () { + m.look = function() { //always on mouse look m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI //smoothed mouse look translations @@ -9339,7 +9290,7 @@ const tech = { }, { name: "decomposers", - description: "after they die mobs leave behind spawns", + description: "after they die mobs leave behind spawns
 ", maxCount: 1, count: 0, frequency: 0, @@ -9358,7 +9309,7 @@ const tech = { }, { name: "panopticon", - description: "mobs can always see you", + description: "mobs can always see you
 ", maxCount: 1, count: 0, frequency: 0, @@ -9482,7 +9433,7 @@ const tech = { }, { name: "encryption", - description: "secure tech information", + description: "secure tech information
 ", maxCount: 1, count: 0, frequency: 0, @@ -9493,7 +9444,7 @@ const tech = { }, requires: "", effect() { - String.prototype.shuffle = function () { + String.prototype.shuffle = function() { var a = this.split(""), n = a.length; @@ -9532,7 +9483,7 @@ const tech = { }, { name: "score", - description: "Add a score to n-gon!", + description: "Add a score to n-gon!
 ", maxCount: 1, count: 0, frequency: 0, @@ -9571,7 +9522,7 @@ const tech = { }, { name: "music", - description: "add music to n-gon", + description: "add music to n-gon
 ", maxCount: 1, count: 0, frequency: 0, @@ -9588,7 +9539,7 @@ const tech = { }, { name: "performance", - description: "display performance stats to n-gon", + description: "display performance stats to n-gon
 ", maxCount: 1, count: 0, frequency: 0, @@ -9599,9 +9550,9 @@ const tech = { }, requires: "", effect() { - (function () { + (function() { var script = document.createElement('script'); - script.onload = function () { + script.onload = function() { var stats = new Stats(); document.body.appendChild(stats.dom); requestAnimationFrame(function loop() { @@ -9644,7 +9595,7 @@ const tech = { }, { name: "defragment", - description: "set the frequency of finding JUNKtech to zero", + description: "set the frequency of finding JUNKtech to zero
 ", maxCount: 1, count: 0, frequency: 0, @@ -9684,7 +9635,7 @@ const tech = { // }, { name: "pitch", - description: "oscillate the pitch of your world", + description: "oscillate the pitch of your world
 ", maxCount: 1, count: 0, frequency: 0, @@ -9721,7 +9672,7 @@ const tech = { }, { name: "lighter", - description: `ctx.globalCompositeOperation = "lighter"`, + description: `ctx.globalCompositeOperation = "lighter"
 `, maxCount: 1, count: 0, frequency: 0, @@ -9738,7 +9689,7 @@ const tech = { }, { name: "rewind", - description: "every 10 seconds rewind 2 seconds", + description: "every 10 seconds rewind 2 seconds
 ", maxCount: 9, count: 0, frequency: 0, @@ -9761,7 +9712,7 @@ const tech = { }, { name: "undo", - description: "every 4 seconds rewind 1/2 a second", + description: "every 4 seconds rewind 1/2 a second
 ", maxCount: 9, count: 0, frequency: 0, @@ -9781,7 +9732,7 @@ const tech = { }, { name: "energy to mass conversion", - description: "convert your energy into blocks", + description: "convert your energy into blocks
 ", maxCount: 9, count: 0, frequency: 0, @@ -9813,7 +9764,7 @@ const tech = { }, { name: "level.nextLevel()", - description: "advance to the next level", + description: "advance to the next level
 ", maxCount: 9, count: 0, frequency: 0, @@ -9899,7 +9850,7 @@ const tech = { }, { name: "missile launching system", - description: "fire missiles for the next 120 seconds", + description: "fire missiles for the next 120 seconds
 ", maxCount: 9, count: 0, frequency: 0, @@ -9924,7 +9875,7 @@ const tech = { }, { name: "grenade production", - description: "drop a grenade every 2 seconds", + description: "drop a grenade every 2 seconds
 ", maxCount: 9, count: 0, frequency: 0, @@ -9977,7 +9928,7 @@ const tech = { // }, { name: "Sleipnir", - description: "grow more legs", + description: "grow more legs
 ", maxCount: 1, count: 0, frequency: 0, @@ -9989,7 +9940,7 @@ const tech = { }, requires: "", effect() { - m.draw = function () { + m.draw = function() { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; @@ -10035,7 +9986,7 @@ const tech = { }, requires: "", effect() { - m.draw = function () { + m.draw = function() { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; @@ -10064,7 +10015,7 @@ const tech = { }, { name: "🐱", - description: "🐈", + description: "🐈
 ", maxCount: 1, count: 0, frequency: 0, @@ -10076,7 +10027,7 @@ const tech = { }, requires: "", effect() { - m.draw = function () { + m.draw = function() { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); @@ -10164,7 +10115,7 @@ const tech = { }, { name: "posture", - description: "stand a bit taller", + description: "stand a bit taller
 ", maxCount: 1, count: 0, frequency: 0, @@ -10183,7 +10134,7 @@ const tech = { }, { name: "rhythm", - description: "you oscillate up and down", + description: "you oscillate up and down
 ", maxCount: 1, count: 0, frequency: 0, @@ -10204,7 +10155,7 @@ const tech = { }, { name: "pareidolia", - description: "don't", + description: "don't
 ", maxCount: 1, count: 0, frequency: 0, @@ -10216,7 +10167,7 @@ const tech = { }, requires: "", effect() { - m.draw = function () { + m.draw = function() { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); @@ -10273,7 +10224,7 @@ const tech = { }, { name: "prism", - description: "you cycle through different colors", + description: "you cycle through different colors
 ", maxCount: 1, count: 0, frequency: 0, @@ -10290,7 +10241,7 @@ const tech = { sat: 100, light: 50 } - setInterval(function () { + setInterval(function() { m.color.hue++ m.setFillColors() }, 10); @@ -10427,7 +10378,7 @@ const tech = { }, { name: "growth hacking", - description: "increase combat difficulty by 1 level", + description: "increase combat difficulty by 1 level
 ", maxCount: 1, count: 0, frequency: 0, @@ -10444,7 +10395,7 @@ const tech = { }, { name: "stun", - description: "stun all mobs for up to 8 seconds", + description: "stun all mobs for up to 8 seconds
 ", maxCount: 9, count: 0, frequency: 0, @@ -10489,7 +10440,7 @@ const tech = { }, { name: "re-research", - description: `eject all your ${powerUps.orb.research(1)}`, + description: `eject all your ${powerUps.orb.research(1)}
 `, maxCount: 9, count: 0, frequency: 0, @@ -10527,7 +10478,7 @@ const tech = { }, { name: "black hole cluster", - description: `spawn 30 nearby black holes`, + description: `spawn 30 nearby black holes
 `, maxCount: 1, count: 0, frequency: 0, @@ -10755,7 +10706,7 @@ const tech = { const bc = new BroadcastChannel('planetesimals'); bc.activated = false - bc.onmessage = function (ev) { + bc.onmessage = function(ev) { if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); if (ev.data === 'death') { m.death() @@ -11056,7 +11007,6 @@ const tech = { fastTime: null, squirrelJump: null, isFastRadiation: null, - isExtraMaxEnergy: null, isAmmoForGun: null, isRapidPulse: null, isSporeFreeze: null, @@ -11239,7 +11189,6 @@ const tech = { isHarpoonPowerUp: null, harpoonDensity: null, isAddRemoveMaxHealth: null, - isSpawnExitTech: null, cloakDuplication: null, extruderRange: null, isForeverDrones: null, @@ -11250,11 +11199,9 @@ const tech = { isFreeWormHole: null, isRewindField: null, isCrouchRegen: null, - // OccamDamage: null, isAxion: null, isWormholeMapIgnore: null, isLessDamageReduction: null, - // bulletSize: null, needleTunnel: null, isBrainstorm: null, isBrainstormActive: null, diff --git a/style.css b/style.css index bf5c78f..356356a 100644 --- a/style.css +++ b/style.css @@ -6,8 +6,6 @@ body { font-family: "Helvetica", "Arial", sans-serif; margin: 0; overflow: hidden; - /* background-color: #eee; */ - cursor: auto; } @@ -23,9 +21,6 @@ select { font-size: 0.8em; border: 1px #333 solid; border-radius: 6px; - /* margin-bottom: -20px; */ - /* position: "relative"; - top: "-15px"; */ } select option { @@ -33,13 +28,10 @@ select option { } input { - /* font-family: Monaco, monospace; */ padding: 0px 4px; font-size: 0.8em; border: 1px #333 solid; border-radius: 4px; - /* margin: 0.2em; */ - /* width: 38px; */ } a { @@ -68,9 +60,7 @@ em { table { border-collapse: collapse; - /* border: 1px solid #eee; */ width: 360px; - /* background-color: #ddd; */ } tr { @@ -142,16 +132,10 @@ summary { #training-button { position: absolute; - /* bottom: 4px; */ - /* right: 0px; - left: 0px; - margin: auto; */ - /* bottom: 58px; */ top: 4px; right: 4px; z-index: 12; transition: opacity 5s ease-in; - } #construct { @@ -170,19 +154,6 @@ summary { border: 1px #333 solid; } -#choose-background { - position: absolute; - z-index: 2; - width: 100%; - height: 100%; - background-color: #ccc; - /* opacity: 0.6; */ - /* display: none; */ - visibility: hidden; - opacity: 0; - transition: opacity 0.25s linear; - -} #flex-center{ display: flex; align-items: center; @@ -384,11 +355,12 @@ summary { .card-text { background-color: rgba(255,255,255,1); /* border-radius: 8px; */ - padding: 8px; + padding: 11px 13px; /* border-top: 1px solid var(--build-bg-color); */ border: 1px solid #444; margin-top: -1px; margin-right: -1px; + font-size: 0.92em; } /* .no-image-cards{ diff --git a/todo.txt b/todo.txt index 3cdf7dc..6018e3e 100644 --- a/todo.txt +++ b/todo.txt @@ -1,29 +1,40 @@ ******************************************************** NEXT PATCH ************************************************** -added images to tech, field, gun cards (enable this in settings) - in progress - not all images are generated yet - images are generated by me using midJourney plus significant post processing +card font is 10% smaller with a bit more padding on the edges +background is darker on power up selection +css border added to research and cancel buttons +JUNK images now timeout if you don't download the image in under 1 sec + and it will not even try to download an image above 500KB + and it will try a different random image if it's first attempt is too big + (gotta protect our friends with slow internet) -random research power ups are 20% more common per level -global difficulty balance: player takes a bit less damage -mutualism: 0.5->1 borrowed health for 250->300% more spore damage +finalBoss + mine mode comes in waves + orbiters mode comes in waves, and they spawn at a radius that intersects the player -harpoon can still fire when out of energy, but slower -harpoon fire cooldown no longer triggers when the harpoon returns - it's just a flat 2/3 of a second after you Fire - improved fire rate now allows you to fire many harpoons at once until you run out of energy -default harpoon rope is a bit longer +several on new level tech effects now also run on each new final Boss phase + gun stuff, many worlds, negative entropy heal spawns -several bug fixes and undocumented changes I forgot to list +perfect diamagnetism slow fall is much strong, but works better when angled like a parachute *********************************************************** TODO ***************************************************** +maybe harpoon should start with less ammo? + +tech: p-zombie - sporangium infect mobs, making them fight for you + zombies should attack player if there are no mob targets + name: cordyceps, zombie, p-zombie? + infected mobs get a status debuff. when they die they return as zombie mob type + zombie mobs run code similar to drones + they inherit color, sides, radius from host + +tech super balls - super ball can damage you, but it does more damage to mobs + set media rules for smaller screens smaller card size - -tech super balls - super ball can damage you - -add to todo: make it so each phase of the final boss works like a new level (call new level code on each new phase) + set font to 0.8em + set card width to 384*0.8 + and set background images to fit bug reactor boss + harpoon foam production seems to make too much foam @@ -36,73 +47,6 @@ physics notes: add link to double slit content seekers after taking damage if seekers are below 1/2 life they teleport to a random point on the player history and sneak attack again make sure they don't teleport on top of the player -card images - process: discord midjourney prompts -> "pixelmator pro" -> adjust color, repair, scale to 384x256, export PNG -> webP? -> place in /img folder - make n-gon a progressive web app to manage image downloads, cache - wave function collapse opens the pause menu after it triggers alternate reality - this is actually good, maybe reuse this code to get pause menu to open at any time - if pause is pressed while selecting power ups, display pause menu on top of selection menu - ***styles*** - try --- Pastel drawing, Psychedelic art, Arabesque (cool patterns), knolling (everything spread out and placed on a flat mat) - try taking screen shots of fields graphics and feeding them into midJourney V4 - technology stuff --- Dan Matutina (cute complex technology), - Katsuhiro Otomo (intricate space technology), Tsutomu Nihei (black and white detailed future tech) - infographics of all know multiverses. 1980s Japanese graphic design, dimensional astrolabe, - Japanese poster graphics, Ralph McQuarrie (looks like star wars), Simon Stålenhag (retro-futuristic), Yoshiyuki Tomino (detailed anime future technology) - isometric: low-poly, box cutout, made in blender, Materials: matte clay - subtractive sculpture - kinetic sculpture - quantum stuff -- Hypertorus, Glowing Opal Pearlescent, Physics, Hydro-Dipping Hydrodipped, Vija Celmins, Matt Molloy (photo of golden waves in the sky) - ***major themes missing*** - ***maybe redo*** - dynamical systems - harpoon gun - nail-bot - homeostasis - ***past style themes*** - field emitter - isometric, clean white robot spherical gun turret on bird legs, blender 3d, style of artstation and behance, Disney Pixar, cute - standing wave - concentric transparent blue geometric circles science - perfect diamagnetism - physics magnetic field chalk diagram - time dilation - graphic of a hyperbolic equation Luminogram - negative mass - Blacklight painting by Moebius - plasma torch - by Dan Mumford - metamaterial cloaking - Scientific photography by Miki Asai - molecular assembler - by Laurie Greasley 16-bit Isometric - wormhole - by Tim White - - nail gun - Screenprint - shotgun - blueprint by Dan McPharlin - grenades, missiles, explosions - by Victo Ngai - spores - by Ernst Haeckel - drones - tilt-shift photography - super balls - By Akari Toriyama - wave - sound wave oscilloscope by Paul Catherall, concentric circles by Paul Catherall - foam - black blobs Ink doodle - harpoon - by Eiichiro Oda - mine - by Dan McPharlin - laser - complex optical scientific equipment - - guns, ammo - isometric clean pixel art image cutaway of , style of tekkonkinkreet - defensive - Paper cutout - bots - hovering drone by Laurie Greasley 16-bit Isometric - generic energy tech - by Laurie Greasley - duplication, cancel - by Kazumasa Nagai - anti-shear topology, fracture analysis, shear stress - Chemigram - ON/OFF - ASCII art - block throwing - Bauhaus style - tech that adds JUNK - by Choi Jeong-hwa - ice IX - microscope images of ice crystals - tech that spawns health - glowing green balls by Enki Bilal - invulnerable - by Nick Veasey (photos that look like x-rays) - alternate reality - Fractal art - tech choice - mandala tile Mosaic - tech that spawns heal power ups - green Quilling - time, CPT, pause - by Lee Bontecou - boost, coupling power ups tech - cyan electron orbiting a black nucleus electric field as bas-relief //(by Kazumasa Nagai) - radioactive - volumetric atomic nucleus diagram by Paul Catherall - - - tech: railgun area damage effect, but for all harpoon mode laser momentum pushed back on player? @@ -111,14 +55,6 @@ laser momentum pushed back on player? JUNK - overwrite mob draw function so mobs only draw if they can connect a ray from player to mob gonna cause lag? -tech: p-zombie - sporangium infect mobs, making them fight for you - zombies should attack player if there are no mob targets - name: cordyceps, zombie, p-zombie? - infected mobs get a status debuff. when they die they return as zombie mob type - zombie mobs run code similar to drones - they inherit color, sides, radius from host - - mob status effect - vulnerability mobs take 4x damage for __ time afterwards mobs go back to normal damage taken @@ -1214,6 +1150,73 @@ possible names for tech https://en.wikipedia.org/wiki/Cosmic_censorship_hypothesis - black holes can't leak Alcubierre warp drive (FTL with negative mass) +******************************************************** CARS IMAGES ******************************************************** +process: discord midjourney prompts -> "pixelmator pro" -> adjust color, repair, scale to 384x256, export PNG -> webP? -> place in /img folder +make n-gon a progressive web app to manage image downloads, cache +wave function collapse opens the pause menu after it triggers alternate reality + this is actually good, maybe reuse this code to get pause menu to open at any time +if pause is pressed while selecting power ups, display pause menu on top of selection menu +***styles*** + try --- Pastel drawing, Psychedelic art, Arabesque (cool patterns), knolling (everything spread out and placed on a flat mat) + try taking screen shots of fields graphics and feeding them into midJourney V4 + technology stuff --- Dan Matutina (cute complex technology), + Katsuhiro Otomo (intricate space technology), Tsutomu Nihei (black and white detailed future tech) + infographics of all know multiverses. 1980s Japanese graphic design, dimensional astrolabe, + Japanese poster graphics, Ralph McQuarrie (looks like star wars), Simon Stålenhag (retro-futuristic), Yoshiyuki Tomino (detailed anime future technology) + isometric: low-poly, box cutout, made in blender, Materials: matte clay + subtractive sculpture + kinetic sculpture + quantum stuff -- Hypertorus, Glowing Opal Pearlescent, Physics, Hydro-Dipping Hydrodipped, Vija Celmins, Matt Molloy (photo of golden waves in the sky) +***major themes missing*** +***maybe redo*** + dynamical systems + harpoon gun + nail-bot + homeostasis + heuristics + thermal runaway - infrared maybe? + redo the energy tech images with by Laurie Greasley + now that you can use --ar 3:2 --stylize 1000 and photo repair +***past style themes*** + field emitter - isometric, clean white robot spherical gun turret on bird legs, blender 3d, style of artstation and behance, Disney Pixar, cute + standing wave - concentric transparent blue geometric circles science + perfect diamagnetism - physics magnetic field chalk diagram + time dilation - graphic of a hyperbolic equation Luminogram + negative mass - Blacklight painting by Moebius + plasma torch - by Dan Mumford + metamaterial cloaking - Scientific photography by Miki Asai + molecular assembler - by Laurie Greasley 16-bit Isometric + wormhole - by Tim White + nail gun - Screenprint + shotgun - blueprint by Dan McPharlin + grenades, missiles, explosions - by Victo Ngai + spores - by Ernst Haeckel + drones - tilt-shift photography + super balls - By Akari Toriyama + wave - sound wave oscilloscope by Paul Catherall, concentric circles by Paul Catherall + foam - black blobs Ink doodle + harpoon - by Eiichiro Oda + mine - by Dan McPharlin + laser - complex optical scientific equipment + + guns, ammo - isometric clean pixel art image cutaway of , style of tekkonkinkreet + defensive - Paper cutout + bots - hovering drone by Laurie Greasley 16-bit Isometric + generic energy tech - by Laurie Greasley + duplication, cancel - by Kazumasa Nagai + anti-shear topology, fracture analysis, shear stress - Chemigram + ON/OFF - ASCII art + block throwing - Bauhaus style + tech that adds JUNK - by Choi Jeong-hwa + ice IX - microscope images of ice crystals + tech that spawns health - glowing green balls by Enki Bilal + invulnerable - by Nick Veasey (photos that look like x-rays) + alternate reality - Fractal art + tech choice - mandala tile Mosaic + tech that spawns heal power ups - green Quilling + time, CPT, pause - by Lee Bontecou + boost, coupling power ups tech - cyan electron orbiting a black nucleus electric field as bas-relief //(by Kazumasa Nagai) + radioactive - volumetric atomic nucleus diagram by Paul Catherall