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 += `
  ${b.guns[choose].name}
${b.guns[choose].description}
` - text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`) - - b.guns[choose].isRecentlyShown = true - removeOption(choose) - if (options.length < 1) break - } - if (tech.isExtraBotOption) { - const botTech = [] //make an array of bot options - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i) + //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) } - if (botTech.length > 0) { //pick random bot tech - // const choose = botTech[Math.floor(Math.random() * botTech.length)]; - // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; - // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` - const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; - const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` - text += `
+ 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 += `
  ${b.guns[choose].name}
${b.guns[choose].description}
` + text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`) + + b.guns[choose].isRecentlyShown = true + removeOption(choose) + if (options.length < 1) break + } + if (tech.isExtraBotOption) { + const botTech = [] //make an array of bot options + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i) + } + if (botTech.length > 0) { //pick random bot tech + // const choose = botTech[Math.floor(Math.random() * botTech.length)]; + // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; + // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + const choose = botTech[Math.floor(Math.random() * botTech.length)]; + const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + text += `
⭓▸●■   ${tech.tech[choose].name} ${techCountText}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + } } + if (tech.isOneGun && b.inventory.length > 0) text += `
replaces your current gun
` + document.getElementById("choose-grid").innerHTML = text + powerUps.showDraft(); } - if (tech.isOneGun && b.inventory.length > 0) text += `
replaces your current gun
` - document.getElementById("choose-grid").innerHTML = text - powerUps.showDraft(); // } } }, diff --git a/js/tech.js b/js/tech.js index 50edafc..9c4a5cb 100644 --- a/js/tech.js +++ b/js/tech.js @@ -232,7 +232,7 @@ const tech = { // } // } if (tech.isDivisor && b.activeGun && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77 - if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.78 : 1.88 + if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.75 : 2 if (tech.isDilate) dmg *= 1.5 + 0.6 * Math.sin(m.cycle * 0.0075) 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 @@ -955,9 +955,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple + return !m.isShipMode && !tech.isAlwaysFire }, - requires: "not ship mode, automatic, grappling hook", + requires: "not ship mode, automatic", effect() { tech.isFireMoveLock = true; b.setFireCD(); @@ -6682,10 +6682,10 @@ const tech = { }, requires: "foam", effect() { - tech.foamDamage += 0.011 * 0.43 + tech.foamDamage += 0.01 * 0.43 }, remove() { - tech.foamDamage = 0.011; + tech.foamDamage = 0.01; } }, { @@ -6831,9 +6831,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple && !tech.isBoostReplaceAmmo + return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isBoostReplaceAmmo }, - requires: "harpoon, not UHMWPE, induction furnace, grappling hook, quasiparticles", + requires: "harpoon, not UHMWPE, induction furnace, quasiparticles", ammoBonus: 9, effect() { tech.isRailGun = true; @@ -6852,52 +6852,52 @@ const tech = { } } }, - { - name: "grappling hook", - description: `harpoons attach to the map and pull you
your rope extends while holding fire`, - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock - }, - requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism", - effect() { - tech.isGrapple = true; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod() - } - }, - remove() { - if (tech.isGrapple) { - tech.isGrapple = false; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod() - } - } - } - }, - { - name: "bulk modulus", - description: `while grappling become invulnerable
drain energy`, - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy - }, - requires: "grappling hook, not alternator", - effect() { - tech.isImmuneGrapple = true; - }, - remove() { - tech.isImmuneGrapple = false - } - }, + // { + // name: "grappling hook", + // description: `harpoons attach to the map and pull you
your rope extends while holding fire`, + // isGunTech: true, + // maxCount: 1, + // count: 0, + // frequency: 2, + // frequencyDefault: 2, + // allowed() { + // return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock + // }, + // requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism", + // effect() { + // tech.isGrapple = true; + // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun + // if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod() + // } + // }, + // remove() { + // if (tech.isGrapple) { + // tech.isGrapple = false; + // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun + // if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod() + // } + // } + // } + // }, + // { + // name: "bulk modulus", + // description: `while grappling become invulnerable
drain energy`, + // isGunTech: true, + // maxCount: 1, + // count: 0, + // frequency: 2, + // frequencyDefault: 2, + // allowed() { + // return tech.haveGunCheck("harpoon") && !tech.isRailEnergy + // }, + // requires: "not alternator", + // effect() { + // tech.isImmuneGrapple = true; + // }, + // remove() { + // tech.isImmuneGrapple = false + // } + // }, { name: "alternator", description: "+90% harpoon energy efficiency", @@ -6907,9 +6907,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("harpoon") && !tech.isImmuneGrapple + return tech.haveGunCheck("harpoon") }, - requires: "harpoon, not bulk modulus", + requires: "harpoon", effect() { tech.isRailEnergy = true; }, @@ -6994,9 +6994,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple + return tech.haveGunCheck("harpoon") && !tech.isRailGun }, - requires: "harpoon, not grappling hook, railgun", + requires: "harpoon, not railgun", effect() { tech.isFilament = true; }, @@ -7013,9 +7013,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple + return tech.haveGunCheck("harpoon") && !tech.isRailGun }, - requires: "harpoon, not grappling hook, railgun", + requires: "harpoon, not railgun", effect() { tech.isHarpoonPowerUp = true }, @@ -7657,9 +7657,9 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3) && (build.isExperimentSelection || powerUps.research.count > 3) + return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 3) }, - requires: "perfect diamagnetism, negative mass, pilot wave", + requires: "perfect diamagnetism, negative mass, grappling hook, pilot wave", effect() { tech.isFieldHarmReduction = true for (let i = 0; i < 2; i++) { @@ -7706,9 +7706,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (m.fieldMode === 8 || m.fieldMode === 3) && !tech.isCloakHealLastHit + return m.fieldMode === 8 || m.fieldMode === 3 }, - requires: "negative mass, pilot wave, not patch", + requires: "negative mass, pilot wave", effect() { tech.lastHitDamage += 4; }, @@ -7746,16 +7746,16 @@ const tech = { }, { name: "aerostat", - description: `+88% damage while off the ground
-22% damage while on the ground`, + description: `+100% damage while off the ground
-25% damage while on the ground`, isFieldTech: true, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return m.fieldMode === 3 + return m.fieldMode === 3 || m.fieldMode === 10 }, - requires: "negative mass", + requires: "negative mass, grappling hook", effect() { tech.isNoGroundDamage = true }, @@ -7831,9 +7831,9 @@ const tech = { isBotTech: true, isNonRefundable: true, allowed() { - return powerUps.research.count > 1 && (m.fieldMode === 4 || m.fieldMode === 8) + return powerUps.research.count > 1 && (m.fieldMode === 4 || m.fieldMode === 10 || m.fieldMode === 8) }, - requires: "molecular assembler, pilot wave", + requires: "molecular assembler, grappling hook, pilot wave", effect() { for (let i = 0; i < 2; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) @@ -7856,9 +7856,9 @@ const tech = { isBotTech: true, isNonRefundable: true, allowed() { - return powerUps.research.count > 2 && (m.fieldMode === 4 || m.fieldMode === 8) + return powerUps.research.count > 2 && (m.fieldMode === 4 || m.fieldMode === 10 || m.fieldMode === 8) }, - requires: "molecular assembler, pilot wave", + requires: "molecular assembler, grappling hook, pilot wave", effect() { for (let i = 0; i < 3; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) @@ -8121,9 +8121,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 2 || m.fieldMode === 8) + return (m.fieldMode === 10 || m.fieldMode === 4 || m.fieldMode === 8) }, - requires: "molecular assembler, plasma torch, perfect diamagnetism, pilot wave", + requires: "plasma torch, grappling hook, pilot wave", effect() { tech.isHarmReduce = true }, @@ -8479,9 +8479,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return m.fieldMode === 7 && !tech.lastHitDamage && !tech.isEnergyHealth + return m.fieldMode === 7 && !tech.isEnergyHealth }, - requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy", + requires: "metamaterial cloaking, not mass-energy", effect() { tech.isCloakHealLastHit = true; }, @@ -8586,9 +8586,9 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (m.fieldMode === 8 || m.fieldMode === 3 || m.fieldMode === 6 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2) + return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 2) }, - requires: "wormhole, time dilation, negative mass, pilot wave", + requires: "wormhole, time dilation, negative mass, pilot wave, grappling hook", effect() { tech.fieldDuplicate = 0.11 powerUps.setPowerUpMode(); //needed after adjusting duplication chance @@ -10982,6 +10982,30 @@ const tech = { }, remove() { } }, + { + name: "mobs!", + descriptionFunction() { + if (this.mobType === "") this.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)] + return `spawn 20 ${this.mobType} mobs` + }, + maxCount: 1, + count: 0, + frequency: 0, + isNonRefundable: true, + isJunk: true, + allowed() { return true }, + requires: "", + mobType: "", + effect() { + if (this.mobType === "") this.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)] + for (let i = 0; i < 20; i++) { + spawn[this.mobType](m.pos.x, m.pos.y - 700) + } + simulation.makeTextLog(`spawn.${this.mobType}(x,y)`) + + }, + remove() { } + }, { name: "black hole cluster", description: `spawn 30 nearby black holes`, @@ -11718,8 +11742,8 @@ const tech = { isTimeCrystals: null, isGroundState: null, isRailGun: null, - isGrapple: null, - isImmuneGrapple: null, + // isGrapple: null, + // isImmuneGrapple: null, isDronesTravel: null, isTechDebt: null, isPlasmaBall: null, diff --git a/js/visibility.js b/js/visibility.js deleted file mode 100644 index d1686b7..0000000 --- a/js/visibility.js +++ /dev/null @@ -1,44 +0,0 @@ -// https://ncase.me/sight-and-light/ -// redblobgames.com/articles/visibility -// https://github.com/Silverwolf90/2d-visibility/tree/master/src -// could apply to explosions, neutron bomb, player LOS - - -const v = { - points: [], - populate() { - v.points = [{ - x: -150, - y: -950 - }, { - x: 710, - y: -950 - }, { - x: 710, - y: -940 - }, { - x: 710, - y: -710 - }, { - x: 710, - y: -700 - }, { - x: -150, - y: -700 - }] - }, - draw() { - ctx.beginPath(); - ctx.moveTo(v.points[0].x, v.points[0].y) - for (let i = 0, len = v.points.length; i < len; i++) { - ctx.lineTo(v.points[i].x, v.points[i].y) - } - // ctx.fillStyle = "#333" - ctx.globalCompositeOperation = "destination-in"; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - ctx.clip(); - } -} -v.populate(); -// console.log(v.points) \ No newline at end of file diff --git a/todo.txt b/todo.txt index 32e22e5..76a7a9c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,20 +1,58 @@ ******************************************************** NEXT PATCH ************************************************** -new community map - LaunchSite by Des Boot +grappling hook is now a field (work in progress) + reworked physics to allow faster speeds, but more control + improved rate of power up grabbing + more player control to hook retraction rate + changed hook shape and field image graphics + grappling hook field coupling, more tech, bug fixes, and general polish to be added soon -added a short color animation after grabbing basic power ups +aerostat - 88->100% damage in air 22-> 25% damage on ground +foam damage reduced 10%, ammo increased about 10% +after hitting an invulnerable mob (drones,spores,worms,iceIX,fleas) don't die or lose cycles +added JUNK tech: mobs! - summon 20 random mobs +added announcement of mob names in console at start of new level -reduced overall damage done to player by ~6% -commodities exchange spawns 5-10 -> 6-12 power ups on cancel -residual dipolar coupling spawns 5 -> 6 coupling power ups - -bots maintain relative position to player after the no camera tracking teleport - for portals and falling off level - -the once every 7 seconds stuck check now also check to see if you stay stuck for 3 seconds before resetting you. +bug fixes *********************************************************** TODO ***************************************************** +grappling hook is a field + check for places that the player could get into but not out of + maybe grapple could grab more then 1 power up? + grapple slices blocks + cut large blocks into 2,3 + use dead mob code for mobs > 5 sides + write code to cut large blocks in half and remove one half + need several field tech + new field tech ideas + increase hook damage + hook damage aura + hook's line does damage + make several auto targeting harpoons after taking damage + how to make them not drain energy + generate ___ after destroying blocks + energy, drones, iceIX, explosion, nails, junk bots? + coupling effect: defense?, bonus from ammo power ups, fire rate + +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 + heal for 50%? + heal from mob damage or from kills? + +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 + sharp cut off + use length of torch as cut off length + make it look like hollow knight slash + what about upgrades to extruder,plasma ball + give them their own version of a slash? + make a tech that buffs the slash, but it disables extruder,plasma ball + more (all) bosses need to be made of parts good examples: spiderBoss, dragonFlyBoss, beetleBoss methods: