diff --git a/img/brittle.webp b/img/brittle.webp
new file mode 100644
index 0000000..85dd2fe
Binary files /dev/null and b/img/brittle.webp differ
diff --git a/img/cascading failure.webp b/img/cascading failure.webp
new file mode 100644
index 0000000..443206e
Binary files /dev/null and b/img/cascading failure.webp differ
diff --git a/img/field/field emitter25.webp b/img/field/field emitter25.webp
new file mode 100644
index 0000000..aa48cdd
Binary files /dev/null and b/img/field/field emitter25.webp differ
diff --git a/img/topological defect.webp b/img/topological defect.webp
new file mode 100644
index 0000000..c81a53c
Binary files /dev/null and b/img/topological defect.webp differ
diff --git a/img/yield stress.webp b/img/yield stress.webp
new file mode 100644
index 0000000..a4be7c9
Binary files /dev/null and b/img/yield stress.webp differ
diff --git a/js/bullet.js b/js/bullet.js
index c77361f..67bcf5b 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -288,7 +288,7 @@ const b = {
if (m.fieldMode === 6) b.fireCDscale *= 0.8
if (tech.isFastTime) b.fireCDscale *= 0.5
if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, Math.max(0, b.inventory.length - 1))
- if (tech.isFireMoveLock) b.fireCDscale *= 0.55
+ if (tech.isFireMoveLock) b.fireCDscale *= 0.23 // 77% fire rate
},
fireAttributes(dir, rotate = true) {
if (rotate) {
@@ -1508,8 +1508,9 @@ const b = {
},
minDmgSpeed: 4,
// lookFrequency: Math.floor(7 + Math.random() * 3),
- density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
+ density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon
drain: 0.001,
+ powerUpDamage: tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle,
draw() {
// draw rope
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
@@ -1559,9 +1560,26 @@ const b = {
// ctx.stroke();
// }
-
-
-
+ if (this.powerUpDamage) {
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
+ ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
+ ctx.lineTo(this.vertices[2].x, this.vertices[2].y);
+ ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
+ ctx.lineTo(this.vertices[4].x, this.vertices[4].y);
+ ctx.lineJoin = "miter"
+ ctx.miterLimit = 30;
+ ctx.lineWidth = 25;
+ ctx.strokeStyle = "rgba(0,255,255,0.4)";
+ ctx.stroke();
+ ctx.lineWidth = 8;
+ ctx.strokeStyle = "rgb(0,255,255)";
+ ctx.stroke();
+ ctx.lineJoin = "round"
+ ctx.miterLimit = 5
+ ctx.fillStyle = "#000"
+ ctx.fill();
+ }
//draw hook
ctx.beginPath();
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
@@ -1581,6 +1599,42 @@ const b = {
}
if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
+ // if (this.powerUpDamage) this.density = 2 * 0.004 //double damage after pick up power up for 8 seconds
+
+
+ if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
+ Matter.Body.setDensity(this, 1.8 * 0.004); //+90% damage after pick up power up for 8 seconds
+ } else if (tech.isHarpoonFullHealth && who.health === 1) {
+ Matter.Body.setDensity(this, 1.9 * 0.004); //+90% damage if mob has full health do
+ simulation.ephemera.push({
+ name: "grapple outline",
+ count: 3, //cycles before it self removes
+ vertices: this.vertices,
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
+ for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
+ ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
+ ctx.lineJoin = "miter"
+ ctx.miterLimit = 20;
+ ctx.lineWidth = 40;
+ ctx.strokeStyle = "rgba(255,0,100,0.35)";
+ ctx.stroke();
+ ctx.lineWidth = 10;
+ ctx.strokeStyle = `#f07`;
+ ctx.stroke();
+ ctx.lineJoin = "round"
+ ctx.miterLimit = 5
+ ctx.fillStyle = "#000"
+ ctx.fill();
+ },
+ })
+ }
+
+
this.retract()
},
caughtPowerUp: null,
@@ -1602,7 +1656,7 @@ const b = {
this.caughtPowerUp.effect();
Matter.Composite.remove(engine.world, this.caughtPowerUp);
powerUp.splice(index, 1);
- if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
+ if (tech.isHarpoonPowerUp) tech.harpoonPowerUpCycle = simulation.cycle
} else {
this.dropCaughtPowerUp()
}
@@ -1893,321 +1947,6 @@ const b = {
});
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- // grapple(where, angle = m.angle, harpoonSize = 1) {
- // const me = bullet.length;
- // const returnRadius = 100 * Math.sqrt(harpoonSize)
- // bullet[me] = Bodies.fromVertices(where.x, where.y, [{
- // x: -50 * harpoonSize,
- // y: 2 * harpoonSize,
- // index: 0,
- // isInternal: false
- // }, {
- // x: -50 * harpoonSize,
- // y: -2 * harpoonSize,
- // index: 1,
- // isInternal: false
- // }, {
- // x: 45 * harpoonSize,
- // y: -3 * harpoonSize,
- // index: 2,
- // isInternal: false
- // }, {
- // x: 50 * harpoonSize,
- // y: 0,
- // index: 3,
- // isInternal: false
- // }, {
- // x: 45 * harpoonSize,
- // y: 3 * harpoonSize,
- // index: 4,
- // isInternal: false
- // }], {
- // angle: angle,
- // friction: 1,
- // frictionAir: 0.4,
- // thrustMag: 0.1,
- // dmg: 6, //damage done in addition to the damage from momentum
- // classType: "bullet",
- // endCycle: simulation.cycle + 70,
- // collisionFilter: {
- // category: cat.bullet,
- // mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
- // },
- // minDmgSpeed: 4,
- // lookFrequency: Math.floor(7 + Math.random() * 3),
- // density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
- // drain: tech.isRailEnergy ? 0.0006 : 0.006,
- // beforeDmg(who) {
- // if (tech.isShieldPierce && who.isShielded) { //disable shields
- // who.isShielded = false
- // requestAnimationFrame(() => {
- // who.isShielded = true
- // });
- // }
- // if (tech.fragments) {
- // b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random()))
- // }
- // if (tech.isFoamBall) {
- // for (let i = 0, len = 4 * this.mass; i < len; i++) {
- // const radius = 5 + 8 * Math.random()
- // const velocity = {
- // x: Math.max(0.5, 2 - radius * 0.1),
- // y: 0
- // }
- // b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
- // }
- // // this.endCycle = 0;
- // }
- // },
- // caughtPowerUp: null,
- // dropCaughtPowerUp() {
- // if (this.caughtPowerUp) {
- // this.caughtPowerUp.collisionFilter.category = cat.powerUp
- // this.caughtPowerUp.collisionFilter.mask = cat.map | cat.powerUp
- // this.caughtPowerUp = null
- // }
- // },
- // onEnd() {
- // if (this.caughtPowerUp && !simulation.isChoosing && (this.caughtPowerUp.name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)) {
- // let index = null //find index
- // for (let i = 0, len = powerUp.length; i < len; ++i) {
- // if (powerUp[i] === this.caughtPowerUp) index = i
- // }
- // if (index !== null) {
- // powerUps.onPickUp(this.caughtPowerUp);
- // this.caughtPowerUp.effect();
- // Matter.Composite.remove(engine.world, this.caughtPowerUp);
- // powerUp.splice(index, 1);
- // if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
- // } else {
- // this.dropCaughtPowerUp()
- // }
- // } else {
- // this.dropCaughtPowerUp()
- // }
- // },
- // draw() {
- // const where = {
- // x: m.pos.x + 30 * Math.cos(m.angle),
- // y: m.pos.y + 30 * Math.sin(m.angle)
- // }
- // const sub = Vector.sub(where, this.vertices[0])
- // const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
- // ctx.strokeStyle = "#000" // "#0ce"
- // ctx.lineWidth = 0.5
- // ctx.beginPath();
- // ctx.moveTo(where.x, where.y);
- // ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
- // // ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
- // ctx.stroke();
- // //draw harpoon spikes
- // const spikeLength = 2
- // ctx.beginPath();
- // const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
- // ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
- // ctx.lineTo(spike1.x, spike1.y);
- // ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
-
- // const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
- // ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
- // ctx.lineTo(spike2.x, spike2.y);
- // ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
- // ctx.fillStyle = '#000'
- // ctx.fill();
- // },
- // returnToPlayer() {
- // if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
- // this.endCycle = 0;
- // // if (m.energy < 0.05) {
- // // m.fireCDcycle = m.cycle + 120; //fire cooldown
- // // } else if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) {
- // // m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 25 if it is above 25
- // // }
-
- // if (m.energy < 0.05) this.dropCaughtPowerUp()
-
- // //recoil on catching
- // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
- // player.force.x += momentum.x
- // player.force.y += momentum.y
- // // refund ammo
- // b.guns[9].ammo++;
- // simulation.updateGunHUD();
-
- // // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- // // if (b.guns[i].name === "harpoon") {
- // // b.guns[i].ammo++;
- // // simulation.updateGunHUD();
- // // break;
- // // }
- // // }
- // } else {
- // if (m.energy > this.drain) m.energy -= this.drain
- // const sub = Vector.sub(this.position, m.pos)
- // const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
- // const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
- // this.force.x -= returnForce.x
- // this.force.y -= returnForce.y
- // this.grabPowerUp()
- // }
- // this.draw();
- // },
- // grabPowerUp() { //grab power ups near the tip of the harpoon
- // if (this.caughtPowerUp) {
- // Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
- // Matter.Body.setVelocity(this.caughtPowerUp, {
- // x: 0,
- // y: 0
- // })
- // } else { //&& simulation.cycle % 2
- // for (let i = 0, len = powerUp.length; i < len; ++i) {
- // const radius = powerUp[i].circleRadius + 50
- // if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) {
- // if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
- // this.caughtPowerUp = powerUp[i]
- // Matter.Body.setVelocity(powerUp[i], {
- // x: 0,
- // y: 0
- // })
- // Matter.Body.setPosition(powerUp[i], this.vertices[2])
- // powerUp[i].collisionFilter.category = 0
- // powerUp[i].collisionFilter.mask = 0
- // this.thrustMag *= 0.6
- // this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
- // break //just pull 1 power up if possible
- // }
- // }
- // }
- // }
- // },
- // do() {
- // if (input.fire) { //&& !Matter.Query.collides(this, body).length
- // this.grabPowerUp()
- // if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction
- // this.endCycle = simulation.cycle + 60
- // // m.fireCDcycle = m.cycle + 120 // cool down
- // this.do = this.returnToPlayer
- // Matter.Body.setDensity(this, 0.0005); //reduce density on return
- // if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
- // this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
- // }
- // } else {
- // //if not enough energy
- // if (m.energy < 0.05) this.dropCaughtPowerUp()
- // // const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
- // // this.force.x -= returnForce.x
- // // this.force.y -= returnForce.y
- // // this.frictionAir = 0.002
- // // this.do = () => {
- // // if (this.speed < 20) this.force.y += 0.0005 * this.mass;
- // // }
-
- // // } else {
- // //return to player
- // this.do = this.returnToPlayer
- // this.endCycle = simulation.cycle + 60
- // Matter.Body.setDensity(this, 0.0005); //reduce density on return
- // if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
- // this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
- // //recoil on catching
- // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
- // player.force.x += momentum.x
- // player.force.y += momentum.y
- // // }
- // }
- // //grappling hook
- // if (input.fire && Matter.Query.collides(this, map).length) {
- // Matter.Body.setPosition(this, Vector.add(this.position, {
- // x: 20 * Math.cos(this.angle),
- // y: 20 * Math.sin(this.angle)
- // }))
- // if (Matter.Query.collides(this, map).length) {
- // Matter.Body.setVelocity(this, {
- // x: 0,
- // y: 0
- // });
- // Matter.Sleeping.set(this, true)
- // this.endCycle = simulation.cycle + 5
- // this.dropCaughtPowerUp()
- // this.do = () => {
- // //between player nose and the grapple
- // const sub = Vector.sub(this.vertices[0], {
- // x: m.pos.x + 30 * Math.cos(m.angle),
- // y: m.pos.y + 30 * Math.sin(m.angle)
- // })
- // let dist = Vector.magnitude(sub)
- // if (input.fire) {
- // // m.fireCDcycle = m.cycle + 30; // cool down if out of energy
- // m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
- // this.endCycle = simulation.cycle + 10
- // if (input.down) { //down
- // dist = 0
- // player.force.y += 5 * player.mass * simulation.g;
- // }
- // if (m.energy > this.drain) {
- // Matter.Body.setVelocity(player, {
- // x: player.velocity.x * 0.8,
- // y: player.velocity.y * 0.8
- // });
- // const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), 200))
- // player.force.x += pull.x
- // player.force.y += pull.y
-
- // if (dist > 500) {
- // m.energy -= this.drain
- // if (m.energy < 0) {
- // this.endCycle = 0;
- // if (m.cycle + 50 < m.fireCDcycle) m.fireCDcycle = m.cycle + 50
- // // refund ammo
- // b.guns[9].ammo++;
- // simulation.updateGunHUD();
- // // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- // // if (b.guns[i].name === "harpoon") {
- // // break;
- // // }
- // // }
- // }
- // }
- // }
- // if (tech.isImmuneGrapple && m.immuneCycle < m.cycle + 10) {
- // m.immuneCycle = m.cycle + 10;
- // if (m.energy > 0.001) {
- // m.energy -= 0.001
- // } else { //out of energy
- // Matter.Sleeping.set(this, false)
- // this.collisionFilter.category = 0
- // this.collisionFilter.mask = 0
- // this.do = this.returnToPlayer
- // this.endCycle = simulation.cycle + 60
- // m.fireCDcycle = m.cycle + 120; //fire cooldown
- // //recoil on catching
- // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
- // player.force.x += momentum.x
- // player.force.y += momentum.y
- // }
- // }
- // } else {
- // Matter.Sleeping.set(this, false)
- // this.collisionFilter.category = 0
- // this.collisionFilter.mask = 0
- // this.do = this.returnToPlayer
- // this.endCycle = simulation.cycle + 60
- // //recoil on catching
- // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
- // player.force.x += momentum.x
- // player.force.y += momentum.y
- // }
- // this.draw();
- // }
- // }
- // }
- // this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
- // this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
- // this.draw()
- // },
- // });
- // Composite.add(engine.world, bullet[me]); //add bullet to world
- // },
harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {
const me = bullet.length;
const returnRadius = 100 * Math.sqrt(harpoonSize)
@@ -2274,12 +2013,43 @@ const b = {
}
}
if (tech.isFoamBall) {
- for (let i = 0, len = Math.min(50, 2.5 + 3 * Math.sqrt(this.mass)); i < len; i++) {
+ for (let i = 0, len = Math.min(30, 2 + 2 * Math.sqrt(this.mass)); i < len; i++) {
const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
}
}
+ if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
+ Matter.Body.setDensity(this, 1.8 * tech.harpoonDensity); //+90% damage after pick up power up for 8 seconds
+ } else if (tech.isHarpoonFullHealth && who.health === 1) {
+ Matter.Body.setDensity(this, 1.9 * tech.harpoonDensity); //+90% damage if mob has full health do
+ simulation.ephemera.push({
+ name: "harpoon outline",
+ count: 2, //cycles before it self removes
+ vertices: this.vertices,
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
+ for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
+ ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
+ ctx.lineJoin = "miter"
+ ctx.miterLimit = 20;
+ ctx.lineWidth = 40;
+ ctx.strokeStyle = "rgba(255,0,100,0.35)";
+ ctx.stroke();
+ ctx.lineWidth = 10;
+ ctx.strokeStyle = `#f07`;
+ ctx.stroke();
+ ctx.lineJoin = "round"
+ ctx.miterLimit = 5
+ ctx.fillStyle = "#000"
+ ctx.fill();
+ },
+ })
+ }
},
caughtPowerUp: null,
dropCaughtPowerUp() {
@@ -2300,7 +2070,7 @@ const b = {
this.caughtPowerUp.effect();
Matter.Composite.remove(engine.world, this.caughtPowerUp);
powerUp.splice(index, 1);
- if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.006 is normal
+ if (tech.isHarpoonPowerUp) tech.harpoonPowerUpCycle = simulation.cycle
} else {
this.dropCaughtPowerUp()
}
@@ -2308,29 +2078,26 @@ const b = {
this.dropCaughtPowerUp()
}
},
- drawToggleHarpoon() {
+ drawDamageAura() {
ctx.beginPath();
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
ctx.lineJoin = "miter"
- ctx.miterLimit = 100;
- ctx.lineWidth = 60;
- ctx.strokeStyle = "rgba(0,255,255,0.25)";
+ ctx.miterLimit = 20;
+ ctx.lineWidth = 15;
+ ctx.strokeStyle = "rgba(255,0,100,0.25)";
ctx.stroke();
- ctx.lineWidth = 20;
- ctx.strokeStyle = "rgb(0,255,255)";
+ ctx.lineWidth = 4;
+ ctx.strokeStyle = `#f07`;
ctx.stroke();
ctx.lineJoin = "round"
- ctx.miterLimit = 10
+ ctx.miterLimit = 5
ctx.fillStyle = "#000"
ctx.fill();
},
drawString() {
- const where = {
- x: m.pos.x + 30 * Math.cos(m.angle),
- y: m.pos.y + 30 * Math.sin(m.angle)
- }
+ const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
const sub = Vector.sub(where, this.vertices[0])
const perpendicular = Vector.mult(Vector.normalise(Vector.perp(sub)), this.drawStringFlip * Math.min(80, 10 + this.drawStringControlMagnitude / (10 + Vector.magnitude(sub))))
const controlPoint = Vector.add(Vector.add(where, Vector.mult(sub, -0.5)), perpendicular)
@@ -2384,10 +2151,7 @@ const b = {
grabPowerUp() { //grab power ups near the tip of the harpoon
if (this.caughtPowerUp) {
Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
- Matter.Body.setVelocity(this.caughtPowerUp, {
- x: 0,
- y: 0
- })
+ Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
} else { //&& simulation.cycle % 2
for (let i = 0, len = powerUp.length; i < len; ++i) {
const radius = powerUp[i].circleRadius + 50
@@ -2395,10 +2159,7 @@ const b = {
if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
powerUp[i].isGrabbed = true
this.caughtPowerUp = powerUp[i]
- Matter.Body.setVelocity(powerUp[i], {
- x: 0,
- y: 0
- })
+ Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
Matter.Body.setPosition(powerUp[i], this.vertices[2])
powerUp[i].collisionFilter.category = 0
powerUp[i].collisionFilter.mask = 0
@@ -2459,15 +2220,15 @@ const b = {
this.draw();
}
}
- if (tech.isHarpoonPowerUp && bullet[me].density > 0.01) {
+ if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) { //8 seconds
if (isReturn) {
bullet[me].draw = function () {
- this.drawToggleHarpoon()
+ this.drawDamageAura()
this.drawString()
}
} else {
bullet[me].draw = function () {
- this.drawToggleHarpoon()
+ this.drawDamageAura()
}
}
} else if (isReturn) {
@@ -2628,15 +2389,9 @@ const b = {
if (dist < radius * radius) {
if (mob[i].speed > 2) {
if (mob[i].isBoss || mob[i].isShielded) {
- Matter.Body.setVelocity(mob[i], {
- x: mob[i].velocity.x * 0.95,
- y: mob[i].velocity.y * 0.95
- });
+ Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.95, y: mob[i].velocity.y * 0.95 });
} else {
- Matter.Body.setVelocity(mob[i], {
- x: mob[i].velocity.x * 0.25,
- y: mob[i].velocity.y * 0.25
- });
+ Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.25, y: mob[i].velocity.y * 0.25 });
}
}
// Matter.Body.setPosition(this, Vector.add(this.position, mob[i].velocity)) //move with the medium
@@ -5139,39 +4894,39 @@ const b = {
for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.soundBotCount; i++) b.soundBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
for (let i = 0; i < tech.missileBotCount; i++) b.missileBot({
x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5)
- }, false)
+ })
if (tech.isIntangible && m.isCloak) {
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield
@@ -5250,7 +5005,6 @@ const b = {
},
setDynamoBotDelay() {
- //reorder orbital bot positions around a circle
let total = 0
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'dynamo') total++
@@ -5259,13 +5013,17 @@ const b = {
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'dynamo') {
count++
- const step = Math.max(60 - 3 * total, 20)
- bullet[i].followDelay = (step * count) % 600
+ const step = Math.max(60 - 3 * total, 10)
+ if (bullet[i].isKeep) {
+ bullet[i].followDelay = (step * count) % 600
+ } else {
+ bullet[i].followDelay = Math.floor(step * bullet.length * Math.random()) % 600
+ }
}
}
},
- dynamoBot(position = player.position, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.dynamoBot()`);
+ dynamoBot(position = player.position, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.dynamoBot()`);
const me = bullet.length;
bullet[me] = Bodies.polygon(position.x, position.y, 5, 10, {
isUpgraded: tech.isDynamoBotUpgrade,
@@ -5274,7 +5032,8 @@ const b = {
frictionStatic: 0,
frictionAir: 0.02,
spin: 0.07 * (Math.random() < 0.5 ? -1 : 1),
- // isStatic: true,
+ // isStatic: true,
+ isKeep: isKeep,
isSensor: true,
restitution: 0,
dmg: 0, // 0.14 //damage done in addition to the damage from momentum
@@ -5359,17 +5118,14 @@ const b = {
}
}
let history = m.history[(m.cycle - this.followDelay) % 600]
- Matter.Body.setPosition(this, {
- x: history.position.x,
- y: history.position.y - history.yOff + 24.2859
- }) //bullets move with player
+ Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
}
})
Composite.add(engine.world, bullet[me]); //add bullet to world
b.setDynamoBotDelay()
},
- nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.nailBot()`);
+ nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.nailBot()`);
const me = bullet.length;
const dir = m.angle;
const RADIUS = (12 + 4 * Math.random())
@@ -5386,8 +5142,8 @@ const b = {
// lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20,
lastLookCycle: simulation.cycle + 60 * Math.random(),
delay: Math.floor((tech.isNailBotUpgrade ? 18 : 85) * b.fireCDscale),
- acceleration: 0.005 * (1 + 0.5 * Math.random()),
- range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(),
+ acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
+ range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100,
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
@@ -5433,8 +5189,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.missileBot()`);
+ missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.missileBot()`);
const me = bullet.length;
bullet[me] = Bodies.rectangle(position.x, position.y, 28, 11, {
botType: "missile",
@@ -5504,8 +5260,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.foamBot()`);
+ foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.foamBot()`);
const me = bullet.length;
const dir = m.angle;
const RADIUS = (10 + 5 * Math.random())
@@ -5524,8 +5280,8 @@ const b = {
fireCount: 0,
fireLimit: 5 + 2 * tech.isFoamBotUpgrade,
delay: Math.floor((145 + (tech.isFoamBotUpgrade ? 0 : 230)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
- acceleration: 0.005 * (1 + 0.5 * Math.random()),
- range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move
+ acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
+ range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
@@ -5625,8 +5381,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- soundBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.soundBot()`);
+ soundBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.soundBot()`);
const me = bullet.length;
const dir = m.angle;
bullet[me] = Bodies.rectangle(position.x, position.y, 12, 30, {
@@ -5644,8 +5400,8 @@ const b = {
fireCount: 0,
fireLimit: 5 + 2 * tech.isSoundBotUpgrade,
delay: Math.floor((120 + (tech.isSoundBotUpgrade ? 0 : 70)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
- acceleration: 0.005 * (1 + 0.5 * Math.random()),
- range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move
+ acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
+ range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
@@ -5791,11 +5547,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- laserBot(position = {
- x: player.position.x + 50 * (Math.random() - 0.5),
- y: player.position.y + 50 * (Math.random() - 0.5)
- }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.laserBot()`);
+ laserBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.laserBot()`);
const me = bullet.length;
const dir = m.angle;
const RADIUS = (14 + 6 * Math.random())
@@ -5833,10 +5586,7 @@ const b = {
const mag = Math.min(farAway, 4) * this.mass * this.acceleration
this.force = Vector.mult(Vector.normalise(Vector.sub(playerPos, this.position)), mag)
//manual friction to not lose rotational velocity
- Matter.Body.setVelocity(this, {
- x: this.velocity.x * 0.95,
- y: this.velocity.y * 0.95
- });
+ Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 });
//find targets
if (!(simulation.cycle % this.lookFrequency)) {
this.lockedOn = null;
@@ -5858,11 +5608,13 @@ const b = {
}
}
//randomize position relative to player
- if (Math.random() < 0.15) {
- const range = 110 + 4 * b.totalBots()
- this.offPlayer = {
- x: range * (Math.random() - 0.5),
- y: range * (Math.random() - 0.5) - 20,
+ if (Math.random() < 0.1) {
+ if (isKeep) {
+ const range = 110 + 4 * b.totalBots()
+ this.offPlayer = { x: range * (Math.random() - 0.5), y: range * (Math.random() - 0.5) - 20, }
+ } else {
+ const range = 110 + 4 * b.totalBots() + 100 * Math.random()
+ this.offPlayer = Vector.mult(Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random()), range)
}
}
}
@@ -6040,11 +5792,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- boomBot(position = {
- x: player.position.x + 50 * (Math.random() - 0.5),
- y: player.position.y + 50 * (Math.random() - 0.5)
- }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.boomBot()`);
+ boomBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.boomBot()`);
const me = bullet.length;
const dir = m.angle;
const RADIUS = (7 + 2 * Math.random())
@@ -6059,9 +5808,9 @@ const b = {
dmg: 0,
minDmgSpeed: 0,
lookFrequency: 43 + Math.floor(7 * Math.random()) - 13 * tech.isBoomBotUpgrade,
- acceleration: 0.005 * (1 + 0.5 * Math.random()),
+ acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
attackAcceleration: 0.012 + 0.006 * tech.isBoomBotUpgrade,
- range: 500 * (1 + 0.1 * Math.random()) + 350 * tech.isBoomBotUpgrade,
+ range: 500 * (1 + 0.1 * Math.random()) + 350 * tech.isBoomBotUpgrade + !isKeep * 100,
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
@@ -6131,8 +5880,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.plasmaBot()`);
+ plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.plasmaBot()`);
const me = bullet.length;
const dir = m.angle;
const RADIUS = 21
@@ -6305,8 +6054,8 @@ const b = {
})
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- orbitBot(position = player.position, isConsole = true) {
- if (isConsole) simulation.makeTextLog(`b.orbitBot()`);
+ orbitBot(position = player.position, isKeep = true) {
+ // if (isKeep) simulation.makeTextLog(`b.orbitBot()`);
const me = bullet.length;
bullet[me] = Bodies.polygon(position.x, position.y, 9, 12, {
isUpgraded: tech.isOrbitBotUpgrade,
@@ -6316,6 +6065,7 @@ const b = {
frictionAir: 1,
isStatic: true,
isSensor: true,
+ isKeep: isKeep,
restitution: 0,
dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 0,
@@ -6330,17 +6080,17 @@ const b = {
//reorder orbital bot positions around a circle
let totalOrbitalBots = 0
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'orbit' && bullet[i] !== this) totalOrbitalBots++
+ if (bullet[i].botType === 'orbit' && bullet[i] !== this && bullet[i].isKeep) totalOrbitalBots++
}
let index = 0
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'orbit' && bullet[i] !== this) {
+ if (bullet[i].botType === 'orbit' && bullet[i] !== this && bullet[i].isKeep) {
bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI
index++
}
}
},
- range: 190 + 130 * tech.isOrbitBotUpgrade, //range is set in bot upgrade too!
+ range: 190 + 130 * tech.isOrbitBotUpgrade + !isKeep * 60 * (0.5 - Math.random()), //range is set in bot upgrade too!
orbitalSpeed: 0,
phase: 2 * Math.PI * Math.random(),
do() {
@@ -6377,10 +6127,7 @@ const b = {
}
//orbit player
const time = simulation.cycle * this.orbitalSpeed + this.phase
- const orbit = {
- x: Math.cos(time),
- y: Math.sin(time) //*1.1
- }
+ const orbit = { x: Math.cos(time), y: Math.sin(time) }
Matter.Body.setPosition(this, Vector.add(m.pos, Vector.mult(orbit, this.range))) //bullets move with player
}
})
@@ -6392,11 +6139,11 @@ const b = {
//reorder orbital bot positions around a circle
let totalOrbitalBots = 0
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'orbit') totalOrbitalBots++
+ if (bullet[i].botType === 'orbit' && bullet[i].isKeep) totalOrbitalBots++
}
let index = 0
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'orbit') {
+ if (bullet[i].botType === 'orbit' && bullet[i].isKeep) {
bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI
index++
}
@@ -6739,7 +6486,7 @@ const b = {
name: "shotgun", //1
// description: `fire a wide burst of short range bullets
with a low fire rate
3-4 nails per ${powerUps.orb.ammo()}`,
descriptionFunction() {
- return `fire a wide burst of short range bullets
has a slow fire rate
${this.ammoPack.toFixed(1)} nails per ${powerUps.orb.ammo()}`
+ return `fire a wide burst of short range bullets
has a slow fire rate
${this.ammoPack.toFixed(1)} shots per ${powerUps.orb.ammo()}`
},
ammo: 0,
ammoPack: 3.5,
@@ -7995,7 +7742,6 @@ const b = {
}
//fire
if ((!input.fire && this.charge > 0.6)) {
- // tech.harpoonDensity = 0.0065 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
@@ -8067,8 +7813,6 @@ const b = {
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.03 : 0.06)
player.force.x -= recoil.x
player.force.y -= recoil.y
- // tech.harpoonDensity = 0.0065 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
-
const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
const thrust = 0.15 * (this.charge)
if (tech.extraHarpoons) {
@@ -8263,12 +8007,8 @@ const b = {
count++
if (!(count % delay) && this.ammo > 0) {
this.ammo--
- b.harpoon({
- x: m.pos.x + 30 * Math.cos(m.angle),
- y: m.pos.y + 30 * Math.sin(m.angle)
- }, null, angle, harpoonSize, true, totalCycles)
+ b.harpoon({ x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, null, angle, harpoonSize, true, totalCycles)
angle += SPREAD
- tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
}
if (count < num * delay && m.alive) requestAnimationFrame(harpoonDelay);
}
@@ -8298,7 +8038,6 @@ const b = {
} else {
b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles)
}
- tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
}
m.fireCDcycle = m.cycle + 5 + 35 * b.fireCDscale + 60 * (m.energy < 0.05) + tech.extraHarpoons // cool down is set when harpoon bullet returns to player
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.015 : 0.035)
diff --git a/js/index.js b/js/index.js
index 6e42585..cb0033c 100644
--- a/js/index.js
+++ b/js/index.js
@@ -967,7 +967,6 @@ ${simulation.isCheating ? "
lore disabled" : ""}
startExperiment() { //start playing the game after exiting the experiment menu
build.isExperimentSelection = false;
spawn.setSpawnList(); //gives random mobs, not starter mobs
- spawn.setSpawnList();
if (b.inventory.length > 0) {
b.activeGun = b.inventory[0] //set first gun to active gun
b.inventoryGun = 0;
diff --git a/js/level.js b/js/level.js
index e2f9fad..eecb410 100644
--- a/js/level.js
+++ b/js/level.js
@@ -11,7 +11,7 @@ const level = {
// playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
//see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
- communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave"],
+ communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo"],
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
levels: [],
start() {
@@ -19,17 +19,15 @@ const level = {
// simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
// simulation.isHorizontalFlipped = true
// tech.giveTech("performance")
- // level.difficultyIncrease(5 * 4) //30 is near max on hard //60 is near max on why
- // spawn.setSpawnList();
- // spawn.setSpawnList();
- // m.maxHealth = m.health = 100
+ // level.difficultyIncrease(8 * 2) //30 is near max on hard //60 is near max on why
+ // m.maxHealth = m.health = 1
// m.maxEnergy = m.energy = 10000000
// tech.isRerollDamage = true
// powerUps.research.changeRerolls(99999)
// m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100
// m.couplingChange(10)
- // m.setField("grappling hook") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
+ // m.setField("metamaterial cloaking") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// tech.isHookWire = true
// m.energy = 0
// simulation.molecularMode = 2
@@ -37,22 +35,23 @@ const level = {
// b.giveGuns("super balls") //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("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.guns[8].ammo = 100000000
- // requestAnimationFrame(() => { tech.giveTech("MACHO") });
- // for (let i = 0; i < 1; ++i) tech.giveTech("degenerate matter")
- // for (let i = 0; i < 1; ++i) tech.giveTech("reel")
- // for (let i = 0; i < 1; ++i) tech.giveTech("tokamak")
- // requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") });
- // for (let i = 0; i < 1; i++) tech.giveTech("laser-bot upgrade")
- // for (let i = 0; i < 1; ++i) tech.giveTech("rupture")
+ // requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") });
+ // for (let i = 0; i < 1; ++i) tech.giveTech("Higgs mechanism")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("topological defect")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("Hilbert space")
+ // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") });
+ // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) });
+
+ // for (let i = 0; i < 1; i++) tech.giveTech("cascading failure")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("induction furnace")
// for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense")
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling");
-
- // level.unchartedCave();
+ // level.skyscrapers();
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
- // for (let i = 0; i < 5; ++i) spawn.starter(1900, -500)
+ // for (let i = 0; i < 10; ++i) spawn.starter(1900, -500, 50)
// for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500)
// spawn.beetleBoss(1900, -500, 25)
// spawn.slasher2(2000, -1150)
@@ -64,13 +63,14 @@ const level = {
// for (let i = 0; i < 40; ++i) tech.giveTech()
level[simulation.isTraining ? "walk" : "intro"]() //normal starting level **************************************************
+
// spawn.bodyRect(2425, -120, 200, 200);
// console.log(body[body.length - 1].mass)
// simulation.isAutoZoom = false; //look in close
// simulation.zoomScale *= 0.5;
// simulation.setZoom();
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
- // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "boost");
+ // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "boost");
// for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo");
// for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false);
//lore testing
@@ -2159,8 +2159,9 @@ const level = {
spawn.mapRect(475, -25, 25, 50); //edge shelf
},
intro() {
- // console.log(level.levelsCleared)
if (level.levelsCleared === 0) { //if this is the 1st level of the game
+ if (simulation.difficultyMode > 2) spawn.setSpawnList() // hard and why difficulty don't begin with starter mobs
+
//wait to spawn power ups until unpaused
//power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode
const goal = simulation.cycle + 10
@@ -2172,10 +2173,17 @@ const level = {
} else {
powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125);
}
- if (simulation.difficultyMode < 5) {
+ if (simulation.difficultyMode < 5) { //hard, normal and easy
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false);
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
+ }
+ if (simulation.difficultyMode < 3) { //normal and easy
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
- powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); //not on why difficulty
+ }
+ if (simulation.difficultyMode < 2) { //easy
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
}
} else {
requestAnimationFrame(cycle);
@@ -2548,7 +2556,6 @@ const level = {
if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run
- // spawn.setSpawnList();
spawn.pickList.splice(0, 1);
spawn.pickList.push('starter');
spawn.pickList.splice(0, 1);
@@ -2662,6 +2669,7 @@ const level = {
if (gateButton.isUp) {
gateButton.query();
if (!gateButton.isUp) {
+ simulation.makeTextLog(`station gate opened`, 360);
if (stationNumber > 0) {
if (!isExitOpen && gatesOpenRight < stationNumber) level.newLevelOrPhase() //run some new level tech effects
gatesOpenRight = stationNumber
@@ -2673,7 +2681,7 @@ const level = {
gatesOpenRight = stationNumber
}
if (Math.abs(stationNumber) > 0 && ((Math.abs(stationNumber) + 1) % stationList.length) === 0) {
- simulation.makeTextLog(`exit opened`);
+ simulation.makeTextLog(`level exit opened`, 360);
isExitOpen = true;
}
}
@@ -2725,13 +2733,12 @@ const level = {
var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
}
}
-
spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
- spawn.mapRect(x + -1775, -1600, 3400, 1100); //center pillar
+ spawn.mapRect(x + -1775, -1600, 3400, 1000); //center pillar
spawn.mapRect(x + -4100, -3325, 8000, 700); //roof
spawn.mapRect(x + -4100, -3325, 325, 1500);
spawn.mapRect(x + 3500, -3325, 400, 1500);
- spawn.mapRect(x + -225, -575, 450, 425); //lower portal blocks
+ spawn.mapRect(x + -225, -700, 450, 600); //lower portal blocks
//upper parts
spawn.mapRect(x + -1425, -2400, 1900, 50);
@@ -3025,7 +3032,7 @@ const level = {
}
},
() => { //portal fling
- const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2083 },]
+ const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2080 },]
const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
if (isExitOpen) {
level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
@@ -3219,7 +3226,7 @@ const level = {
}
},
() => { //jump pads and 6 sided platforms
- const buttonsCoords = [{ x: x + 275, y: -1817 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2420 }, { x: x - 2100, y: -1995 }]
+ const buttonsCoords = [{ x: x + 278, y: -1814 }, { x: x + 778, y: -1814 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2425 }, { x: x - 2100, y: -1995 }]
const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
if (isExitOpen) {
level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
@@ -3375,7 +3382,7 @@ const level = {
}
},
]
- // stations[1]() //for testing a specific station
+ // stations[4]() //for testing a specific station
stations[stationList[Math.abs(stationNumber % stationList.length)]]() //*************** run this one when uploading
//add in standard station map infrastructure
spawn.mapRect(x + -8000, 0, 16000, 800);//tunnel floor
@@ -5034,10 +5041,12 @@ const level = {
powerUps.directSpawn(x + 1950, y - 1525, "ammo");
powerUps.directSpawn(x + 1900, y - 1525, "ammo");
spawn.hopMotherBoss(x + 800, y + -2200)
- for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
- for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
+ for (let i = 0; i < 4; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
+ for (let i = 0; i < 4; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
spawn.hopper(x + 1550, y + -775);
spawn.hopper(x + 500, y + -775);
+ spawn.hopper(x + 500, y + -2200);
+ spawn.hopper(x + 1100, y + -2200);
spawn.hopMother(x + 1400, y + -775);
spawn.hopMother(x + 550, y + -775);
spawn.hopMother(x + 525, y + -1475);
@@ -30084,9 +30093,6 @@ const level = {
},
unchartedCave() {
simulation.makeTextLog(`unchartedCave by 3xionDev`);
- //lore.unlockTesting();
- //simulation.enableConstructMode();
- level.difficultyIncrease(15);
level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 20985;
level.exit.y = 2816;
@@ -30095,7 +30101,6 @@ const level = {
level.defaultZoom = 1900
simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#979797";
- // color.map = "#444" //custom map color
spawn.randomMob(1000, -975, 0);
spawn.randomMob(2550, -575, 0);
@@ -30490,15 +30495,462 @@ const level = {
spawn.randomGroup(5835, -532, 0.4);
if (simulation.difficulty > 1) spawn.randomLevelBoss(18823, 2191);
spawn.secondaryBossChance(20217, 1913)
-
-
-
level.custom = () => {
level.exit.drawAndCheck();
level.enter.draw();
};
},
+ dojo() { // By weird_pusheen
+ simulation.makeTextLog(`dojo by werid_pusheen, fixed by Cornbread 2100`)
+ const vanishes = [];
+ const smoofes = [];
+ const leftRotor = level.rotor(-550, 900, 950, 25);
+ leftRotor.frictionAir = 0.01;
+ var leftSchwoof = level.boost(-20, -60, -2000);
+ var rightSchwoof = level.button(2550, -50);
+ var rightSchwoofState = false;
+ var rightSchwoofLive = true;
+ spawn.mapRect(2513, -39, 200, 100);
+ var pathPoints = [
+ [0, 0], // Index 0 is owned by M and is set to M's position during play
+ // this means that occasionally the boss will bonk M on the way to somewhere else, which gives it a chance to hurt M and gives the player a chance to hurt it
+ [250, -750], /* Left bases */
+ [250, -2500],
+ [350, -1500], // Left doorway
+ [1150, -1500], // Home base
+ [1150, -2750], // Upper base
+ [1950, -1500], // Right doorway
+ [2050, -750], /* Right bases */
+ [2050, -2500],
+ [-150, -250], // Left porthole
+ ];
+ function isntIn(point, array) {
+ for (var x = 0; x < array.length; x++) {
+ if (point[0] == array[x][0] && point[1] == array[x][1]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ function isObstructed(v1, v2) {
+ var ret = Matter.Query.ray(map,
+ {
+ x: v1[0],
+ y: v1[1],
+ },
+ {
+ x: v2[0],
+ y: v2[1]
+ }).length != 0;
+ return ret; // Kinda-ish stolen from mob.js
+ }
+ function pythag(p1, p2) {
+ var dx = p1[0] - p2[0];
+ var dy = p1[1] - p2[1];
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ var path = undefined; // This is a stupid way to go about pathfinding code. I might even clean it up!
+ function pathFind(goalPoint, startPoint, curPath = []) {
+ var myPoint = startPoint;
+ if (curPath.length) {
+ myPoint = curPath[curPath.length - 1];
+ }
+ if (path && (curPath.length >= path.length)) { // If we've already found a shorter or equal path, no reason to continue and waste CPU time
+ return; // Minimizes for HOP COUNT, not PATH LENGTH - path length was buggy
+ }
+ if (!isObstructed(myPoint, goalPoint)) { // If the line to the goal point ain't blocked by a map object, we've arrived!
+ path = [...curPath];
+ path.push(goalPoint);
+ return;
+ }
+ pathPoints.forEach(testPoint => {
+ if (isntIn(testPoint, curPath)) { // If it's reusing points, there's clearly something wrong
+ if (!isObstructed(myPoint, testPoint)) { // If the line to the test point ain't blocked by a map object
+ var thing = [...curPath];
+ thing.push(testPoint);
+ pathFind(goalPoint, startPoint, thing); // Branch to a valid test point
+ }
+ }
+ });
+ }
+ level.setPosToSpawn(1200, 500);
+ level.exit.x = 51500;
+ level.exit.y = -1875;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 1500;
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+
+ spawn.mapRect(-500, 0, 3300, 300); // Floor
+ spawn.mapRect(-100, -3000, 2500, 100); // Ceiling
+ spawn.mapRect(-200, -3000, 100, 2600); // Left wall
+ spawn.mapRect(2400, -3000, 100, 3000); // Right wall
+
+ spawn.mapRect(500, -1000, 100, 500); /* obstruction blocks */
+ smoofes.push(map[map.length - 1]);
+ spawn.mapRect(500, -2500, 100, 500);
+ smoofes.push(map[map.length - 1]);
+ spawn.mapRect(1700, -1000, 100, 500);
+ smoofes.push(map[map.length - 1]);
+ spawn.mapRect(1700, -2500, 100, 500);
+ smoofes.push(map[map.length - 1]);
+
+ spawn.mapRect(-1000, 550, 200, 50); // Left chonky stepppp low
+ spawn.mapRect(-800, 300, 200, 50); // Left chonky stepppp high
+ spawn.mapVertex(-1000, 1200, "0 0 100 0 700 500 700 700 0 700"); // Left chonky
+ spawn.mapRect(3100, 550, 200, 50); // Right chonky stepppp low
+ spawn.mapRect(2900, 300, 200, 50); // Right chonky stepppp high
+ spawn.mapVertex(3300, 1200, "0 0 -100 0 -700 500 -700 700 0 700"); // Right chonky
+ const leftElevator = level.elevator(-1400 - 300, 1450, 300, 100, 500);
+ const rightElevator = level.elevator(-1400 + 5100, 1450, 300, 100, 500);
+
+ spawn.mapRect(-150, -1700, 200, 50);
+ spawn.mapRect(400, -2050, 200, 50);
+ spawn.mapRect(1600, -1000, 200, 50);
+
+ spawn.randomMob(1200, 700);
+ spawn.randomMob(600, 1000);
+ spawn.randomMob(1800, 1000);
+ spawn.randomMob(3200, 400);
+ spawn.randomMob(3000, 200);
+ spawn.randomMob(-900, 400);
+ spawn.randomMob(-700, 200);
+ spawn.randomMob(1200, 1000);
+ for (var i = 0; i < 4; i++) {
+ spawn.randomSmallMob(Math.random() * 600 - 600, Math.random() * 3000 - 400);
+ }
+ spawn.grenadier(-300, -1000);
+ spawn.grenadier(2600, -1000);
+
+ spawn.mapRect(-1400, 1450, 5100, 100); // The True Floor
+
+ const slime = level.hazard(-1250, 1400, 4800, 50);
+ slime.maxHeight = 600;
+ simulation.draw.body = function () {
+ ctx.beginPath();
+ for (let i = 0, len = body.length; i < len; ++i) {
+ if (!body[i].hidden) {
+ let vertices = body[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ }
+ }
+ ctx.lineWidth = 2;
+ ctx.fillStyle = color.block;
+ ctx.fill();
+ ctx.strokeStyle = color.blockS;
+ ctx.stroke();
+ } // Override the old draw code to allow intelligent hiding of blocks - preferably this becomes official code because it's just a single added if statement and makes a lot of things cleaner and more intelligent
+
+ const vanish = function (x, y, width, height) { // normal vanishes don't work well on my map for some reason, so I rewrote
+ x += width / 2;
+ y += height / 2;
+ const getVertices = function (bX, bY, bW, bH) { return [{ x: bX, y: bY, index: 0, isInternal: false }, { x: bX + bW, y: bY, index: 1, isInternal: false }, { x: bX + bW, y: bY + bH, index: 4, isInternal: false }, { x: bX, y: bY + bH, index: 3, isInternal: false }] };
+ const cMask = cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ const vertices = getVertices(x, y, width, height);
+ const block = body[body.length] = Bodies.fromVertices(x, y, vertices, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cMask
+ },
+ isNoSetCollision: true,
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ isNonStick: true, //this keep sporangium from sticking
+ isTouched: false,
+ cWidth: width,
+ hiddenCycle: 0,
+ isStatic: true,
+ query() {
+ if (this.cWidth <= 0) {
+ if (this.cWidth > -100) {
+ this.cWidth = -100;
+ Matter.Body.setVertices(this, vertices);
+ }
+ this.isTouched = false;
+ this.collisionFilter.mask = undefined;
+ this.hidden = true;
+ this.hiddenCycle++;
+ if (this.hiddenCycle > 100) {
+ if (Matter.Query.collides(this, [player]).length) {
+ this.hiddenCycle = 50;
+ }
+ else {
+ this.hiddenCycle = 0;
+ this.cWidth = width;
+ this.collisionFilter.mask = cMask;
+ this.hidden = false;
+ }
+ }
+ }
+ else if (this.isTouched) {
+ Matter.Body.setVertices(this, getVertices(x, y, this.cWidth, height * (this.cWidth / width)));
+ this.cWidth -= 3;
+ }
+ else if (Matter.Query.collides(this, [player]).length) { // Elseif short circuit avoids expensive collision detection
+ this.isTouched = true;
+ }
+ }
+ });
+ return block;
+ };
+
+ vanishes.push(vanish(800, 800, 800, 50));
+ vanishes.push(vanish(400, 1100, 400, 50));
+ vanishes.push(vanish(1600, 1100, 400, 50));
+ for (const vanishBlock of vanishes) Composite.add(engine.world, vanishBlock);
+ spawn.bodyRect(1700, 812, 300, 25, 1, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.map
+ },
+ isNoSetCollision: true,
+ isNotHoldable: true,
+ isNonStick: true, //this keep sporangium from sticking
+ restitution: 1,
+ friction: 0,
+ frictionAir: 0,
+ frictionStatic: 0,
+ query() {
+ Matter.Body.setAngularVelocity(this, 0);
+ Matter.Body.applyForce(this, this.position, {
+ x: 0,
+ y: -(this.position.y - 812) * 0.002
+ });
+ }
+ });
+ const zigzag = body[body.length - 1];
+ Matter.Body.applyForce(zigzag, zigzag.position, {
+ x: 0.1,
+ y: 0
+ });
+ var buttonWasDown = false;
+ level.customTopLayer = () => {
+
+ }
+ level.custom = () => {
+ rightSchwoof.isUp = false;
+ level.exit.drawAndCheck();
+ leftSchwoof.query();
+ level.enter.draw();
+ pathPoints[0][0] = m.pos.x;
+ pathPoints[0][1] = m.pos.y;
+ leftElevator.move();
+ rightElevator.move();
+ slime.query();
+ zigzag.query();
+ slime.levelRise(0.2);
+ for (var i = 0; i < vanishes.length; i++) {
+ vanishes[i].query();
+ }
+ if (!rightSchwoofState) {
+ var math = m.pos.y < leftRotor.position.y;
+ Matter.Body.setAngularVelocity(leftRotor, (math ? 1 : -1) * Math.PI / 45);
+ }
+ if (rightSchwoofLive) {
+ rightSchwoof.query();
+ rightSchwoof.draw();
+ if (rightSchwoofState) {
+ ctx.fillStyle = "lightgreen";
+ }
+ else {
+ ctx.fillStyle = "red";
+ }
+ ctx.beginPath();
+ ctx.arc(2615, -220, 40, 0, Math.PI * 2);
+ ctx.fill();
+ }
+ if (rightSchwoof.isUp) {
+ buttonWasDown = true;
+ }
+ else if (buttonWasDown) {
+ buttonWasDown = false;
+ rightSchwoofState = !rightSchwoofState;
+ }
+ if (Matter.Query.collides(player, smoofes).length) {
+ Matter.Body.applyForce(player, player.position, {
+ x: 0,
+ y: -0.015
+ });
+ }
+ };
+
+ mobs.spawn(500, -500, 10, 100, "yellow"); /* TacticalBoss
+ Modes:
+ Spawn:
+ Pathfinds to a point above M and starts dropping mobs. Learns which mobs to drop to cause the most damage, of course.
+ Occasionally strikes at M.
+ Hide:
+ Pathfinds to the point furthest from M
+ Strike:
+ Pathfind really, really fast to M
+ Recharge:
+ Stop moving for a bit to "recharge" (this is so the player has a chance to hit it)
+
+ It must always Hide or Recharge after Spawning or Striking. Which one it does is based on some factor I'll figure out.
+ Pathfinding is a hypersimplified algorithm with hard-coded "points" that it can travel between. M is one of these.
+ */
+ var boss = mob[mob.length - 1];
+ boss.isBoss = true;
+ boss.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ boss.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ level.exit.x = 2560;
+ level.exit.y = -90;
+ rightSchwoofLive = false;
+ };
+ var spawnables = {};
+ ["hopper", "stabber", "springer", "striker", "sneaker", "grower"].forEach((m) => { /* Used to be spawn.fullPickList, but some of those mobs don't do collision-only damage and would thus never be properly selected for */
+ if (spawn[m]) {
+ spawnables[m] = {
+ fun: spawn[m],
+ name: m,
+ weight: 1
+ }
+ }
+ });
+ boss.stabCycle = 0;
+ boss.spawnCycle = 0;
+ function spawny() {
+ var totalWeight = 0;
+ Object.keys(spawnables).forEach(key => {
+ totalWeight += spawnables[key].weight;
+ });
+ var cursorWeight = 0;
+ var choice = Math.random();
+ var mC = undefined;
+ Object.values(spawnables).forEach((thing) => {
+ var lower = cursorWeight / totalWeight;
+ cursorWeight += thing.weight;
+ var upper = cursorWeight / totalWeight;
+ if ((choice > lower && choice <= upper) || !mC) {
+ mC = thing;
+ }
+ });
+ mC.fun(boss.position.x, boss.position.y);
+ var sp = mob[mob.length - 1];
+ sp.typeName = mC.name;
+ sp.onHit = () => {
+ spawnables[sp.typeName].weight += 1;
+ };
+ var oldFun = sp.onDeath;
+ sp.onDeath = () => { /* Mobs that die are worth less */
+ oldFun.call(sp);
+ spawnables[sp.typeName].weight -= 0.3; /* But not too much less */
+ };
+ }
+ boss.spawnDelay = 40;
+ boss.mode = "hide";
+ boss.modeSwitch = -1; // Randomize mode immediately
+ boss.damageReduction = 0.1;
+ var oldOnHit = boss.onHit;
+ boss.onHit = () => {
+ boss.modeSwitch = -1; // After striking the player, always switch modes
+ oldOnHit.call(boss); //this is the line that is bugging <-----
+ };
+ boss.do = () => {
+ path = undefined;
+ var pfGoal = [0, 0];
+ boss.modeSwitch--;
+ if (boss.modeSwitch < 0) {
+ if (!boss.isShielded) {
+ spawn.shield(boss, boss.position.x, boss.position.y, 0.75); // Every time the mode switches, have a 75% chance to gain a new shield
+ }
+ if (boss.mode == "hide" || boss.mode == "recharge") {
+ if (Math.random() > 0.5) {
+ boss.mode = "spawn";
+ }
+ else {
+ boss.mode = "strike";
+ }
+ boss.modeSwitch = 600;
+ }
+ else {
+ if (boss.mode == "strike") {
+ boss.mode = "hide"; // Always hides after striking
+ }
+ else {
+ if (Math.random() > 0.5) {
+ boss.mode = "hide";
+ }
+ else {
+ boss.mode = "recharge"; // same when it goes into recharge mode
+ spawn.shield(boss, boss.position.x, boss.position.y, 1);
+ }
+ }
+ boss.modeSwitch = 200;
+ }
+ }
+ if (boss.mode == "hide") { /* Find the furthest point from M and get to it */
+ var longest = 0;
+ pathPoints.forEach(item => {
+ if (item[0] == 1150) {
+ return;
+ }
+ var iL = pythag(item, [m.pos.x, m.pos.y]);
+ if (iL > longest) {
+ longest = iL;
+ pfGoal = item;
+ }
+ });
+ }
+ else if (boss.mode == "strike") {
+ pfGoal = pathPoints[0]; // Target M
+ }
+ else if (boss.mode == "spawn") {
+ pfGoal = pathPoints[4]; // Go to Home Base to spawn
+ }
+ if (boss.mode != "recharge") {
+ if (m.pos.x > 2350 || m.pos.x < -150 || m.pos.y > 50) {
+ boss.mode = "hide";
+ }
+ pathFind(pfGoal, [boss.position.x, boss.position.y]);
+ if (!path) {
+ return; // If it couldn't pathfind, just drift
+ }
+ var goalX = path[0][0];
+ var goalY = path[0][1];
+
+ var dX = goalX - boss.position.x;
+ var dY = goalY - boss.position.y;
+ var hyp = Math.sqrt(dX * dX + dY * dY);
+ Matter.Body.applyForce(boss, {
+ x: goalX,
+ y: goalY
+ }, {
+ x: dX / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1),
+ y: dY / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1)// - 0.005
+ });
+ }
+ if (boss.mode == "spawn") {
+ boss.stabCycle++;
+ if (boss.stabCycle > 25) {
+ if (Math.abs(dX) < 200 && dY > 0) {
+ Matter.Body.applyForce(boss, {
+ x: player.position.x,
+ y: player.position.y
+ }, {
+ x: 0,
+ y: 5
+ });
+ }
+ boss.stabCycle = 0;
+ }
+ boss.spawnCycle++;
+ if (boss.spawnCycle > boss.spawnDelay) {
+ spawny();
+ boss.spawnDelay += 4;
+ boss.spawnCycle = 0;
+ }
+ }
+ };
+ boss.showHealthBar = true;
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
// ********************************************************************************************************
// ********************************************************************************************************
// ***************************************** training levels **********************************************
diff --git a/js/mob.js b/js/mob.js
index d86b9fc..18434b1 100644
--- a/js/mob.js
+++ b/js/mob.js
@@ -242,7 +242,7 @@ const mobs = {
deathCount: 0,
mobSpawnWithHealth: 1,
setMobSpawnHealth() {
- mobs.mobSpawnWithHealth = 0.89 ** (tech.mobSpawnWithHealth)
+ mobs.mobSpawnWithHealth = 0.88 ** (tech.mobSpawnWithHealth)
},
//**********************************************************************************************
//**********************************************************************************************
@@ -1133,6 +1133,85 @@ const mobs = {
if ((!this.isShielded || isBypassShield) && this.alive) {
if (dmg !== Infinity) {
dmg *= tech.damageFromTech()
+ if (this.isDropPowerUp) {
+ if (this.health === 1) {
+ if (tech.isMobFullHealth) {
+ dmg *= 1.55
+
+ simulation.ephemera.push({
+ name: "damage outline",
+ count: 5, //cycles before it self removes
+ vertices: this.vertices,
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
+ ctx.strokeStyle = `#f05` //"rgba(150,150,225,0.5)";
+ ctx.stroke();
+ },
+ })
+ } else if (tech.isMobFullHealthCloak) {
+ dmg *= 1.88
+
+ simulation.ephemera.push({
+ name: "damage outline",
+ count: 7, //cycles before it self removes
+ vertices: this.vertices,
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = `rgba(255,0,100,0.15)` //"rgba(150,150,225,0.5)";
+ ctx.fill()
+ ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
+ ctx.strokeStyle = `#f08` //"rgba(150,150,225,0.5)";
+ ctx.stroke();
+ },
+ })
+ }
+ } else if (tech.isMobLowHealth && this.health < 0.25) {
+ dmg *= 3.22
+
+ simulation.ephemera.push({
+ name: "damage outline",
+ count: 2, //cycles before it self removes
+ vertices: this.vertices,
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = `rgba(255,50,100,0.2)` //"rgba(150,150,225,0.5)";
+ ctx.fill()
+ ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
+ ctx.strokeStyle = `#f38` //"rgba(150,150,225,0.5)";
+ ctx.stroke();
+ },
+ })
+ }
+ }
+
//mobs specific damage changes
if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 33% dmg at max range of 3000
dmg *= this.damageReduction
@@ -1143,6 +1222,7 @@ const mobs = {
}
dmg /= Math.sqrt(this.mass)
}
+
this.health -= dmg
//this.fill = this.color + this.health + ')';
this.onDamage(dmg); //custom damage effects
@@ -1187,7 +1267,7 @@ const mobs = {
leaveBody: true,
isDropPowerUp: true,
death() {
- if (tech.collidePowerUps && Math.random() < tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups
+ if (tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups
this.onDeath(this); //custom death effects
this.removeConsBB();
this.alive = false; //triggers mob removal in mob[i].replace(i)
@@ -1261,22 +1341,23 @@ const mobs = {
}
if (tech.isBotSpawnerReset) {
for (let i = 0, len = bullet.length; i < len; i++) {
- if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 780 //13 seconds
+ if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 900 //15 seconds
}
}
if (Math.random() < tech.botSpawner) {
b.randomBot(this.position, false)
- bullet[bullet.length - 1].endCycle = simulation.cycle + 780 //13 seconds
+ bullet[bullet.length - 1].endCycle = simulation.cycle + 900 //15 seconds
this.leaveBody = false; // no body since it turned into the bot
}
if (tech.isAddRemoveMaxHealth) {
if (this.isBoss && this.isDropPowerUp) {
powerUps.spawn(this.position.x + 20, this.position.y, "tech", false)
- powerUps.spawn(this.position.x - 20, this.position.y, "ammo", false)
+ powerUps.spawn(this.position.x - 20, this.position.y, "research", false)
+ powerUps.spawn(this.position.x - 40, this.position.y, "research", false)
+ powerUps.spawn(this.position.x + 40, this.position.y, "research", false)
powerUps.spawn(this.position.x, this.position.y + 20, "research", false)
powerUps.spawn(this.position.x, this.position.y - 20, "heal", false)
- powerUps.spawn(this.position.x - 40, this.position.y, "ammo", false)
- powerUps.spawn(this.position.x, this.position.y + 40, "research", false)
+ powerUps.spawn(this.position.x, this.position.y + 40, "heal", false)
powerUps.spawn(this.position.x, this.position.y - 40, "heal", false)
} else {
const amount = 0.005
@@ -1292,7 +1373,7 @@ const mobs = {
}
}
if (tech.cloakDuplication && !this.isBoss) {
- tech.cloakDuplication -= 0.02
+ tech.cloakDuplication -= 0.01
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
}
} else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) {
diff --git a/js/player.js b/js/player.js
index ed5cc78..7877e7d 100644
--- a/js/player.js
+++ b/js/player.js
@@ -393,7 +393,7 @@ const m = {
for (let i = 0, len = b.inventory.length; i < len; i++) {
if (b.guns[b.inventory[i]].ammo !== Infinity) b.guns[b.inventory[i]].ammo = Math.max(0, Math.floor(ammoCount / b.inventory.length * b.guns[b.inventory[i]].ammoPack * (1.15 + 0.3 * (Math.random() - 0.5))))
}
- console.log(b.activeGun)
+ // console.log(b.activeGun)
//randomize tech
for (let i = 0; i < totalTech; i++) {
//find what tech I could get
@@ -568,7 +568,7 @@ const m = {
if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0193, 0.88) //capped at speed of 55
- if (tech.isHarmReduce && input.field) dmg *= 0.15
+ if (tech.isHarmReduce && input.field) dmg *= 0.12
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
@@ -935,83 +935,6 @@ const m = {
ctx.restore();
}
},
- // resetSkin() {
- // simulation.isAutoZoom = true;
- // m.yOffWhen.jump = 70
- // m.yOffWhen.stand = 49
- // m.yOffWhen.crouch = 22
- // m.isAltSkin = false
- // m.color = {
- // hue: 0,
- // sat: 0,
- // light: 100,
- // }
- // m.setFillColors();
- // m.draw = function () {
- // ctx.fillStyle = m.fillColor;
- // m.walk_cycle += m.flipLegs * m.Vx;
- // ctx.save();
- // ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
- // ctx.translate(m.pos.x, m.pos.y);
- // m.calcLeg(Math.PI, -3);
- // m.drawLeg("#4a4a4a");
- // m.calcLeg(0, 0);
- // m.drawLeg("#333");
- // ctx.rotate(m.angle);
- // ctx.beginPath();
- // ctx.arc(0, 0, 30, 0, 2 * Math.PI);
- // ctx.fillStyle = m.bodyGradient
- // ctx.fill();
- // ctx.arc(15, 0, 4, 0, 2 * Math.PI);
- // ctx.strokeStyle = "#333";
- // ctx.lineWidth = 2;
- // ctx.stroke();
- // ctx.restore();
- // m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
- // powerUps.boost.draw()
- // }
- // m.drawLeg = function (stroke) {
- // // if (simulation.mouseInGame.x > m.pos.x) {
- // if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
- // m.flipLegs = 1;
- // } else {
- // m.flipLegs = -1;
- // }
- // ctx.save();
- // ctx.scale(m.flipLegs, 1); //leg lines
- // ctx.beginPath();
- // ctx.moveTo(m.hip.x, m.hip.y);
- // ctx.lineTo(m.knee.x, m.knee.y);
- // ctx.lineTo(m.foot.x, m.foot.y);
- // ctx.strokeStyle = stroke;
- // ctx.lineWidth = 7;
- // ctx.stroke();
-
- // //toe lines
- // ctx.beginPath();
- // ctx.moveTo(m.foot.x, m.foot.y);
- // ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
- // ctx.moveTo(m.foot.x, m.foot.y);
- // ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
- // ctx.lineWidth = 4;
- // ctx.stroke();
-
- // //hip joint
- // ctx.beginPath();
- // ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
- // //knee joint
- // ctx.moveTo(m.knee.x + 7, m.knee.y);
- // ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
- // //foot joint
- // ctx.moveTo(m.foot.x + 6, m.foot.y);
- // ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
- // ctx.fillStyle = m.fillColor;
- // ctx.fill();
- // ctx.lineWidth = 2;
- // ctx.stroke();
- // ctx.restore();
- // }
- // },
skin: {
none() {
m.isAltSkin = true
@@ -1146,6 +1069,96 @@ const m = {
ctx.restore();
}
},
+ strokeGap() {
+ m.isAltSkin = true
+ m.yOffWhen.stand = 52
+ m.yOffWhen.jump = 72
+ // m.yOffWhen.crouch = 22
+ // m.color = {
+ // hue: 184,
+ // sat: 0,
+ // light: 55,
+ // }
+ // m.setFillColors();
+ m.draw = function () {
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -1.25);
+ m.drawLeg("#606070");
+ m.calcLeg(0, 0);
+ m.drawLeg("#445");
+
+
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ // ctx.arc(0, 0, 30, m.angle + 1, m.angle - 1);
+ ctx.fillStyle = "#fff"//m.bodyGradient
+ ctx.fill();
+ ctx.beginPath();
+ const arc = 0.7 + 0.17 * Math.sin(m.cycle * 0.012)
+ ctx.arc(0, 0, 30, -arc, arc, true); //- Math.PI / 2
+ ctx.strokeStyle = "#445";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(13, 0)
+ ctx.lineTo(20, 0)
+ // ctx.beginPath();
+ // ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "#445";
+ ctx.stroke();
+
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 5;
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x - 14, m.foot.y + 5);
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x + 14, m.foot.y + 5);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y, 8, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 4, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 4, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(m.foot.x + 4, m.foot.y + 1);
+ ctx.arc(m.foot.x, m.foot.y + 1, 4, 0, 2 * Math.PI);
+ ctx.fillStyle = m.fillColor;
+ ctx.fill();
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
energy() {
m.isAltSkin = true
m.color = {
@@ -1333,17 +1346,9 @@ const m = {
sat: 14,
light: 65,
}
- // m.setFillColors();
m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 50}%)`
- // let grd = ctx.createLinearGradient(-30, 0, 30, 0);
const grd = ctx.createRadialGradient(16, 0, 0, 0, 0, 40);
-
- // grd.addColorStop(0, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
- // grd.addColorStop(0.25, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 20}%)`);
- // grd.addColorStop(0.5, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
- // grd.addColorStop(1, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 10}%)`);
-
grd.addColorStop(0, `#c78034`);
grd.addColorStop(0.04, `#bd5235`);
grd.addColorStop(0.08, `#ab554d`);
@@ -1369,10 +1374,8 @@ const m = {
grd.addColorStop(0.92, `#00e19b`);
grd.addColorStop(0.96, `#19f5aa`);
grd.addColorStop(1, `#aaf5af`);
-
m.bodyGradient = grd
-
m.draw = function () {
ctx.fillStyle = m.fillColor;
m.walk_cycle += m.flipLegs * m.Vx;
@@ -1410,7 +1413,7 @@ const m = {
ctx.lineTo(m.knee.x, m.knee.y);
ctx.lineTo(m.foot.x, m.foot.y);
ctx.strokeStyle = stroke;
- ctx.lineWidth = 7;
+ ctx.lineWidth = 5;
ctx.stroke();
//toe lines
@@ -1424,21 +1427,22 @@ const m = {
//hip joint
ctx.beginPath();
- ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
- ctx.fillStyle = "#1b85cf";
+ ctx.arc(m.hip.x, m.hip.y, 9, 0, 2 * Math.PI);
+ ctx.fillStyle = "#222";
+ // ctx.fillStyle = "#1b85cf";
ctx.fill();
//knee joint
ctx.beginPath();
- ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
- ctx.fillStyle = "#ffa050";
+ ctx.arc(m.knee.x, m.knee.y, 5, 0, 2 * Math.PI);
+ // ctx.fillStyle = "#ffa050";
ctx.fill();
//foot joint
ctx.beginPath();
- ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
- ctx.fillStyle = "#878cf0";
+ ctx.arc(m.foot.x, m.foot.y, 4, 0, 2 * Math.PI);
+ // ctx.fillStyle = "#878cf0";
ctx.fill();
- ctx.lineWidth = 2;
- ctx.stroke();
+ // ctx.lineWidth = 3;
+ // ctx.stroke();
ctx.restore();
}
},
@@ -2636,7 +2640,7 @@ const m = {
},
fieldUpgrades: [{
name: "field emitter",
- imageNumber: Math.floor(Math.random() * 23),
+ imageNumber: Math.floor(Math.random() * 26), //pick one of the 25 field emitter image files at random
description: `initial field
use energy to deflect mobs and throw blocks
generate 4 energy per second`, //
100 max energy
effect: () => {
@@ -2934,7 +2938,6 @@ const m = {
// if (m.energy < m.fieldRegen) m.fieldCDcycle = m.cycle + 90;
// }
-
if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
m.grabPowerUp();
m.lookForPickUp();
@@ -3998,7 +4001,7 @@ const m = {
},
{
name: "metamaterial cloaking",
- description: "+50% defense while cloaked
after decloaking +333% damage for 2 s
generate 6 energy per second",
+ description: "+66% defense while cloaked
after decloaking +333% damage for 2 s
generate 6 energy per second",
effect: () => {
m.fieldFire = true;
m.fieldMeterColor = "#333";
@@ -4013,29 +4016,6 @@ const m = {
m.walk_cycle -= m.flipLegs * m.Vx;
m.pos.x += 4
m.draw();
-
- // let history = m.history[(m.cycle - 1) % 600]
- // m.pos.x = history.position.x
- // m.pos.y = history.position.y + m.yPosDifference - history.yOff
-
- // m.pos.x += 4
- // ctx.fillStyle = m.fillColor;
- // ctx.save();
- // ctx.translate(m.pos.x, m.pos.y);
- // m.calcLeg(Math.PI, -3);
- // m.drawLeg("#ccc");
- // m.calcLeg(0, 0);
- // m.drawLeg("#ccc");
- // ctx.rotate(m.angle);
- // ctx.beginPath();
- // ctx.arc(0, 0, 30, 0, 2 * Math.PI);
- // ctx.fillStyle = "#fff"
- // ctx.fill();
- // ctx.arc(15, 0, 4, 0, 2 * Math.PI);
- // ctx.strokeStyle = "#333";
- // ctx.lineWidth = 2;
- // ctx.stroke();
- // ctx.restore()
}
m.drawCloak = function () {
m.fieldPhase += 0.007
@@ -4067,27 +4047,27 @@ const m = {
}
//not shooting (or using field) enable cloak
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
- if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing
+ if (m.fireCDcycle + 10 < m.cycle && !input.fire) { //automatically cloak if not firing
const drain = 0.02
if (!m.isCloak && m.energy > drain + 0.03) {
m.energy -= drain
m.isCloak = true //enter cloak
- m.fieldHarmReduction = 0.5;
+ m.fieldHarmReduction = 0.33; //66% reduction
m.enterCloakCycle = m.cycle
if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy)
- if (m.energy > heal) {
- m.energy -= heal
- m.addHealth(heal); //heal from last hit
- m.lastHit = 0
- simulation.drawList.push({ //add dmg to draw queue
- x: m.pos.x,
- y: m.pos.y,
- radius: Math.sqrt(heal) * 200,
- color: "rgba(0,255,200,0.6)",
- time: 16
- });
- }
+ // if (m.energy > heal) {
+ // m.energy -= heal * 0.8
+ m.addHealth(heal); //heal from last hit
+ m.lastHit = 0
+ simulation.drawList.push({ //add dmg to draw queue
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: Math.sqrt(heal) * 200,
+ color: "rgba(0,255,200,0.6)",
+ time: 16
+ });
+ // }
}
if (tech.isIntangible) {
for (let i = 0; i < bullet.length; i++) {
@@ -4133,9 +4113,16 @@ const m = {
m.fieldRange = m.fieldRange * 0.85 + 130
m.fieldDrawRadius = m.fieldRange * 1.1 //* 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak()
- ctx.globalCompositeOperation = "lighter";
- m.drawCloakedM()
- ctx.globalCompositeOperation = "source-over";
+ // ctx.globalCompositeOperation = "lighter";
+ // m.drawCloakedM()
+ // ctx.globalCompositeOperation = "source-over";
+
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 35, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(255,255,255,0.25)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
+ ctx.lineWidth = 10
+ ctx.stroke();
+
} else if (m.fieldRange < 4000) {
m.fieldRange += 90
m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
@@ -4148,8 +4135,8 @@ const m = {
if (inPlayer.length > 0) {
for (let i = 0; i < inPlayer.length; i++) {
if (m.energy > 0) {
- if (!inPlayer[i].isUnblockable) m.energy -= 0.007;
- if (inPlayer[i].shield) m.energy -= 0.025;
+ if (!inPlayer[i].isUnblockable) m.energy -= 0.003;
+ if (inPlayer[i].shield) m.energy -= 0.011;
}
}
}
@@ -4158,10 +4145,17 @@ const m = {
}
}
this.drawRegenEnergyCloaking()
- if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
- ctx.globalCompositeOperation = "multiply";
- m.drawCloakedM()
- ctx.globalCompositeOperation = "source-over";
+ if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
+ const timeLeft = (m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) - m.cycle) * 0.5
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 32, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(180,30,70,0.5)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
+ ctx.lineWidth = Math.max(Math.min(10, timeLeft), 3);
+ ctx.stroke();
+
+ // ctx.globalCompositeOperation = "multiply";
+ // m.drawCloakedM()
+ // ctx.globalCompositeOperation = "source-over";
}
}
}
diff --git a/js/powerup.js b/js/powerup.js
index 27ee626..562a8b2 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -534,26 +534,24 @@ const powerUps = {
if (!tech.isEnergyHealth && m.alive) {
powerUps.animatePowerUpGrab('rgba(0, 238, 187,0.25)')
let heal = (this.size / 40 / (simulation.healScale ** 0.25)) ** 2 //simulation.healScale is undone here because heal scale is already properly affected on m.addHealth()
- // console.log("size = " + this.size, "heal = " + heal)
if (heal > 0) {
const overHeal = m.health + heal * simulation.healScale - m.maxHealth //used with tech.isOverHeal
const healOutput = Math.min(m.maxHealth - m.health, heal) * simulation.healScale
m.addHealth(heal);
if (healOutput > 0) simulation.makeTextLog(`m.health += ${(healOutput).toFixed(3)}`) //
${m.health.toFixed(3)}
if (tech.isOverHeal && overHeal > 0) { //tech quenching
- const scaledOverHeal = overHeal // * 0.9
- m.damage(scaledOverHeal);
- simulation.makeTextLog(`m.health -= ${(scaledOverHeal).toFixed(3)}`) //
${m.health.toFixed(3)}
+ m.damage(overHeal);
+ simulation.makeTextLog(`m.health -= ${(overHeal).toFixed(3)}`) //
${m.health.toFixed(3)}
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
- radius: scaledOverHeal * 500 * simulation.healScale,
+ radius: overHeal * 500 * simulation.healScale,
color: simulation.mobDmgColor,
time: simulation.drawTime
});
- tech.extraMaxHealth += scaledOverHeal * simulation.healScale //increase max health
+ tech.extraMaxHealth += overHeal * Math.sqrt(simulation.healScale) //increase max health
m.setMaxHealth();
- } else if (overHeal > 0.1) {
+ } else if (overHeal > 0.13) { //if leftover heals spawn a new spammer heal power up
requestAnimationFrame(() => {
powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
});
diff --git a/js/simulation.js b/js/simulation.js
index 6ca36b5..4b73590 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -1272,7 +1272,7 @@ const simulation = {
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isDropPowerUp && mob[i].alive) count++
}
- count *= 0.17 //to fake the chance, this makes it not random, and maybe less confusing
+ count *= 0.22 //to fake the 20% chance, this makes it not random, and more predictable
let cycle = () => { //run after waiting a cycle for the map to be cleared
const types = ["heal", "ammo", "heal", "ammo", "research", "coupling", "boost", "tech", "gun", "field"]
for (let i = 0; i < count; i++) powerUps.spawnDelay(types[Math.floor(Math.random() * types.length)], 1)
diff --git a/js/spawn.js b/js/spawn.js
index cb45c95..5b5b277 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -200,7 +200,7 @@ const spawn = {
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isShielded) {
if (Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius < this.radius) {
- mob[i].damage(0.02 * m.dmgScale);
+ mob[i].damage(0.025 * m.dmgScale);
// mob[i].locatePlayer();//
simulation.drawList.push({ //add dmg to draw queue
@@ -366,7 +366,7 @@ const spawn = {
me.maxMobs = 400
me.mode = [{
name: "boulders",
- spawnRate: 170 - 6 * simulation.difficultyMode,
+ spawnRate: Math.max(30, 170 - 5 * simulation.difficultyMode),
do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.boulder(me.position.x, me.position.y + 250)
@@ -374,10 +374,11 @@ const spawn = {
},
enter() { },
exit() { },
- }, {
+ },
+ {
name: "mobs",
// whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
- spawnRate: 280 - 20 * simulation.difficultyMode,
+ spawnRate: Math.max(60, 240 - 20 * simulation.difficultyMode),
do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.torque += 0.000015 * me.inertia; //spin
@@ -397,7 +398,7 @@ const spawn = {
},
{
name: "hoppers",
- spawnRate: 480 - 16 * simulation.difficultyMode,
+ spawnRate: Math.max(90, 480 - 16 * simulation.difficultyMode),
do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.torque += 0.00002 * me.inertia; //spin
@@ -422,7 +423,7 @@ const spawn = {
},
{
name: "seekers",
- spawnRate: 100 - 3 * simulation.difficultyMode,
+ spawnRate: Math.max(15, 100 - 3 * simulation.difficultyMode),
do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
const index = Math.floor((me.cycle % 360) / 60)
@@ -440,7 +441,7 @@ const spawn = {
{
name: "mines",
bombCycle: 0,
- bombInterval: 10 - simulation.difficultyMode,
+ bombInterval: Math.max(2, 10 - simulation.difficultyMode),
do() {
const yOff = 120
this.bombCycle++
@@ -498,7 +499,7 @@ const spawn = {
},
{
name: "orbiters",
- spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode),
+ spawnRate: Math.ceil(Math.max(2, 5 - 0.2 * simulation.difficultyMode)),
orbitersCycle: 0,
do() {
this.orbitersCycle++
@@ -522,7 +523,7 @@ const spawn = {
this.fadeCycle++
if (this.fadeCycle > 0) {
me.torque += this.spinForce * me.inertia; //spin //0.00000015
- if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
+ if (this.fadeCycle > 360) this.fadeCycle = -200 + simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
ctx.strokeStyle = "#50f";
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
ctx.lineWidth = 1.5;
@@ -561,7 +562,7 @@ const spawn = {
{
name: "black hole",
eventHorizon: 0,
- eventHorizonRadius: 1900,
+ eventHorizonRadius: 1700,
eventHorizonCycle: 0,
do() {
this.eventHorizonCycle++
@@ -629,15 +630,121 @@ const spawn = {
spawn.shield(me, me.position.x, me.position.y, 1);
},
exit() { this.waveCycle = 0 },
+ },
+ {
+ name: "slow zone",
+ waveCycle: 0,
+ whereX: simulation.isHorizontalFlipped ? -3000 : 3000,
+ width: 1200,
+ // isActive: false,
+ cycle: 0,
+ cycleDuration: 150,
+ zone: 0,
+ isMovingRight: true,
+ playerSlowTime: 0,
+ do() {
+ // console.log(zone)
+ this.cycle++
+ if (this.cycle % this.cycleDuration === 0) { //next zone
+ this.zone += this.isMovingRight ? 1 : -1
+ if (this.zone > 0) this.isMovingRight = false
+ if (this.zone < -1) this.isMovingRight = true
+ this.whereX = (simulation.isHorizontalFlipped ? -3000 : 3000) + this.width * this.zone
+ }
+ //draw slow zone
+ if (this.cycle % this.cycleDuration > 0.45 * this.cycleDuration) {
+ ctx.fillStyle = `rgba(0, 100, 255, ${0.19 + 0.015 * Math.sin(simulation.cycle * 0.36)})`;
+ ctx.fillRect(this.whereX, -1500, this.width, 1500);
+ //check for player in range and apply slow debuff
+ if (player.position.x > this.whereX && player.position.x < this.whereX + this.width) {
+ this.playerSlowTime = 180
+ //damage player
+ const dmg = 0.0001 * simulation.dmgScale
+ m.damage(dmg);
+ }
+ } else { //show where slow zone is about to show up
+ ctx.fillStyle = `rgba(0, 100, 255, ${0.2 + 0.25 * Math.random()})`;
+ ctx.fillRect(this.whereX, -1500, this.width, 12);
+ ctx.fillRect(this.whereX, -12, this.width, 12);
+ }
+ if (this.playerSlowTime > 0) {
+ this.playerSlowTime-- //warm up player when outside of slow zone
+ //slow player
+ // Matter.Body.setVelocity(player, Vector.mult(player.velocity, (1 - 0.01 * this.playerSlowTime)));
+ // Matter.Body.setVelocity(player, { x: (1 - 0.01 * this.playerSlowTime) * player.velocity.x, y: (1 - 0.0025 * this.playerSlowTime) * player.velocity.y }); //makes the player get stuck slow when walking horizontally
+ Matter.Body.setVelocity(player, { x: Math.max(0.05, 1 - 0.01 * Math.max(10, this.playerSlowTime)) * player.velocity.x, y: Math.max(0.2, 1 - 0.0025 * this.playerSlowTime) * player.velocity.y });
+ //draw effect on player
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 45, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(0,100,255,${(0.003 * Math.max(10, this.playerSlowTime))})`;
+ ctx.fill();
+ }
+ },
+ enter() {
+ },
+ exit() { },
+ },
+ {
+ name: "antigravity",
+ cycle: 0,
+ startCycle: 420,
+ totalCycles: 600,
+ rectX: simulation.isHorizontalFlipped ? -5400 : -150, //for positioning graphics
+ do() {
+ this.cycle++
+ if (this.cycle > this.totalCycles) this.cycle = 0
+ if (this.cycle === this.startCycle) {
+ //initial push up
+ for (let i = 0, len = body.length; i < len; ++i) {
+ body[i].force.y -= 0.05 * body[i].mass
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ powerUp[i].force.y -= 0.07 * powerUp[i].mass
+ }
+ for (let i = 0, len = bullet.length; i < len; ++i) {
+ bullet[i].force.y -= 0.05 * bullet[i].mass
+ }
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ mob[i].force.y -= 0.15 * mob[i].mass
+ }
+ player.force.y -= 0.04 * player.mass
+ } else if (this.cycle > this.startCycle) { //antigravity
+ for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
+ body[i].force.y -= simulation.g * body[i].mass
+ Matter.Body.setVelocity(body[i], Vector.mult(body[i].velocity, 0.98)); //friction
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ powerUp[i].force.y -= simulation.g * powerUp[i].mass
+ }
+ // for (let i = 0, len = bullet.length; i < len; ++i) {
+ // bullet[i].force.y -= simulation.g * bullet[i].mass
+ // Matter.Body.setVelocity(bullet[i], Vector.mult(bullet[i].velocity, 0.98)); //friction
+ // }
+ // for (let i = 0, len = mob.length; i < len; ++i) {
+ // mob[i].force.y -= 0.7 * simulation.g * mob[i].mass
+ // }
+ player.force.y -= simulation.g * player.mass //g = 0.0024
+ Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.985)); //friction
+ //graphics
+ ctx.fillStyle = `rgba(0, 0, 0, ${0.03 + 0.03 * Math.random()})`;
+ ctx.fillRect(this.rectX, -1500, 5650, 1500); //cover everything
+ } else if (this.cycle > this.startCycle - 60) {
+ //graphical warning of antigravity
+ ctx.fillStyle = `rgba(0, 0, 0, ${0.2 + 0.25 * Math.random()})`;
+ ctx.fillRect(this.rectX, -25, 5650, 25); //cover floor
+ }
+ },
+ enter() { spawn.shield(me, me.position.x, me.position.y, 1); },
+ exit() { this.cycle = 0 },
},
// {
// name: "__",
- // do() {},
- // enter() {},
- // exit() {},
+ // do() { },
+ // enter() { },
+ // exit() { },
// },
]
- shuffle(me.mode); //THIS SHOULDN'T BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ shuffle(me.mode); //THIS SHOULD NOT BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
me.do = function () {
this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
if (this.health < 1) {
@@ -648,7 +755,8 @@ const spawn = {
this.damageReductionDecay();
for (let i = 0; i < this.totalModes; i++) this.mode[i].do()
}
- // this.mode[5].do() //deelete this
+ // this.mode[10].do() //comment out this
+ // console.log(this.mode[9].name)
// this.cycle++;
// this.mode[4].do()
// this.mode[7].do()
@@ -719,7 +827,7 @@ const spawn = {
}
}
Matter.Body.setDensity(me, 0.003); //normal is 0.001
- me.timeLeft = 360;
+ me.timeLeft = 300;
me.g = 0.0005; //required if using this.gravity
me.frictionAir = 0.005;
me.friction = 1;
@@ -740,6 +848,12 @@ const spawn = {
this.torque += this.spin;
this.gravity();
this.timeLimit();
+ if (this.timeLeft < 60) {
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.explodeRange, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255,255,255,0.15)`;
+ ctx.fill();
+ }
};
}
me.orbitalNoVelocity = function (who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
@@ -2502,7 +2616,7 @@ const spawn = {
spawn.hopBullet(this.position.x, this.position.y)
this.death();
}
- if (Matter.Query.collides(this, [player]).length > 0) this.isExploding = true
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) this.isExploding = true
if (this.isExploding) {
if (this.countDown-- < 0) { //explode
this.death();
@@ -2538,7 +2652,7 @@ const spawn = {
// me.isBadTarget = true;
me.isMobBullet = true;
me.showHealthBar = false;
- me.timeLeft = 1140 + Math.floor(480 * Math.random());
+ me.timeLeft = 1020 + Math.floor(480 * Math.random());
me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
me.accelMag = 0.01; //jump height
@@ -2547,7 +2661,7 @@ const spawn = {
me.friction = 1
me.frictionStatic = 1
me.restitution = 0;
- me.delay = 130 + 60 * simulation.CDScale;
+ me.delay = 120 + 60 * simulation.CDScale;
// Matter.Body.rotate(me, Math.random() * Math.PI);
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
@@ -3673,12 +3787,54 @@ const spawn = {
} else if (c < -threshold) {
this.torque -= turn;
}
- const flapArc = 0.7 //don't go past 1.57 for normal flaps
+ const flapArc = 0.7 //don't go past 1.57 for normal flaps
ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
}
+ // else { //flocking behavior (not working yet)
+ // this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
+ // this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
+ // //set direction to turn to fire
+ // if (!(simulation.cycle % this.seePlayerFreq)) {
+ // //find nearest mob and maintain a distance
+ // let nearestMob = null
+ // let nearestMobDistance = Infinity
+ // for (let i = 0; i < mob.length; i++) {
+ // const newMobDistance = Vector.magnitude(Vector.sub(this.position, mob[i].position))
+ // if (mob[i].isDropPowerUp && mob[i].alive && newMobDistance < nearestMobDistance) { //&& !mob[i].isBoss
+ // nearestMobDistance = newMobDistance
+ // nearestMob = mob[i]
+ // }
+ // }
+ // if (nearestMob) {
+ // // console.log(nearestMob)
+ // this.fireDir = Vector.normalise(Vector.sub(nearestMob.position, this.position));
+ // //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
+ // const mod = (a, n) => {
+ // return a - Math.floor(a / n) * n
+ // }
+ // const sub = Vector.sub(nearestMob.position, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
+ // const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
+ // if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
+ // }
+ // }
+ // //rotate towards fireDir
+ // const angle = this.angle + Math.PI / 2;
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ // const threshold = 0.4;
+ // const turn = 0.000025 * this.inertia
+ // if (c > threshold) {
+ // this.torque += turn;
+ // } else if (c < -threshold) {
+ // this.torque -= turn;
+ // }
+ // const flapArc = 0.7 //don't go past 1.57 for normal flaps
+ // ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ // this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
+ // this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
+ // }
};
},
beetleBoss(x, y, radius = 50) {
@@ -5237,9 +5393,7 @@ const spawn = {
me.do = function () {
this.checkStatus();
- if (Matter.Query.collides(this, [player]).length > 0) {
- this.isExploding = true
- }
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) this.isExploding = true
if (this.isExploding) {
if (this.countDown-- < 0) { //explode
diff --git a/js/tech.js b/js/tech.js
index 4792f6b..44d1103 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -237,7 +237,7 @@ const tech = {
if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage
if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.015 * m.coupling
- if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling)
+ if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling)
if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime
if (tech.isTechDebt) dmg *= tech.totalCount > 20 ? Math.pow(0.85, tech.totalCount - 20) : 4 - 0.15 * tech.totalCount // if (tech.isTechDebt) dmg *= Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount)
if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555
@@ -365,6 +365,57 @@ const tech = {
if (this.count) m.resetSkin();
}
},
+ {
+ name: "Higgs mechanism",
+ description: "+77% fire rate
while firing your position is fixed",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin && !m.isShipMode && !tech.isAlwaysFire
+ },
+ requires: "not skinned, ship mode, automatic",
+ effect() {
+ tech.isFireMoveLock = true;
+ b.setFireCD();
+ b.setFireMethod();
+ m.skin.strokeGap();
+ },
+ remove() {
+ if (tech.isFireMoveLock) {
+ tech.isFireMoveLock = false
+ b.setFireCD();
+ b.setFireMethod();
+ if (this.count) m.resetSkin();
+ }
+ }
+ },
+ {
+ name: "Hilbert space",
+ description: "+142% damage
after a collision enter an alternate reality",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isAltRealityTech: true,
+ isSkin: true,
+ allowed() {
+ return !tech.isResearchReality && !tech.isSwitchReality
+ },
+ requires: "not Ψ(t) collapse, many-worlds",
+ damage: 2.42,
+ effect() {
+ m.skin.anodize();
+ tech.damage *= this.damage
+ tech.isCollisionRealitySwitch = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isCollisionRealitySwitch = false;
+ }
+ },
{
name: "aperture",
description: "every 6 seconds your damage cycles
between -10% and +110% damage",
@@ -460,9 +511,9 @@ const tech = {
frequency: 4,
frequencyDefault: 4,
allowed() {
- return tech.isEnergyHealth
+ return tech.isEnergyHealth && !tech.isOverHeal
},
- requires: "mass-energy equivalence",
+ requires: "mass-energy equivalence, not quenching",
effect() {
powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
powerUps.heal.color = "#ff0" //"#0ae"
@@ -947,30 +998,6 @@ const tech = {
tech.isFarAwayDmg = false;
}
},
- {
- name: "Higgs mechanism",
- description: "+45% fire rate
while firing your position is fixed",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !m.isShipMode && !tech.isAlwaysFire
- },
- requires: "not ship mode, automatic",
- effect() {
- tech.isFireMoveLock = true;
- b.setFireCD();
- b.setFireMethod();
- },
- remove() {
- if (tech.isFireMoveLock) {
- tech.isFireMoveLock = false
- b.setFireCD();
- b.setFireMethod();
- }
- }
- },
{
name: "integrated armament",
link: `integrated armament`,
@@ -1278,21 +1305,21 @@ const tech = {
{
name: "collider",
descriptionFunction() {
- return `after mobs die there is a +50% chance to
collide power ups to form different power ups`
+ return `after mobs die power ups
randomly collide to form different power ups`
// return `after mobs die there is a +33% chance to convert
${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, ${powerUps.orb.research(1)}, tech, field, gun into other types`
},
- maxCount: 2,
+ maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed: () => true,
requires: "",
effect() {
- tech.collidePowerUps += 0.5
+ tech.collidePowerUps = true
},
remove() {
- tech.collidePowerUps = 0
+ tech.collidePowerUps = false
}
},
{
@@ -1316,17 +1343,53 @@ const tech = {
tech.isShieldAmmo = false;
}
},
+ {
+ name: "yield stress",
+ description: "+55% damage
to mobs at maximum health",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldMode !== 7 && tech.mobSpawnWithHealth === 0
+ },
+ requires: "not cloaking, reaction inhibitor",
+ effect() {
+ tech.isMobFullHealth = true
+ },
+ remove() {
+ tech.isMobFullHealth = false
+ }
+ },
+ {
+ name: "cascading failure",
+ description: "+222% damage
to mobs below 25% health",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.mobSpawnWithHealth > 0
+ },
+ requires: "reaction inhibitor",
+ effect() {
+ tech.isMobLowHealth = true
+ },
+ remove() {
+ tech.isMobLowHealth = false
+ }
+ },
{
name: "reaction inhibitor",
- description: "-11% maximum mob health", //health
+ description: "mobs spawn with -12% initial health",
maxCount: 3,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
- return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath
+ return !tech.isMobFullHealth
},
- requires: "", //"any mob death tech",
+ requires: "not topological defect",
effect() {
tech.mobSpawnWithHealth++
mobs.setMobSpawnHealth()
@@ -1343,7 +1406,7 @@ const tech = {
{
name: "scrap bots",
link: `scrap bots`,
- description: "after mobs die you have a +33% chance
to build scrap bots that operate for 13 seconds",
+ description: "after mobs die you have a +33% chance
to build scrap bots that operate for 15 seconds",
maxCount: 3,
count: 0,
frequency: 1,
@@ -1363,7 +1426,7 @@ const tech = {
{
name: "scrap refit",
link: `scrap refit`,
- description: "after mobs die
reset scrap bots to 13 seconds of operation",
+ description: "after mobs die
reset scrap bots to 15 seconds of operation",
maxCount: 1,
count: 0,
frequency: 3,
@@ -3108,9 +3171,9 @@ const tech = {
frequencyDefault: 1,
isHealTech: true,
allowed() {
- return true
+ return !tech.isEnergyHealth
},
- requires: "",
+ requires: "not mass-energy",
effect() {
tech.isOverHeal = true;
},
@@ -3121,7 +3184,7 @@ const tech = {
{
name: "accretion",
descriptionFunction() {
- return `${powerUps.orb.heal(1)} follow you, even between levels
spawn ${powerUps.orb.heal(5)}`
+ return `${powerUps.orb.heal(1)} follow you, even between levels
spawn ${powerUps.orb.heal(7)}`
},
// description: `${powerUps.orb.heal(1)} follow you, even between levels
spawn ${powerUps.orb.heal(5)}`,
maxCount: 1,
@@ -3136,7 +3199,7 @@ const tech = {
effect() {
tech.isHealAttract = true
powerUps.setPowerUpMode();
- 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");
+ for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal");
},
remove() {
tech.isHealAttract = false
@@ -3295,28 +3358,6 @@ const tech = {
tech.isImmortal = false;
}
},
- {
- name: "Hilbert space",
- description: "+99% damage
after a collision enter an alternate reality",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isAltRealityTech: true,
- allowed() {
- return !tech.isResearchReality && !tech.isSwitchReality
- },
- requires: "not Ψ(t) collapse, many-worlds",
- damage: 1.99,
- effect() {
- tech.damage *= this.damage
- tech.isCollisionRealitySwitch = true;
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isCollisionRealitySwitch = false;
- }
- },
{
name: "many-worlds",
// description: "each level is an alternate reality, where you
find a tech at the start of each level",
@@ -3415,7 +3456,10 @@ const tech = {
},
{
name: "perturbation theory",
- description: `if you have no ${powerUps.orb.research(1)} in your inventory
+70% fire rate`,
+ description: `if you have no ${powerUps.orb.research(1)} in your inventory
+60% fire rate`,
+ // descriptionFunction() {
+ // return `+40% damage, but -10% damage
for each ${powerUps.orb.research(1)} in your inventory (${40 - 10 * powerUps.research.count}% damage)`
+ // },
maxCount: 1,
count: 0,
frequency: 1,
@@ -3426,7 +3470,7 @@ const tech = {
requires: "no research",
effect() {
tech.isRerollHaste = true;
- tech.researchHaste = 0.3;
+ tech.researchHaste = 0.4; //+60% fire rate
b.setFireCD();
},
remove() {
@@ -3482,7 +3526,7 @@ const tech = {
{
name: "mass production",
descriptionFunction() {
- return `tech always have +3 choices to spawn
${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} or ${powerUps.orb.research(5)}`
+ return `tech always have +3 choices to spawn
${powerUps.orb.ammo(10)} ${powerUps.orb.heal(10)} or ${powerUps.orb.research(7)}`
},
// description: `tech always have +3 choices to spawn
${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} or ${powerUps.orb.research(5)}`,
maxCount: 1,
@@ -3500,7 +3544,7 @@ const tech = {
},
{
name: "research",
- description: `spawn ${powerUps.orb.research(5)}`,
+ description: `spawn ${powerUps.orb.research(7)}`,
maxCount: 1,
count: 0,
frequency: 0,
@@ -3510,13 +3554,13 @@ const tech = {
allowed() { return true },
requires: "",
effect() {
- powerUps.spawnDelay("research", 5);
+ powerUps.spawnDelay("research", 7);
},
remove() { }
},
{
name: "ammo",
- description: `spawn ${powerUps.orb.ammo(8)}`,
+ description: `spawn ${powerUps.orb.ammo(10)}`,
maxCount: 1,
count: 0,
frequency: 0,
@@ -3526,14 +3570,14 @@ const tech = {
allowed() { return true },
requires: "",
effect() {
- powerUps.spawnDelay("ammo", 8);
+ powerUps.spawnDelay("ammo", 10);
},
remove() { }
},
{
name: "heals",
descriptionFunction() {
- return `spawn ${powerUps.orb.heal(8)}`
+ return `spawn ${powerUps.orb.heal(10)}`
},
maxCount: 1,
count: 0,
@@ -3544,7 +3588,7 @@ const tech = {
allowed() { return true },
requires: "mass production",
effect() {
- powerUps.spawnDelay("heal", 8);
+ powerUps.spawnDelay("heal", 10);
},
remove() { }
},
@@ -5339,7 +5383,7 @@ const tech = {
}
},
{
- name: "phonon", //longitudinal //gravitational wave?
+ name: "phonon",
description: "waves are low frequency, high damage
expanding arcs that propagate through solids",
isGunTech: true,
maxCount: 1,
@@ -6818,7 +6862,7 @@ const tech = {
},
remove() {
tech.railChargeRate = 0.97;
- tech.harpoonDensity = 0.007
+ tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
}
},
{
@@ -6837,6 +6881,7 @@ const tech = {
ammoBonus: 9,
effect() {
tech.isRailGun = true;
+ tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
b.guns[9].chooseFireMethod()
b.guns[9].ammoPack = 5;
b.guns[9].ammo = b.guns[9].ammo * 6;
@@ -6845,6 +6890,7 @@ const tech = {
remove() {
if (tech.isRailGun) {
tech.isRailGun = false;
+ tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
b.guns[9].chooseFireMethod()
b.guns[9].ammoPack = 1.7;
b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6);
@@ -7025,21 +7071,41 @@ const tech = {
},
{
name: "induction furnace",
- description: "after using harpoon to collect a power up
+600% harpoon damage",
+ description: "after using harpoon or grapple to collect power ups
+77% harpoon or grapple damage for 8 seconds",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isRailGun
+ return ((tech.haveGunCheck("harpoon") && !tech.isRailGun) || m.fieldMode === 10) && !tech.isHarpoonFullHealth
},
- requires: "harpoon, not railgun",
+ requires: "harpoon, grappling hook, not railgun, brittle",
effect() {
tech.isHarpoonPowerUp = true
},
remove() {
tech.isHarpoonPowerUp = false
+ tech.harpoonPowerUpCycle = 0
+ }
+ },
+ {
+ name: "brittle",
+ description: "+88% harpoon and grapple damage
to mobs at maximum health",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("harpoon") || m.fieldMode === 10) && !tech.isHarpoonPowerUp
+ },
+ requires: "harpoon, grappling hook, not induction furnace",
+ effect() {
+ tech.isHarpoonFullHealth = true
+ },
+ remove() {
+ tech.isHarpoonFullHealth = false
}
},
{
@@ -7437,7 +7503,7 @@ const tech = {
//**************************************************
{
name: "spherical harmonics",
- description: "+50% standing wave deflection efficiency
shield deflection radius maintains it's maximum range", //standing wave oscillates in a 3rd dimension
+ description: "+50% standing wave deflection efficiency
shield deflection radius holds it's max range", //standing wave oscillates in a 3rd dimension
isFieldTech: true,
maxCount: 9,
count: 0,
@@ -8133,7 +8199,7 @@ const tech = {
},
{
name: "degenerate matter",
- description: "if your field is active
+85% defense",
+ description: "if your field is active
+88% defense",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -8400,7 +8466,7 @@ const tech = {
{
name: "no-cloning theorem",
// descriptionFunction() { return `+45% chance to duplicate spawned power ups
after a mob dies –2% duplication (${tech.duplicationChance()})` },
- description: `+45% chance to duplicate spawned power ups
after a mob dies –2% duplication`,
+ description: `+40% chance to duplicate spawned power ups
after a mob dies –1% duplication`,
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -8411,7 +8477,7 @@ const tech = {
},
requires: "cloaking, time dilation",
effect() {
- tech.cloakDuplication = 0.45
+ tech.cloakDuplication = 0.4
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
},
@@ -8423,7 +8489,7 @@ const tech = {
{
name: "metamaterial absorber", //quantum eraser
descriptionFunction() {
- return `for each mob left alive after you exit a level
there is a 17% chance to spawn a random power up`
+ return `for each mob left alive after you exit a level
there is a 22% chance to spawn a random power up`
},
// descriptionFunction() {
// return `for each mob left alive after you exit a level
`
@@ -8447,7 +8513,7 @@ const tech = {
{
name: "symbiosis",
descriptionFunction() {
- return `after a boss dies spawn ${powerUps.orb.research(3)}${powerUps.orb.heal(3)} and a tech
after a mob dies –0.5 maximum ${tech.isEnergyHealth ? "energy" : "health"}`
+ return `after a boss dies spawn ${powerUps.orb.research(4)}${powerUps.orb.heal(3)} and a tech
after a mob dies –0.5 maximum ${tech.isEnergyHealth ? "energy" : "health"}`
},
isFieldTech: true,
maxCount: 1,
@@ -8491,7 +8557,7 @@ const tech = {
{
name: "patch",
link: `patch`,
- description: "after cloaking recover 75% of your
last health loss using that much energy",
+ description: "after cloaking recover 75%
of your last health lost",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -8528,6 +8594,25 @@ const tech = {
tech.isCloakStun = false;
}
},
+ {
+ name: "topological defect",
+ description: "+88% damage
to mobs at maximum health",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (m.fieldMode === 8 || m.fieldMode === 7) && tech.mobSpawnWithHealth === 0 && !tech.isMobFullHealth
+ },
+ requires: "cloaking, pilot wave, not reaction inhibitor, yield stress",
+ effect() {
+ tech.isMobFullHealthCloak = true
+ },
+ remove() {
+ tech.isMobFullHealthCloak = false
+ }
+ },
// {
// name: "ambush",
// description: "metamaterial cloaking field damage effect
is increased from 333% to 555%",
@@ -9192,6 +9277,23 @@ const tech = {
},
remove() { }
},
+ {
+ name: "planned obsolescence",
+ description: "build 100 scrap bots
bots might last for 30 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ for (let i = 0; i < 100; i++) {
+ b.randomBot(m.pos, false)
+ bullet[bullet.length - 1].endCycle = simulation.cycle + 800 + 1000 * Math.random() //15 seconds
+ }
+ },
+ remove() { }
+ },
// {
// name: "synchrotron",
// descriptionFunction() {
@@ -11921,4 +12023,9 @@ const tech = {
isHookExplosion: null,
isHarpoonDefense: null,
isReel: null,
+ harpoonPowerUpCycle: null,
+ isHarpoonFullHealth: null,
+ isMobFullHealth: null,
+ isMobFullHealthCloak: null,
+ isMobLowHealth: null
}
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index 0ac580b..5351fe1 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,24 +1,64 @@
******************************************************** NEXT PATCH **************************************************
-why mode is now 20% easier, but still 25% harder than hard mode
- easy:1, normal:2, hard:4, why:6->5
+mob health tech
+ tech: cascading failure - +222% damage to mobs below 25% health
+ tech: yield stress - +55% damage to mobs at maximum health
+ cloaking tech: topological defect - +88% damage to mobs at maximum health
+ harpoon tech: brittle - +88% harpoon/grapple damage to mobs at maximum health
-new community map unchartedCave by 3xionDev!
+cloaking buffs
+ 50->66% defense while cloaked
+ recloak 0.25s faster
+ simplified cloaking field graphics
+ boson composite drains much less energy while moving through mobs and shields
+ fixed bug where mines and egg mobs were colliding with player while intangible
+ patch no longer drains energy when you heal on cloaking
+ metamaterial absorber gets 17->22% chance to spawn a power up for each mob alive
+ no-cloning theorem changes to 45->40% duplication and 2->1% duplication loss on killing a mob
-Newtons 1st law 66->88% defense when moving fast
-Newtons 2nd law 66->88% damage when moving fast
-CIWS energy 20->18 per shot
-rupture disables reel and tokamak
+finalBoss phases:
+ new: slow zone, antigravity pulse
+ nerfed: laser, black hole, orbitals
+ buffed: oscillation, mobs
+ improved graphics: boulder
+Hilbert space has a skin. 99->142% damage increase, but randomize tech after taking damage
+Higgs mechanism has a skin. +45->77% fire rate, player can't move while firing
+induction furnace gives +77% harpoon/grapple damage for 8 seconds after picking up a power up
+collider 50->100% chance to combine and randomize power ups
+quenching gives more bonus max health at high difficulty level (maybe around 30% more health)
+accretion gives 5->7 heal power ups
+dynamo bots follow player much closer when you have many of them
+scrap-bots don't follow the player as accurately or as quickly
+ scrap bot duration 13->15 seconds
+JUNK tech: planned obsolescence - make 100 scrap bots that last for about 30 seconds
+
+community map dojo by werid_pusheen
+ fixed by Cornbread 2100
+
+hard mode gets 1 less heal at the start
+hard and why difficulty don't begin with starter mobs
+hopBullet mobs last 2 seconds less time
+adjusted button heights on train station level to be consistently the same height
*********************************************************** TODO *****************************************************
+hexagon head skin
+ maybe give defense
-scrap bots don't follow player
- adjust spawn rates to balance
+foam tech: increase size of foam and increase duration, but drop speed down, so they come to a stop and just hang
+ allow them to harm player?
+ this is probably just too annoying
+
+make a flutter variant
+ just move the wings to the back?
+ slow flap, and acceleration that increases when the flap occurs, like swimming
make grappling hook of different shapes
+ shapes
+ longer
+ circular with spikes
indicate tech upgrades?
rupture, reel, tokamak
do this in draw or in verticies?
@@ -31,8 +71,6 @@ grappling hook field
field tech ideas
Buoyancy - aerostat, but for defense: +70% defense while off the ground
too similar to degenerate matter
- generate ___ after destroying blocks
- energy, drones, iceIX, explosion, nails, junk bots?
tech - killing a mob heals for the last damage you took
disable cloaking heal? maybe you don't need to disable, just don't heal twice
@@ -43,9 +81,6 @@ on sucker mob death trigger radiation damage AoE and a graphic (Hawking radiati
tech prismatic laser - cycles between different laser colors every 1-2 seconds
-make phonon the default wave gun type and make a tech to switch to the normal wave beam
- nerf phonon, buff wave
-
sword slash for plasma torch (giving up on this for now, had trouble making graphics look good)
activates when mouse is close to player
gradual activation
@@ -83,12 +118,6 @@ use cross product rotation for other mobs?
super-bot: fires super balls
-tech - only allow 1,2 turrets at time. spawning a new mine removes the oldest mine
- turrets never run out of ammo
- or turrets automatically use one of your mine ammos when they run out?
- good with multi gun builds
- conflict with booby trap?
-
tech: after a needle hits a mobs
the needle splits into 3 needles?
reset your fire CD?
@@ -183,32 +212,6 @@ hookBoss fires a hook that pulls player towards it
player targeted unless cloaking
also add effect to finalBoss
-finalBoss
- add synergies between modes:
- new modes:
- something that needs to be killed quickly
- if you don't kill it boss gets a shield
- rotating quadrant immunity shield, can't take damage from that quadrant
- maybe also attack player near that quadrant
- but how to tell the angle of incoming damage
- maybe a physics body like the shield but it only covers 1/3 of mob?
- falling object warps to ceiling after hitting floor
- doesn't end, player needs to kill it
- slowly grows?
- slow effect zones
- random placement or place over player or both!
- draw white dot and an outline of area of effect
- expanding circle stroke, freeze effect triggers when stroke circle hits fill circle
- after 1-2 seconds freeze player if in the zone
- also freeze mobs
- effect that makes player have to be close to boss
- hook that tries to yank the player into hitting finalBoss
- does damage
- pulls player into center
- counter with wormhole, negative mass
- player targeted unless cloaking
-
-
mob status effect - emit - mobs fire lasers for a few seconds
tech: phosphorescence - mobs emit after being hit with laser beams
@@ -226,7 +229,7 @@ tech increase max energy and energy to 5000, but you can no longer regen energy
it would be nice if there was incentive to go slow when choosing tech so n-gon is more relaxing
add some css based visual effects for opening up a tech,gun,field
-make a new coupling effect for perfect diamagnetism or standing wave
+make a new coupling effect for perfect diamagnetism
make a faster smaller version of cell boss that also has map collisions
@@ -237,22 +240,11 @@ JUNK tech description that changes similar to cards in inscription
that changes based on mouse position
can you tell if mouse is over card?
-tech - buff MACHO range, effect, move speed?
-while you are inside MACHO it will damage mobs?
-
PWA?
https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps
https://codeburst.io/how-to-easily-turn-your-static-website-to-a-progressive-web-app-pwa-b0af08da9693
https://github.com/landgreen/n-gon/pull/32/files
-bug blocks and power ups falling through map
- always foam gun (4-5 times)
- might be about tech pressure vessel
- happens rarely, doesn't repeat
- only occurs for 3 people so far
- normally after level 6
- occurred once on the first level, didn't fire gun and was able to walk through a body
-
Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when relay swicth/flip flop is off, ammo powerups remain ammo powerups
or toggle other power ups
health/ammo
@@ -260,9 +252,6 @@ Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when rel
JUNK: what the golf?
trying to throw a block throws you instead
-tech for lens - you can only fire through the lens
- and some buff? damage or energy?
-
complete blowSuckBoss... or don't
tech: laser reflections increase damage
@@ -272,18 +261,6 @@ JUNK tech different effects based on night or day
Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back
-coupling
- put coupling description as 4th line on field description
- raw text no function call
- no need for coupling description in power ups, pause
- negative coupling?
- wouldn't work for iceIX
-coupling tech
- names: strongly coupled, Vibronic coupling, NMR coupling
- tech: +x% field coupling, your field changes randomly every y seconds
- tech: coupling starts at 200%, but decays when the field is in use, coupling recharges when the field is not in use
- some fields aren't used much (that's ok?)
-
tech give laser mines more lasers (3->4? 5?)
rewindBoss: after hitting 1/5 damage thresholds the boss rewinds back in time to where it was a few seconds ago
@@ -307,11 +284,6 @@ immediately fire all of your ammo
after taking damage explode while invulnerable
scale explosion radius with damage
-quantum immortality: send you to a new tab after you die with a random load out
- basically everything is the same as it is now, but you switch tabs
-
-Tech: Tech/guns/fields can no longer be duplicated. Duplication applies twice
-
tech: get sent to a new tab that closes in 3 minutes
in the new tab you play reactor
if you die in reactor you die in game, if you win you get 2-3 tech in the original game?
@@ -319,31 +291,8 @@ tech: get sent to a new tab that closes in 3 minutes
count guns, field, tech and give random stuff on new tab
i-frame instead of tab?
-reduce the amount of research and nerf anti randomization tech
- increase possible synergies that go nuts
-
-tech expansion: field coupling also expands each fields in different ways
- how to make the description work
- change description based on your current field?
- perfect diamagnetism moves forward when you hold down the shield
- it's great, but maybe annoying?
- maybe only with crouch?
- perfect diamagnetism just replace or increase Messier effect
- time dilation drains 1/2 as much energy when paused
- grow plasma torch as you hold it down
- negative mass effects much more space
- needs more benefit?
- reduces the cloaking vision effect?
- needs more benefit?
-
tech: missiles explode a 2nd time after 1/2 a second (with a slightly different position determined by original velocity)
-The tech that makes blocks that fall into a wormhole give energy should scale with block size, with the same formula as tokomak
-
-junk suggestion: useless machine - ejects itself and removes itself from the item pool
-
-
-
seed isn't working right from shared URL
mob mechanics
@@ -359,8 +308,6 @@ mob mechanics
spawns new nodes
draws connections as quad lines
-tech: You can place an extra perfect diamagnatism field on the map
-
standing wave no longer pushes mobs away, but it can do damage to mobs caught in area effect
Standing wave harmonics no longer deflects, but instead discharges excess energy as lightning toward nearby enemies
negative mass field does damage to mobs inside field
@@ -1157,6 +1104,7 @@ possible names for tech
Josephson junction - superconducting junction
Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity
perturbation
+ Unruh effect - accelerating makes heat/thermal particles
******************************************************** CARS IMAGES ********************************************************