diff --git a/img/bulk modulus.webp b/img/bulk modulus.webp
deleted file mode 100644
index 736fe5b..0000000
Binary files a/img/bulk modulus.webp and /dev/null differ
diff --git a/img/field/grappling hook.webp b/img/field/grappling hook.webp
new file mode 100644
index 0000000..1b13826
Binary files /dev/null and b/img/field/grappling hook.webp differ
diff --git a/img/grappling hook.webp b/img/grappling hook.webp
deleted file mode 100644
index 4b54ade..0000000
Binary files a/img/grappling hook.webp and /dev/null differ
diff --git a/js/bullet.js b/js/bullet.js
index fae5e81..b672669 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -1460,324 +1460,369 @@ const b = {
// Composite.add(engine.world, bullet[me]); //add bullet to world
// },
- grapple(where, angle = m.angle, harpoonSize = 1) {
+ grapple(where, angle = m.angle) {
const me = bullet.length;
- const returnRadius = 100 * Math.sqrt(harpoonSize)
+ const returnRadius = 100
bullet[me] = Bodies.fromVertices(where.x, where.y, [{
- x: -50 * harpoonSize,
- y: 2 * harpoonSize,
+ x: -40,
+ y: 2,
index: 0,
isInternal: false
}, {
- x: -50 * harpoonSize,
- y: -2 * harpoonSize,
+ x: -40,
+ y: -2,
index: 1,
isInternal: false
}, {
- x: 45 * harpoonSize,
- y: -3 * harpoonSize,
+ x: 37,
+ y: -2,
index: 2,
isInternal: false
}, {
- x: 50 * harpoonSize,
- y: 0,
+ x: 40,
+ y: -1,
index: 3,
isInternal: false
}, {
- x: 45 * harpoonSize,
- y: 3 * harpoonSize,
+ x: 34,
+ y: 5,
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 = 3 * this.mass; i < len; i++) {
- const radius = 5 + 8 * Math.random()
- const velocity = {
- x: Math.max(0.5, 2 - radius * 0.1),
- y: 0
+ }],
+
+ // [{
+ // x: -10,
+ // y: 2,
+ // index: 0,
+ // isInternal: false
+ // }, {
+ // x: -10,
+ // y: -2,
+ // index: 1,
+ // isInternal: false
+ // }, {
+ // x: 35,
+ // y: -3,
+ // index: 2,
+ // isInternal: false
+ // }, {
+ // x: 37,
+ // y: -2,
+ // index: 3,
+ // isInternal: false
+ // }, {
+ // x: 40,
+ // y: 0,
+ // index: 4,
+ // isInternal: false
+ // }, {
+ // x: 37,
+ // y: 2,
+ // index: 5,
+ // isInternal: false
+ // }, {
+ // x: 35,
+ // y: 3,
+ // index: 6,
+ // isInternal: false
+ // }],
+ {
+ angle: angle,
+ friction: 1,
+ frictionAir: 0.4,
+ thrustMag: 0.13,
+ dmg: 6, //damage done in addition to the damage from momentum
+ classType: "bullet",
+ endCycle: simulation.cycle + 70,
+ isSlowPull: false,
+ 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: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
+ drain: 0.001,
+ 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 = 3 * 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;
+ // }
+ if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
+ this.retract()
+ },
+ 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()
}
- 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
- }
- }
+ },
+ draw() {
+ const where = {
+ x: m.pos.x + 30 * Math.cos(m.angle),
+ y: m.pos.y + 30 * Math.sin(m.angle)
}
- }
- },
- 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;
- // }
+ 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);
- // } else {
- //return to player
+ 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();
+ },
+ retract() {
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
+ this.collisionFilter.mask = 0//cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
+ //recoil on pulling grapple back
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
- });
+ },
+ returnToPlayer() {
+ if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
+ if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
+ this.endCycle = 0;
+ //recoil on catching grapple
+ 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
-
- //need to scale the friction differently based on distance?
- // if (dist > 500) {
- 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;
- // }
- // }
- }
- }
+ } 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();
+ },
+ destroyBlocks() {
+ const blocks = Matter.Query.collides(this, body)
+ if (blocks.length && !blocks[0].bodyA.isNotHoldable) {
+ if (blocks[0].bodyA.mass > 2.5) this.retract()
+ const block = blocks[0].bodyA.vertices
+ Composite.remove(engine.world, blocks[0].bodyA)
+ body.splice(body.indexOf(blocks[0].bodyA), 1)
+ //animate the block fading away
+ simulation.ephemera.push({
+ name: "blockFadeOut",
+ count: 25, //cycles before it self removes
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+ ctx.beginPath();
+ ctx.moveTo(block[0].x, block[0].y);
+ for (let j = 1; j < block.length; j++) ctx.lineTo(block[j].x, block[j].y);
+ ctx.lineTo(block[0].x, block[0].y);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = `rgba(0,0,0,${this.count / 25})`
+ ctx.stroke();
+ },
+ })
+ }
+ },
+ 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 {
+ 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
+ this.retract()
+ break //just pull 1 power up if possible
}
- 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()
- },
- });
+ m.grabPowerUp();
+ },
+ do() {
+ if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
+ if (input.field) { //&& !Matter.Query.collides(this, body).length
+ this.destroyBlocks()
+ this.grabPowerUp()
+ // if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down field, force retraction
+ // this.endCycle = simulation.cycle + 30
+ // // 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.01) 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.retract()
+ // }
+ }
+ //grappling hook
+ if (input.field && 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 = () => {
+ if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
+ // if (this.caughtPowerUp) {
+ // Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
+ // Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
+ // }
+ this.grabPowerUp()
+
+ //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.field) {
+ // m.fireCDcycle = m.cycle + 30; // cool down if out of energy
+ // m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
+ // if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
+ this.endCycle = simulation.cycle + 10
+ if (input.down) { //down
+ this.isSlowPull = true
+ dist = 0
+ player.force.y += 2.5 * player.mass * simulation.g; //adjust this to control fall rate while hooked and pressing down
+ } else if (input.up) {
+ this.isSlowPull = false
+ }
+ if (m.energy < this.drain) this.isSlowPull = true
+
+ // pulling friction that allowed a slight swinging, but has high linear pull at short dist
+ const drag = 1 - 30 / Math.min(Math.max(100, dist), 700) - 0.1 * (player.speed > 70)
+ // console.log(player.speed)
+ Matter.Body.setVelocity(player, { x: player.velocity.x * drag, y: player.velocity.y * drag });
+ const pullScale = 0.0004
+ const pull = Vector.mult(Vector.normalise(sub), pullScale * Math.min(Math.max(15, dist), this.isSlowPull ? 70 : 200))
+ //original pulling force with high friction and very linear pull
+ // Matter.Body.setVelocity(player, { x: player.velocity.x * 0.85, y: player.velocity.y * 0.85 });
+ // const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), this.isSlowPull ? 100 : 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 (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
+ // if (m.fieldCDcycle < m.cycle + 120) m.fieldCDcycle = m.cycle + 120
+
+ // //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.retract()
+ // 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
},
// grapple(where, angle = m.angle, harpoonSize = 1) {
@@ -3178,20 +3223,24 @@ const b = {
y: 100 * (Math.random() - 0.5)
},
beforeDmg(who) {
- if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
- setTimeout(() => {
- if (!who.alive) {
- for (let i = 0; i < 3; i++) { //spawn 3 more
- b.worm(this.position)
- bullet[bullet.length - 1].endCycle = Math.min(simulation.cycle + Math.floor(420 * tech.bulletsLastLonger), this.endCycle + 180 + Math.floor(60 * Math.random())) //simulation.cycle + Math.floor(420 * tech.bulletsLastLonger)
- }
- }
- this.endCycle = 0; //bullet ends cycle after doing damage
- }, 1);
+ if (who.isInvulnerable) {
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.1));
} else {
- this.endCycle = 0; //bullet ends cycle after doing damage
+ if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
+ setTimeout(() => {
+ if (!who.alive) {
+ for (let i = 0; i < 3; i++) { //spawn 3 more
+ b.worm(this.position)
+ bullet[bullet.length - 1].endCycle = Math.min(simulation.cycle + Math.floor(420 * tech.bulletsLastLonger), this.endCycle + 180 + Math.floor(60 * Math.random())) //simulation.cycle + Math.floor(420 * tech.bulletsLastLonger)
+ }
+ }
+ this.endCycle = 0; //bullet ends cycle after doing damage
+ }, 1);
+ } else {
+ this.endCycle = 0; //bullet ends cycle after doing damage
+ }
+ if (this.isFreeze) mobs.statusSlow(who, 90)
}
- if (this.isFreeze) mobs.statusSlow(who, 90)
},
onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
@@ -3295,8 +3344,10 @@ const b = {
y: 100 * (Math.random() - 0.5)
},
beforeDmg(who) {
- this.endCycle = 0; //bullet ends cycle after doing damage
- if (this.isFreeze) mobs.statusSlow(who, 90)
+ if (!who.isInvulnerable) {
+ this.endCycle = 0; //bullet ends cycle after doing damage
+ if (this.isFreeze) mobs.statusSlow(who, 90)
+ }
},
onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
@@ -3304,7 +3355,7 @@ const b = {
if (m.health > m.maxHealth) m.health = m.maxHealth;
m.displayHealth();
}
- console.log(this.dmg)
+ // console.log(this.dmg)
},
do() {
if (this.lockedOn && this.lockedOn.alive) {
@@ -3425,13 +3476,15 @@ const b = {
minDmgSpeed: 0,
lockedOn: null,
beforeDmg(who) {
- if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
- setTimeout(() => {
- if (!who.alive) m.energy += tech.iceEnergy * 0.8
- }, 10);
+ if (!who.isInvulnerable) {
+ if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
+ setTimeout(() => {
+ if (!who.alive) m.energy += tech.iceEnergy * 0.8
+ }, 10);
+ }
+ mobs.statusSlow(who, tech.iceIXFreezeTime)
+ this.endCycle = simulation.cycle
}
- mobs.statusSlow(who, tech.iceIXFreezeTime)
- this.endCycle = simulation.cycle
// if (tech.isHeavyWater) mobs.statusDoT(who, 0.15, 300)
},
onEnd() { },
@@ -3507,27 +3560,29 @@ const b = {
},
beforeDmg(who) {
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target
- this.endCycle -= 130
this.cd = simulation.cycle + this.delay;
- if (tech.isSporeFreeze) mobs.statusSlow(who, 90)
- if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
- setTimeout(() => {
- if (!who.alive) {
- for (let i = 0; i < 2; i++) { //spawn 2 more
- const speed = 10 + 5 * Math.random()
- const angle = 2 * Math.PI * Math.random()
- b.flea(this.position, {
- x: speed * Math.cos(angle),
- y: speed * Math.sin(angle)
- })
+ if (!who.isInvulnerable) {
+ this.endCycle -= 130
+ if (tech.isSporeFreeze) mobs.statusSlow(who, 90)
+ if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
+ setTimeout(() => {
+ if (!who.alive) {
+ for (let i = 0; i < 2; i++) { //spawn 2 more
+ const speed = 10 + 5 * Math.random()
+ const angle = 2 * Math.PI * Math.random()
+ b.flea(this.position, {
+ x: speed * Math.cos(angle),
+ y: speed * Math.sin(angle)
+ })
+ }
}
- }
- this.endCycle = 0;
- }, 1);
+ this.endCycle = 0;
+ }, 1);
+ }
+ setTimeout(() => {
+ this.dmg = 0
+ })
}
- setTimeout(() => {
- this.dmg = 0
- })
},
onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
@@ -3659,27 +3714,31 @@ const b = {
deathCycles: 110 + RADIUS * 5,
isImproved: false,
beforeDmg(who) {
- if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) {
- const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0)
- b.explosion(this.position, max * 0.1 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end
- if (tech.isForeverDrones) {
- this.endCycle = 0
- b.drone({
- x: m.pos.x + 30 * (Math.random() - 0.5),
- y: m.pos.y + 30 * (Math.random() - 0.5)
- }, 5)
- bullet[bullet.length - 1].endCycle = Infinity
- } else {
- this.endCycle -= max
- }
- } else {
+ if (who.isInvulnerable) {
//move away from target after hitting
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20)
Matter.Body.setVelocity(this, { x: unit.x, y: unit.y });
this.lockedOn = null
- if (this.endCycle > simulation.cycle + this.deathCycles) {
- this.endCycle -= 60
- if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles
+ } else {
+ if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) {
+ const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0)
+ b.explosion(this.position, max * 0.1 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end
+ if (tech.isForeverDrones) {
+ this.endCycle = 0
+ b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ } else {
+ this.endCycle -= max
+ }
+ } else {
+ //move away from target after hitting
+ const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20)
+ Matter.Body.setVelocity(this, { x: unit.x, y: unit.y });
+ this.lockedOn = null
+ if (this.endCycle > simulation.cycle + this.deathCycles) {
+ this.endCycle -= 60
+ if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles
+ }
}
}
},
@@ -4193,28 +4252,39 @@ const b = {
};
}
bullet[me].beforeDmg = function (who) {
- if (tech.oneSuperBall) mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds)
- if (tech.isFoamBall) {
- for (let i = 0, len = 5 * 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 (!who.isInvulnerable) {
+ if (tech.oneSuperBall) mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds)
+ if (tech.isFoamBall) {
+ for (let i = 0, len = 5 * 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
}
- this.endCycle = 0
- }
- if (tech.isIncendiary) {
- b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end
- this.endCycle = 0
- } else if (tech.isSuperBounce) {
- const cycle = () => {
- Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage
- this.endCycle = simulation.cycle + Math.floor(300 + 90 * Math.random()); //reset to full duration of time
- Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(this.velocity), 60)); //reset to high velocity
+ if (tech.isIncendiary) {
+ b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end
+ this.endCycle = 0
+ } else if (tech.isSuperBounce) {
+ const cycle = () => {
+ Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage
+ this.endCycle = simulation.cycle + Math.floor(300 + 90 * Math.random()); //reset to full duration of time
+ Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(this.velocity), 60)); //reset to high velocity
+
+ let count = 5
+ const wait = () => {
+ count--
+ if (count > 0) requestAnimationFrame(wait);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: radius,
+ color: 'rgba(255, 0, 0, 0.33)',
+ time: 8
+ });
+ }
+ requestAnimationFrame(wait);
- let count = 5
- const wait = () => {
- count--
- if (count > 0) requestAnimationFrame(wait);
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
@@ -4223,17 +4293,8 @@ const b = {
time: 8
});
}
- requestAnimationFrame(wait);
-
- simulation.drawList.push({ //add dmg to draw queue
- x: this.position.x,
- y: this.position.y,
- radius: radius,
- color: 'rgba(255, 0, 0, 0.33)',
- time: 8
- });
+ requestAnimationFrame(cycle);
}
- requestAnimationFrame(cycle);
}
};
},
@@ -5394,7 +5455,7 @@ const b = {
cd: 0,
fireCount: 0,
fireLimit: 5 + 2 * tech.isFoamBotUpgrade,
- delay: Math.floor((150 + (tech.isFoamBotUpgrade ? 0 : 250)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * 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
endCycle: Infinity,
@@ -7717,7 +7778,7 @@ const b = {
return `spray bubbly foam that sticks to mobs
slows mobs and does damage over time
${this.ammoPack.toFixed(0)} bubbles per ${powerUps.orb.ammo()}`
},
ammo: 0,
- ammoPack: 24,
+ ammoPack: 28,
have: false,
charge: 0,
isDischarge: false,
@@ -7842,9 +7903,9 @@ const b = {
if (tech.isRailGun) {
this.do = this.railDo
this.fire = this.railFire
- } else if (tech.isGrapple) {
- this.do = () => { }
- this.fire = this.grappleFire
+ // } else if (tech.isGrapple) {
+ // this.do = () => { }
+ // this.fire = this.grappleFire
} else {
this.do = () => { }
this.fire = this.harpoonFire
@@ -8054,36 +8115,36 @@ const b = {
m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
this.charge += 0.00001
},
- grappleFire() {
- const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (m.crouch ? 0.7 : 1)
- const where = {
- x: m.pos.x + harpoonSize * 40 * Math.cos(m.angle),
- y: m.pos.y + harpoonSize * 40 * Math.sin(m.angle)
- }
- const num = Math.min(this.ammo, tech.extraHarpoons + 1)
- if (!m.crouch && num > 1) { //multiple harpoons
- const SPREAD = 0.06
- let angle = m.angle - SPREAD * num / 2;
- for (let i = 0; i < num; i++) {
- if (this.ammo > 0) {
- this.ammo--
- b.grapple(where, angle, true, harpoonSize)
- angle += SPREAD
- }
- }
- this.ammo++ //make up for the ammo used up in fire()
- simulation.updateGunHUD();
- m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
- // } else if (m.crouch) {
- // b.harpoon(where, null, m.angle, harpoonSize, false, 70)
- } else {
- if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1
- b.grapple(where, m.angle, harpoonSize)
- }
- // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
- m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
+ // grappleFire() {
+ // const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (m.crouch ? 0.7 : 1)
+ // const where = {
+ // x: m.pos.x + harpoonSize * 40 * Math.cos(m.angle),
+ // y: m.pos.y + harpoonSize * 40 * Math.sin(m.angle)
+ // }
+ // const num = Math.min(this.ammo, tech.extraHarpoons + 1)
+ // if (!m.crouch && num > 1) { //multiple harpoons
+ // const SPREAD = 0.06
+ // let angle = m.angle - SPREAD * num / 2;
+ // for (let i = 0; i < num; i++) {
+ // if (this.ammo > 0) {
+ // this.ammo--
+ // b.grapple(where, angle, true, harpoonSize)
+ // angle += SPREAD
+ // }
+ // }
+ // this.ammo++ //make up for the ammo used up in fire()
+ // simulation.updateGunHUD();
+ // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
+ // // } else if (m.crouch) {
+ // // b.harpoon(where, null, m.angle, harpoonSize, false, 70)
+ // } else {
+ // if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1
+ // b.grapple(where, m.angle, harpoonSize)
+ // }
+ // // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
+ // m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
- },
+ // },
harpoonFire() {
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
diff --git a/js/level.js b/js/level.js
index e5e2c2d..3e00aba 100644
--- a/js/level.js
+++ b/js/level.js
@@ -28,17 +28,17 @@ const level = {
// m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100
// m.couplingChange(10)
- // m.setField("wormhole") //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
+ // 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.energy = 0
// simulation.molecularMode = 2
// m.damage(0.1);
// 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("foam") //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("electrostatic induction")
- // for (let i = 0; i < 1; ++i) tech.giveTech("enthalpy")
- // for (let i = 0; i < 10; ++i) tech.giveTech("quasiparticles")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("grappling hook")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("superdeterminism")
// for (let i = 0; i < 1; ++i) tech.giveTech("fine-structure constant")
// for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade")
// requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") });
@@ -49,11 +49,11 @@ const level = {
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
- // level.biohazard();
+ // level.testing();
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
// for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500)
// for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500)
- // spawn.suckerBoss(1900, -500, 25)
+ // spawn.beetleBoss(1900, -500, 25)
// spawn.slasher2(2000, -1150)
// spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color)
// for (let i = 0; i < 20; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random())
@@ -239,6 +239,10 @@ const level = {
//
m.field.description = "${m.fieldUpgrades[m.fieldMode].description}"
// `, 1200);
},
+ announceMobTypes() {
+ simulation.makeTextLog(`spawn.${spawn.pickList[0]}(x,y)`)
+ simulation.makeTextLog(`spawn.${spawn.pickList[1]}(x,y)`)
+ },
disableExit: false,
nextLevel() {
if (!level.disableExit) {
@@ -1874,6 +1878,7 @@ const level = {
//******************************************************************************************************************
//******************************************************************************************************************
template() {
+ // level.announceMobTypes()
simulation.enableConstructMode()
level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 1500;
@@ -2375,9 +2380,6 @@ const level = {
ctx.fillStyle = "rgba(68, 68, 68,0.95)"
ctx.fillRect(2030, 0, 150, 1800);
};
-
-
-
level.setPosToSpawn(460, -100); //normal spawn
// level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left
level.exit.x = 2800;
@@ -3451,6 +3453,7 @@ const level = {
simulation.draw.drawMapPath = simulation.draw.drawMapSight
},
reservoir() {
+ level.announceMobTypes()
level.exit.x = 1700;
level.exit.y = -4510;
spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
@@ -3966,6 +3969,7 @@ const level = {
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
factory() {
+ level.announceMobTypes()
// simulation.enableConstructMode() //remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// level.difficultyIncrease(10 * 4) //30 is near max on hard //60 is near max on why
@@ -4249,6 +4253,7 @@ const level = {
powerUps.spawn(5200, -1300, "ammo");
},
labs() {
+ level.announceMobTypes()
level.isProcedural = true //used in generating text for the level builder
level.defaultZoom = 1700
simulation.zoomTransition(level.defaultZoom)
@@ -5347,6 +5352,7 @@ const level = {
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
pavilion() {
+ level.announceMobTypes()
level.isEndlessFall = true;
const vanish = []
level.exit.x = -850;
@@ -5499,6 +5505,7 @@ const level = {
}
},
testChamber() {
+ level.announceMobTypes()
level.setPosToSpawn(0, -50); //lower start
level.exit.y = level.enter.y - 550;
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
@@ -5757,6 +5764,7 @@ const level = {
},
lock() {
+ level.announceMobTypes()
level.setPosToSpawn(0, -65); //lower start
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.y = 2010;
@@ -6006,6 +6014,7 @@ const level = {
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
sewers() {
+ level.announceMobTypes()
const button1 = level.button(6600, 2675)
// const hazard = level.hazard(4550, 2750, 4550, 150)
const hazard = level.hazard(simulation.isHorizontalFlipped ? -4550 - 4550 : 4550, 2750, 4550, 150)
@@ -6196,6 +6205,7 @@ const level = {
},
satellite() {
+ level.announceMobTypes()
level.isEndlessFall = true;
const boost1 = level.boost(5825, 235, 1400)
const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 }
@@ -6372,6 +6382,7 @@ const level = {
}
},
rooftops() {
+ level.announceMobTypes()
level.isEndlessFall = true;
// level.fallPosition = { x: 5000, y:-4000}
const elevator = level.elevator(1450, -990, 235, 45, -2000)
@@ -6560,6 +6571,7 @@ const level = {
}
},
aerie() {
+ level.announceMobTypes()
level.isEndlessFall = true;
const boost1 = level.boost(-425, 100, 1400)
const boost2 = level.boost(5350, 275, 2850);
@@ -6789,6 +6801,7 @@ const level = {
}
},
skyscrapers() {
+ level.announceMobTypes()
level.isEndlessFall = true;
const boost1 = level.boost(475, 0, 1300)
const boost2 = level.boost(4450, 0, 1300);
@@ -6927,6 +6940,7 @@ const level = {
}
},
highrise() {
+ level.announceMobTypes()
level.isEndlessFall = true;
const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, {
up: 0.01,
@@ -7212,6 +7226,7 @@ const level = {
}
},
warehouse() {
+ level.announceMobTypes()
level.isEndlessFall = true;
level.custom = () => {
ctx.fillStyle = "#444" //light fixtures
@@ -7531,6 +7546,7 @@ const level = {
}
},
office() {
+ level.announceMobTypes()
let button, door
let isReverse = false
if (Math.random() < 0.75) { //normal direction start in top left
diff --git a/js/player.js b/js/player.js
index 92d7dcd..f269256 100644
--- a/js/player.js
+++ b/js/player.js
@@ -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.0165, 0.66)
- if (tech.isHarmReduce && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.25
+ if (tech.isHarmReduce && input.field) dmg *= 0.25
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.1
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
@@ -2779,14 +2779,10 @@ const m = {
effect: () => {
m.fieldMeterColor = "#48f" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
-
m.fieldShieldingScale = 0;
m.fieldBlockCD = 3;
m.grabPowerUpRange2 = 10000000
- m.fieldPosition = {
- x: m.pos.x,
- y: m.pos.y
- }
+ m.fieldPosition = { x: m.pos.x, y: m.pos.y }
m.fieldAngle = m.angle
m.perfectPush = (isFree = false) => {
if (m.fieldCDcycle < m.cycle) {
@@ -2794,10 +2790,7 @@ const m = {
if (
Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) - mob[i].radius < m.fieldRange &&
!mob[i].isUnblockable &&
- Vector.dot({
- x: Math.cos(m.fieldAngle),
- y: Math.sin(m.fieldAngle)
- }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold &&
+ Vector.dot({ x: Math.cos(m.fieldAngle), y: Math.sin(m.fieldAngle) }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold &&
Matter.Query.ray(map, mob[i].position, m.fieldPosition).length === 0
) {
mob[i].locatePlayer();
@@ -2816,11 +2809,7 @@ const m = {
}
}
if (tech.blockDmg) { //electricity
- Matter.Body.setVelocity(mob[i], {
- x: 0.5 * mob[i].velocity.x,
- y: 0.5 * mob[i].velocity.y
- });
-
+ Matter.Body.setVelocity(mob[i], { x: 0.5 * mob[i].velocity.x, y: 0.5 * mob[i].velocity.y });
if (mob[i].isShielded) {
for (let j = 0, len = mob.length; j < len; j++) {
if (mob[j].id === mob[i].shieldID) mob[j].damage(tech.blockDmg * m.dmgScale * (tech.isBlockRadiation ? 6 : 2), true)
@@ -3684,6 +3673,94 @@ const m = {
ctx.strokeStyle = "rgba(255,0,110,0.06)"
ctx.stroke();
}
+ // } else if (true) { //plasma sword slash
+ // const plasmaSweepCycles = 30
+ // m.plasmaSweep = 0
+ // m.plasmaSlashDirection = m.flipLegs//Math.random() > 0.5 ? 1 : -1;
+ // m.hold = function () {
+ // if (m.isHolding) {
+ // m.drawHold(m.holdingTarget);
+ // m.holding();
+ // m.throwBlock();
+ // m.plasmaSweep = 0
+ // // } else if (true) { //not hold but field button is pressed
+ // } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ // if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ // m.grabPowerUp();
+ // m.lookForPickUp();
+
+ // //graphics
+ // if (m.plasmaSweep === 0) m.plasmaSlashDirection = m.flipLegs //Math.random() > 0.5 ? 1 : -1;
+ // const angle = m.angle //+ 1 * (m.plasmaSweep - plasmaSweepCycles / 2) / plasmaSweepCycles * m.plasmaSlashDirection
+ // const plasmaSweepCapped = Math.min(m.plasmaSweep, plasmaSweepCycles - 8) / plasmaSweepCycles
+ // const range = 100 * plasmaSweepCapped
+ // const arc = 1.3
+ // const A = { x: m.pos.x + range * Math.cos(angle - arc), y: m.pos.y + range * Math.sin(angle - arc) }
+ // const B = { x: m.pos.x + range * Math.cos(angle + arc), y: m.pos.y + range * Math.sin(angle + arc) }
+ // const controlRange = 500 * plasmaSweepCapped
+ // const AC = { x: m.pos.x + controlRange * Math.cos(angle - arc / 2), y: m.pos.y + controlRange * Math.sin(angle - arc / 2) }
+ // const BC = { x: m.pos.x + controlRange * Math.cos(angle + arc / 2), y: m.pos.y + controlRange * Math.sin(angle + arc / 2) }
+ // const innerControlRange = 300 * plasmaSweepCapped
+ // const ACinner = { x: m.pos.x + innerControlRange * Math.cos(angle - arc / 2), y: m.pos.y + innerControlRange * Math.sin(angle - arc / 2) }
+ // const BCinner = { x: m.pos.x + innerControlRange * Math.cos(angle + arc / 2), y: m.pos.y + innerControlRange * Math.sin(angle + arc / 2) }
+ // ctx.beginPath();
+ // ctx.moveTo(A.x, A.y)
+ // ctx.bezierCurveTo(AC.x, AC.y, BC.x, BC.y, B.x, B.y); //outer curve
+ // ctx.bezierCurveTo(BCinner.x, BCinner.y, ACinner.x, ACinner.y, A.x, A.y); //inner curve
+ // // ctx.strokeStyle = "#000"
+ // // ctx.stroke();
+ // ctx.fillStyle = "rgba(255,0,255,0.5)"
+ // ctx.fill();
+
+ // //draw control points for graphics reference
+ // ctx.lineWidth = '0.5'
+ // ctx.beginPath();
+ // ctx.arc(A.x, A.y, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+ // ctx.beginPath();
+ // ctx.arc(B.x, B.y, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+ // ctx.beginPath();
+ // ctx.arc(AC.x, AC.y, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+ // ctx.beginPath();
+ // ctx.arc(BC.x, BC.y, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+ // ctx.beginPath();
+ // ctx.arc(ACinner.x, ACinner.y, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+ // ctx.beginPath();
+ // ctx.arc(BCinner.x, BCinner.y, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+
+ // //mob collision detection
+ // collideRange = 160
+ // const collideCenter = {
+ // x: m.pos.x + collideRange * Math.cos(angle),
+ // y: m.pos.y + collideRange * Math.sin(angle)
+ // }
+ // ctx.beginPath();
+ // ctx.arc(collideCenter.x, collideCenter.y, 140, 0, 2 * Math.PI);
+ // ctx.stroke();
+
+ // //push mob away and slow them?
+
+
+ // //sweeping motion and cooldown
+ // m.plasmaSweep++
+ // if (m.plasmaSweep > plasmaSweepCycles) {
+ // m.plasmaSweep = 0
+ // if (m.fireCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 30
+ // }
+ // } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ // m.pickUp();
+ // m.plasmaSweep = 0
+ // } else {
+ // m.plasmaSweep = 0
+ // m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ // }
+ // m.drawRegenEnergy("rgba(0, 0, 0, 0.2)")
+ // }
} else {
m.hold = function () {
if (m.isHolding) {
@@ -4864,6 +4941,31 @@ const m = {
// m.drawRegenEnergy()
// },
},
+ {
+ name: "grappling hook",
+ // description: `use energy to pull yourself towards the map
generate 6 energy per second`,
+ description: `use energy to fire a hook that attaches to map,
pulls player, damages mobs, and destroys blocks
generate 6 energy per second`,
+ effect: () => {
+ m.fieldFire = true;
+ // m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping
+ m.fieldMeterColor = "#333"
+ m.eyeFillColor = m.fieldMeterColor
+ m.fieldHarmReduction = 0.45; //55% reduction
+
+ m.hold = function () {
+ if (input.field) {
+ if (m.fieldCDcycle < m.cycle) {
+ if (m.energy > 0.02) m.energy -= 0.02
+ const where = { x: m.pos.x + 40 * Math.cos(m.angle), y: m.pos.y + 40 * Math.sin(m.angle) }
+ b.grapple(where, m.angle)
+ if (m.fieldCDcycle < m.cycle + 20) m.fieldCDcycle = m.cycle + 20
+ }
+ m.grabPowerUp();
+ }
+ m.drawRegenEnergy()
+ }
+ }
+ },
],
//************************************************************************************
//************************************************************************************
diff --git a/js/powerup.js b/js/powerup.js
index 934a523..1b27ff1 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -914,54 +914,57 @@ const powerUps = {
for (let i = 0; i < b.guns.length; i++) {
if (!b.guns[i].have) options.push(i);
}
- let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
- if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
- function removeOption(index) {
- for (let i = 0; i < options.length; i++) {
- if (options[i] === index) {
- options.splice(i, 1) //remove a previous choice from option pool
- return
+ // console.log(options.length)
+ if (options.length > 0 || !tech.isSuperDeterminism) {
+ let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
+ if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
+ function removeOption(index) {
+ for (let i = 0; i < options.length; i++) {
+ if (options[i] === index) {
+ options.splice(i, 1) //remove a previous choice from option pool
+ return
+ }
}
}
- }
- //check for guns that were a choice last time and remove them
- for (let i = 0; i < b.guns.length; i++) {
- if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
- if (b.guns[i].isRecentlyShown) removeOption(i)
- }
- for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
- // if (options.length > 0) {
- let text = powerUps.buildColumns(totalChoices, "gun")
- for (let i = 0; i < totalChoices; i++) {
- const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
- // text += `