winter vacation update

mob health tech
  tech: cascading failure - +222% damage to mobs below 25% health
  tech: yield stress - +55% damage to mobs at maximum health
  cloaking tech: topological defect - +88% damage to mobs at maximum health
  harpoon tech: brittle - +88% harpoon/grapple damage to mobs at maximum health

cloaking buffs
  50->66% defense while cloaked
  recloak 0.25s faster
  simplified cloaking field graphics
  boson composite drains much less energy while moving through mobs and shields
    fixed bug where mines and egg mobs were colliding with player while intangible
  patch no longer drains energy when you heal on cloaking
  metamaterial absorber gets 17->22% chance to spawn a power up for each mob alive
  no-cloning theorem changes to 45->40% duplication and 2->1% duplication loss on killing a mob

finalBoss phases:
  new: slow zone, antigravity pulse
  nerfed: laser, black hole, orbitals
  buffed: oscillation, mobs
  improved graphics: boulder

Hilbert space has a skin. 99->142% damage increase, but randomize tech after taking damage
Higgs mechanism has a skin. +45->77% fire rate, player can't move while firing
induction furnace gives +77% harpoon/grapple damage for 8 seconds after picking up a power up
collider 50->100% chance to combine and randomize power ups
quenching gives more bonus max health at high difficulty level  (maybe around 30% more health)
accretion gives 5->7 heal power ups
dynamo bots follow player much closer when you have many of them
scrap-bots don't follow the player as accurately or as quickly
  scrap bot duration 13->15 seconds
JUNK tech: planned obsolescence - make 100 scrap bots that last for about 30 seconds

community map dojo by werid_pusheen
  fixed by Cornbread 2100

hard mode gets 1 less heal at the start
hard and why difficulty don't begin with starter mobs
hopBullet mobs last 2 seconds less time
adjusted button heights on train station level to be consistently the same height
This commit is contained in:
landgreen
2024-01-04 16:38:52 -08:00
parent 2d12f1da42
commit c47d86064b
15 changed files with 1312 additions and 840 deletions

BIN
img/brittle.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
img/cascading failure.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
img/topological defect.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
img/yield stress.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -288,7 +288,7 @@ const b = {
if (m.fieldMode === 6) b.fireCDscale *= 0.8 if (m.fieldMode === 6) b.fireCDscale *= 0.8
if (tech.isFastTime) b.fireCDscale *= 0.5 if (tech.isFastTime) b.fireCDscale *= 0.5
if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, Math.max(0, b.inventory.length - 1)) if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, Math.max(0, b.inventory.length - 1))
if (tech.isFireMoveLock) b.fireCDscale *= 0.55 if (tech.isFireMoveLock) b.fireCDscale *= 0.23 // 77% fire rate
}, },
fireAttributes(dir, rotate = true) { fireAttributes(dir, rotate = true) {
if (rotate) { if (rotate) {
@@ -1508,8 +1508,9 @@ const b = {
}, },
minDmgSpeed: 4, minDmgSpeed: 4,
// lookFrequency: Math.floor(7 + Math.random() * 3), // lookFrequency: Math.floor(7 + Math.random() * 3),
density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon
drain: 0.001, drain: 0.001,
powerUpDamage: tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle,
draw() { draw() {
// draw rope // draw rope
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
@@ -1559,9 +1560,26 @@ const b = {
// ctx.stroke(); // ctx.stroke();
// } // }
if (this.powerUpDamage) {
ctx.beginPath();
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
ctx.lineTo(this.vertices[2].x, this.vertices[2].y);
ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
ctx.lineTo(this.vertices[4].x, this.vertices[4].y);
ctx.lineJoin = "miter"
ctx.miterLimit = 30;
ctx.lineWidth = 25;
ctx.strokeStyle = "rgba(0,255,255,0.4)";
ctx.stroke();
ctx.lineWidth = 8;
ctx.strokeStyle = "rgb(0,255,255)";
ctx.stroke();
ctx.lineJoin = "round"
ctx.miterLimit = 5
ctx.fillStyle = "#000"
ctx.fill();
}
//draw hook //draw hook
ctx.beginPath(); ctx.beginPath();
ctx.lineTo(this.vertices[0].x, this.vertices[0].y); ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
@@ -1581,6 +1599,42 @@ const b = {
} }
if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
// if (this.powerUpDamage) this.density = 2 * 0.004 //double damage after pick up power up for 8 seconds
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
Matter.Body.setDensity(this, 1.8 * 0.004); //+90% damage after pick up power up for 8 seconds
} else if (tech.isHarpoonFullHealth && who.health === 1) {
Matter.Body.setDensity(this, 1.9 * 0.004); //+90% damage if mob has full health do
simulation.ephemera.push({
name: "grapple outline",
count: 3, //cycles before it self removes
vertices: this.vertices,
do() {
this.count--
if (this.count < 0) simulation.removeEphemera(this.name)
ctx.beginPath();
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
ctx.lineJoin = "miter"
ctx.miterLimit = 20;
ctx.lineWidth = 40;
ctx.strokeStyle = "rgba(255,0,100,0.35)";
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = `#f07`;
ctx.stroke();
ctx.lineJoin = "round"
ctx.miterLimit = 5
ctx.fillStyle = "#000"
ctx.fill();
},
})
}
this.retract() this.retract()
}, },
caughtPowerUp: null, caughtPowerUp: null,
@@ -1602,7 +1656,7 @@ const b = {
this.caughtPowerUp.effect(); this.caughtPowerUp.effect();
Matter.Composite.remove(engine.world, this.caughtPowerUp); Matter.Composite.remove(engine.world, this.caughtPowerUp);
powerUp.splice(index, 1); powerUp.splice(index, 1);
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal if (tech.isHarpoonPowerUp) tech.harpoonPowerUpCycle = simulation.cycle
} else { } else {
this.dropCaughtPowerUp() this.dropCaughtPowerUp()
} }
@@ -1893,321 +1947,6 @@ const b = {
}); });
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
// grapple(where, angle = m.angle, harpoonSize = 1) {
// const me = bullet.length;
// const returnRadius = 100 * Math.sqrt(harpoonSize)
// bullet[me] = Bodies.fromVertices(where.x, where.y, [{
// x: -50 * harpoonSize,
// y: 2 * harpoonSize,
// index: 0,
// isInternal: false
// }, {
// x: -50 * harpoonSize,
// y: -2 * harpoonSize,
// index: 1,
// isInternal: false
// }, {
// x: 45 * harpoonSize,
// y: -3 * harpoonSize,
// index: 2,
// isInternal: false
// }, {
// x: 50 * harpoonSize,
// y: 0,
// index: 3,
// isInternal: false
// }, {
// x: 45 * harpoonSize,
// y: 3 * harpoonSize,
// index: 4,
// isInternal: false
// }], {
// angle: angle,
// friction: 1,
// frictionAir: 0.4,
// thrustMag: 0.1,
// dmg: 6, //damage done in addition to the damage from momentum
// classType: "bullet",
// endCycle: simulation.cycle + 70,
// collisionFilter: {
// category: cat.bullet,
// mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
// },
// minDmgSpeed: 4,
// lookFrequency: Math.floor(7 + Math.random() * 3),
// density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
// drain: tech.isRailEnergy ? 0.0006 : 0.006,
// beforeDmg(who) {
// if (tech.isShieldPierce && who.isShielded) { //disable shields
// who.isShielded = false
// requestAnimationFrame(() => {
// who.isShielded = true
// });
// }
// if (tech.fragments) {
// b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random()))
// }
// if (tech.isFoamBall) {
// for (let i = 0, len = 4 * this.mass; i < len; i++) {
// const radius = 5 + 8 * Math.random()
// const velocity = {
// x: Math.max(0.5, 2 - radius * 0.1),
// y: 0
// }
// b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
// }
// // this.endCycle = 0;
// }
// },
// caughtPowerUp: null,
// dropCaughtPowerUp() {
// if (this.caughtPowerUp) {
// this.caughtPowerUp.collisionFilter.category = cat.powerUp
// this.caughtPowerUp.collisionFilter.mask = cat.map | cat.powerUp
// this.caughtPowerUp = null
// }
// },
// onEnd() {
// if (this.caughtPowerUp && !simulation.isChoosing && (this.caughtPowerUp.name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)) {
// let index = null //find index
// for (let i = 0, len = powerUp.length; i < len; ++i) {
// if (powerUp[i] === this.caughtPowerUp) index = i
// }
// if (index !== null) {
// powerUps.onPickUp(this.caughtPowerUp);
// this.caughtPowerUp.effect();
// Matter.Composite.remove(engine.world, this.caughtPowerUp);
// powerUp.splice(index, 1);
// if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
// } else {
// this.dropCaughtPowerUp()
// }
// } else {
// this.dropCaughtPowerUp()
// }
// },
// draw() {
// const where = {
// x: m.pos.x + 30 * Math.cos(m.angle),
// y: m.pos.y + 30 * Math.sin(m.angle)
// }
// const sub = Vector.sub(where, this.vertices[0])
// const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
// ctx.strokeStyle = "#000" // "#0ce"
// ctx.lineWidth = 0.5
// ctx.beginPath();
// ctx.moveTo(where.x, where.y);
// ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
// // ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
// ctx.stroke();
// //draw harpoon spikes
// const spikeLength = 2
// ctx.beginPath();
// const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
// ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
// ctx.lineTo(spike1.x, spike1.y);
// ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
// const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
// ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
// ctx.lineTo(spike2.x, spike2.y);
// ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
// ctx.fillStyle = '#000'
// ctx.fill();
// },
// returnToPlayer() {
// if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
// this.endCycle = 0;
// // if (m.energy < 0.05) {
// // m.fireCDcycle = m.cycle + 120; //fire cooldown
// // } else if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) {
// // m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 25 if it is above 25
// // }
// if (m.energy < 0.05) this.dropCaughtPowerUp()
// //recoil on catching
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
// player.force.x += momentum.x
// player.force.y += momentum.y
// // refund ammo
// b.guns[9].ammo++;
// simulation.updateGunHUD();
// // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
// // if (b.guns[i].name === "harpoon") {
// // b.guns[i].ammo++;
// // simulation.updateGunHUD();
// // break;
// // }
// // }
// } else {
// if (m.energy > this.drain) m.energy -= this.drain
// const sub = Vector.sub(this.position, m.pos)
// const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
// const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
// this.force.x -= returnForce.x
// this.force.y -= returnForce.y
// this.grabPowerUp()
// }
// this.draw();
// },
// grabPowerUp() { //grab power ups near the tip of the harpoon
// if (this.caughtPowerUp) {
// Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
// Matter.Body.setVelocity(this.caughtPowerUp, {
// x: 0,
// y: 0
// })
// } else { //&& simulation.cycle % 2
// for (let i = 0, len = powerUp.length; i < len; ++i) {
// const radius = powerUp[i].circleRadius + 50
// if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) {
// if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
// this.caughtPowerUp = powerUp[i]
// Matter.Body.setVelocity(powerUp[i], {
// x: 0,
// y: 0
// })
// Matter.Body.setPosition(powerUp[i], this.vertices[2])
// powerUp[i].collisionFilter.category = 0
// powerUp[i].collisionFilter.mask = 0
// this.thrustMag *= 0.6
// this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
// break //just pull 1 power up if possible
// }
// }
// }
// }
// },
// do() {
// if (input.fire) { //&& !Matter.Query.collides(this, body).length
// this.grabPowerUp()
// if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction
// this.endCycle = simulation.cycle + 60
// // m.fireCDcycle = m.cycle + 120 // cool down
// this.do = this.returnToPlayer
// Matter.Body.setDensity(this, 0.0005); //reduce density on return
// if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
// this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
// }
// } else {
// //if not enough energy
// if (m.energy < 0.05) this.dropCaughtPowerUp()
// // const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
// // this.force.x -= returnForce.x
// // this.force.y -= returnForce.y
// // this.frictionAir = 0.002
// // this.do = () => {
// // if (this.speed < 20) this.force.y += 0.0005 * this.mass;
// // }
// // } else {
// //return to player
// this.do = this.returnToPlayer
// this.endCycle = simulation.cycle + 60
// Matter.Body.setDensity(this, 0.0005); //reduce density on return
// if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
// this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
// //recoil on catching
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
// player.force.x += momentum.x
// player.force.y += momentum.y
// // }
// }
// //grappling hook
// if (input.fire && Matter.Query.collides(this, map).length) {
// Matter.Body.setPosition(this, Vector.add(this.position, {
// x: 20 * Math.cos(this.angle),
// y: 20 * Math.sin(this.angle)
// }))
// if (Matter.Query.collides(this, map).length) {
// Matter.Body.setVelocity(this, {
// x: 0,
// y: 0
// });
// Matter.Sleeping.set(this, true)
// this.endCycle = simulation.cycle + 5
// this.dropCaughtPowerUp()
// this.do = () => {
// //between player nose and the grapple
// const sub = Vector.sub(this.vertices[0], {
// x: m.pos.x + 30 * Math.cos(m.angle),
// y: m.pos.y + 30 * Math.sin(m.angle)
// })
// let dist = Vector.magnitude(sub)
// if (input.fire) {
// // m.fireCDcycle = m.cycle + 30; // cool down if out of energy
// m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
// this.endCycle = simulation.cycle + 10
// if (input.down) { //down
// dist = 0
// player.force.y += 5 * player.mass * simulation.g;
// }
// if (m.energy > this.drain) {
// Matter.Body.setVelocity(player, {
// x: player.velocity.x * 0.8,
// y: player.velocity.y * 0.8
// });
// const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), 200))
// player.force.x += pull.x
// player.force.y += pull.y
// if (dist > 500) {
// m.energy -= this.drain
// if (m.energy < 0) {
// this.endCycle = 0;
// if (m.cycle + 50 < m.fireCDcycle) m.fireCDcycle = m.cycle + 50
// // refund ammo
// b.guns[9].ammo++;
// simulation.updateGunHUD();
// // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
// // if (b.guns[i].name === "harpoon") {
// // break;
// // }
// // }
// }
// }
// }
// if (tech.isImmuneGrapple && m.immuneCycle < m.cycle + 10) {
// m.immuneCycle = m.cycle + 10;
// if (m.energy > 0.001) {
// m.energy -= 0.001
// } else { //out of energy
// Matter.Sleeping.set(this, false)
// this.collisionFilter.category = 0
// this.collisionFilter.mask = 0
// this.do = this.returnToPlayer
// this.endCycle = simulation.cycle + 60
// m.fireCDcycle = m.cycle + 120; //fire cooldown
// //recoil on catching
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
// player.force.x += momentum.x
// player.force.y += momentum.y
// }
// }
// } else {
// Matter.Sleeping.set(this, false)
// this.collisionFilter.category = 0
// this.collisionFilter.mask = 0
// this.do = this.returnToPlayer
// this.endCycle = simulation.cycle + 60
// //recoil on catching
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
// player.force.x += momentum.x
// player.force.y += momentum.y
// }
// this.draw();
// }
// }
// }
// this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
// this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
// this.draw()
// },
// });
// Composite.add(engine.world, bullet[me]); //add bullet to world
// },
harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) { harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {
const me = bullet.length; const me = bullet.length;
const returnRadius = 100 * Math.sqrt(harpoonSize) const returnRadius = 100 * Math.sqrt(harpoonSize)
@@ -2274,12 +2013,43 @@ const b = {
} }
} }
if (tech.isFoamBall) { if (tech.isFoamBall) {
for (let i = 0, len = Math.min(50, 2.5 + 3 * Math.sqrt(this.mass)); i < len; i++) { for (let i = 0, len = Math.min(30, 2 + 2 * Math.sqrt(this.mass)); i < len; i++) {
const radius = 5 + 8 * Math.random() const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } 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) b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
} }
} }
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
Matter.Body.setDensity(this, 1.8 * tech.harpoonDensity); //+90% damage after pick up power up for 8 seconds
} else if (tech.isHarpoonFullHealth && who.health === 1) {
Matter.Body.setDensity(this, 1.9 * tech.harpoonDensity); //+90% damage if mob has full health do
simulation.ephemera.push({
name: "harpoon outline",
count: 2, //cycles before it self removes
vertices: this.vertices,
do() {
this.count--
if (this.count < 0) simulation.removeEphemera(this.name)
ctx.beginPath();
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
ctx.lineJoin = "miter"
ctx.miterLimit = 20;
ctx.lineWidth = 40;
ctx.strokeStyle = "rgba(255,0,100,0.35)";
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = `#f07`;
ctx.stroke();
ctx.lineJoin = "round"
ctx.miterLimit = 5
ctx.fillStyle = "#000"
ctx.fill();
},
})
}
}, },
caughtPowerUp: null, caughtPowerUp: null,
dropCaughtPowerUp() { dropCaughtPowerUp() {
@@ -2300,7 +2070,7 @@ const b = {
this.caughtPowerUp.effect(); this.caughtPowerUp.effect();
Matter.Composite.remove(engine.world, this.caughtPowerUp); Matter.Composite.remove(engine.world, this.caughtPowerUp);
powerUp.splice(index, 1); powerUp.splice(index, 1);
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.006 is normal if (tech.isHarpoonPowerUp) tech.harpoonPowerUpCycle = simulation.cycle
} else { } else {
this.dropCaughtPowerUp() this.dropCaughtPowerUp()
} }
@@ -2308,29 +2078,26 @@ const b = {
this.dropCaughtPowerUp() this.dropCaughtPowerUp()
} }
}, },
drawToggleHarpoon() { drawDamageAura() {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(this.vertices[0].x, this.vertices[0].y); ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y); for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
ctx.lineTo(this.vertices[0].x, this.vertices[0].y); ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
ctx.lineJoin = "miter" ctx.lineJoin = "miter"
ctx.miterLimit = 100; ctx.miterLimit = 20;
ctx.lineWidth = 60; ctx.lineWidth = 15;
ctx.strokeStyle = "rgba(0,255,255,0.25)"; ctx.strokeStyle = "rgba(255,0,100,0.25)";
ctx.stroke(); ctx.stroke();
ctx.lineWidth = 20; ctx.lineWidth = 4;
ctx.strokeStyle = "rgb(0,255,255)"; ctx.strokeStyle = `#f07`;
ctx.stroke(); ctx.stroke();
ctx.lineJoin = "round" ctx.lineJoin = "round"
ctx.miterLimit = 10 ctx.miterLimit = 5
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.fill(); ctx.fill();
}, },
drawString() { drawString() {
const where = { const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
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 sub = Vector.sub(where, this.vertices[0])
const perpendicular = Vector.mult(Vector.normalise(Vector.perp(sub)), this.drawStringFlip * Math.min(80, 10 + this.drawStringControlMagnitude / (10 + Vector.magnitude(sub)))) const perpendicular = Vector.mult(Vector.normalise(Vector.perp(sub)), this.drawStringFlip * Math.min(80, 10 + this.drawStringControlMagnitude / (10 + Vector.magnitude(sub))))
const controlPoint = Vector.add(Vector.add(where, Vector.mult(sub, -0.5)), perpendicular) const controlPoint = Vector.add(Vector.add(where, Vector.mult(sub, -0.5)), perpendicular)
@@ -2384,10 +2151,7 @@ const b = {
grabPowerUp() { //grab power ups near the tip of the harpoon grabPowerUp() { //grab power ups near the tip of the harpoon
if (this.caughtPowerUp) { if (this.caughtPowerUp) {
Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity)) Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
Matter.Body.setVelocity(this.caughtPowerUp, { Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
x: 0,
y: 0
})
} else { //&& simulation.cycle % 2 } else { //&& simulation.cycle % 2
for (let i = 0, len = powerUp.length; i < len; ++i) { for (let i = 0, len = powerUp.length; i < len; ++i) {
const radius = powerUp[i].circleRadius + 50 const radius = powerUp[i].circleRadius + 50
@@ -2395,10 +2159,7 @@ const b = {
if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) { if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
powerUp[i].isGrabbed = true powerUp[i].isGrabbed = true
this.caughtPowerUp = powerUp[i] this.caughtPowerUp = powerUp[i]
Matter.Body.setVelocity(powerUp[i], { Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
x: 0,
y: 0
})
Matter.Body.setPosition(powerUp[i], this.vertices[2]) Matter.Body.setPosition(powerUp[i], this.vertices[2])
powerUp[i].collisionFilter.category = 0 powerUp[i].collisionFilter.category = 0
powerUp[i].collisionFilter.mask = 0 powerUp[i].collisionFilter.mask = 0
@@ -2459,15 +2220,15 @@ const b = {
this.draw(); this.draw();
} }
} }
if (tech.isHarpoonPowerUp && bullet[me].density > 0.01) { if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) { //8 seconds
if (isReturn) { if (isReturn) {
bullet[me].draw = function () { bullet[me].draw = function () {
this.drawToggleHarpoon() this.drawDamageAura()
this.drawString() this.drawString()
} }
} else { } else {
bullet[me].draw = function () { bullet[me].draw = function () {
this.drawToggleHarpoon() this.drawDamageAura()
} }
} }
} else if (isReturn) { } else if (isReturn) {
@@ -2628,15 +2389,9 @@ const b = {
if (dist < radius * radius) { if (dist < radius * radius) {
if (mob[i].speed > 2) { if (mob[i].speed > 2) {
if (mob[i].isBoss || mob[i].isShielded) { if (mob[i].isBoss || mob[i].isShielded) {
Matter.Body.setVelocity(mob[i], { Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.95, y: mob[i].velocity.y * 0.95 });
x: mob[i].velocity.x * 0.95,
y: mob[i].velocity.y * 0.95
});
} else { } else {
Matter.Body.setVelocity(mob[i], { Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.25, y: mob[i].velocity.y * 0.25 });
x: mob[i].velocity.x * 0.25,
y: mob[i].velocity.y * 0.25
});
} }
} }
// Matter.Body.setPosition(this, Vector.add(this.position, mob[i].velocity)) //move with the medium // Matter.Body.setPosition(this, Vector.add(this.position, mob[i].velocity)) //move with the medium
@@ -5139,39 +4894,39 @@ const b = {
for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({ for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({ for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({ for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({ for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.soundBotCount; i++) b.soundBot({ for (let i = 0; i < tech.soundBotCount; i++) b.soundBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({ for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({ for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({ for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
for (let i = 0; i < tech.missileBotCount; i++) b.missileBot({ for (let i = 0; i < tech.missileBotCount; i++) b.missileBot({
x: player.position.x + 50 * (Math.random() - 0.5), x: player.position.x + 50 * (Math.random() - 0.5),
y: player.position.y + 50 * (Math.random() - 0.5) y: player.position.y + 50 * (Math.random() - 0.5)
}, false) })
if (tech.isIntangible && m.isCloak) { if (tech.isIntangible && m.isCloak) {
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield if (bullet[i].botType) bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield
@@ -5250,7 +5005,6 @@ const b = {
}, },
setDynamoBotDelay() { setDynamoBotDelay() {
//reorder orbital bot positions around a circle
let total = 0 let total = 0
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'dynamo') total++ if (bullet[i].botType === 'dynamo') total++
@@ -5259,13 +5013,17 @@ const b = {
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'dynamo') { if (bullet[i].botType === 'dynamo') {
count++ count++
const step = Math.max(60 - 3 * total, 20) const step = Math.max(60 - 3 * total, 10)
bullet[i].followDelay = (step * count) % 600 if (bullet[i].isKeep) {
bullet[i].followDelay = (step * count) % 600
} else {
bullet[i].followDelay = Math.floor(step * bullet.length * Math.random()) % 600
}
} }
} }
}, },
dynamoBot(position = player.position, isConsole = true) { dynamoBot(position = player.position, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.dynamoBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.dynamoBot()`);
const me = bullet.length; const me = bullet.length;
bullet[me] = Bodies.polygon(position.x, position.y, 5, 10, { bullet[me] = Bodies.polygon(position.x, position.y, 5, 10, {
isUpgraded: tech.isDynamoBotUpgrade, isUpgraded: tech.isDynamoBotUpgrade,
@@ -5275,6 +5033,7 @@ const b = {
frictionAir: 0.02, frictionAir: 0.02,
spin: 0.07 * (Math.random() < 0.5 ? -1 : 1), spin: 0.07 * (Math.random() < 0.5 ? -1 : 1),
// isStatic: true, // isStatic: true,
isKeep: isKeep,
isSensor: true, isSensor: true,
restitution: 0, restitution: 0,
dmg: 0, // 0.14 //damage done in addition to the damage from momentum dmg: 0, // 0.14 //damage done in addition to the damage from momentum
@@ -5359,17 +5118,14 @@ const b = {
} }
} }
let history = m.history[(m.cycle - this.followDelay) % 600] let history = m.history[(m.cycle - this.followDelay) % 600]
Matter.Body.setPosition(this, { Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
x: history.position.x,
y: history.position.y - history.yOff + 24.2859
}) //bullets move with player
} }
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
b.setDynamoBotDelay() b.setDynamoBotDelay()
}, },
nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.nailBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.nailBot()`);
const me = bullet.length; const me = bullet.length;
const dir = m.angle; const dir = m.angle;
const RADIUS = (12 + 4 * Math.random()) const RADIUS = (12 + 4 * Math.random())
@@ -5386,8 +5142,8 @@ const b = {
// lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20, // lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20,
lastLookCycle: simulation.cycle + 60 * Math.random(), lastLookCycle: simulation.cycle + 60 * Math.random(),
delay: Math.floor((tech.isNailBotUpgrade ? 18 : 85) * b.fireCDscale), delay: Math.floor((tech.isNailBotUpgrade ? 18 : 85) * b.fireCDscale),
acceleration: 0.005 * (1 + 0.5 * Math.random()), acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100,
endCycle: Infinity, endCycle: Infinity,
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
@@ -5433,8 +5189,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.missileBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.missileBot()`);
const me = bullet.length; const me = bullet.length;
bullet[me] = Bodies.rectangle(position.x, position.y, 28, 11, { bullet[me] = Bodies.rectangle(position.x, position.y, 28, 11, {
botType: "missile", botType: "missile",
@@ -5504,8 +5260,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.foamBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.foamBot()`);
const me = bullet.length; const me = bullet.length;
const dir = m.angle; const dir = m.angle;
const RADIUS = (10 + 5 * Math.random()) const RADIUS = (10 + 5 * Math.random())
@@ -5524,8 +5280,8 @@ const b = {
fireCount: 0, fireCount: 0,
fireLimit: 5 + 2 * tech.isFoamBotUpgrade, fireLimit: 5 + 2 * tech.isFoamBotUpgrade,
delay: Math.floor((145 + (tech.isFoamBotUpgrade ? 0 : 230)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade, 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()), acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move
endCycle: Infinity, endCycle: Infinity,
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
@@ -5625,8 +5381,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
soundBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { soundBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.soundBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.soundBot()`);
const me = bullet.length; const me = bullet.length;
const dir = m.angle; const dir = m.angle;
bullet[me] = Bodies.rectangle(position.x, position.y, 12, 30, { bullet[me] = Bodies.rectangle(position.x, position.y, 12, 30, {
@@ -5644,8 +5400,8 @@ const b = {
fireCount: 0, fireCount: 0,
fireLimit: 5 + 2 * tech.isSoundBotUpgrade, fireLimit: 5 + 2 * tech.isSoundBotUpgrade,
delay: Math.floor((120 + (tech.isSoundBotUpgrade ? 0 : 70)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade, delay: Math.floor((120 + (tech.isSoundBotUpgrade ? 0 : 70)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
acceleration: 0.005 * (1 + 0.5 * Math.random()), acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move
endCycle: Infinity, endCycle: Infinity,
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
@@ -5791,11 +5547,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
laserBot(position = { laserBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
x: player.position.x + 50 * (Math.random() - 0.5), // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.laserBot()`);
y: player.position.y + 50 * (Math.random() - 0.5)
}, isConsole = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.laserBot()`);
const me = bullet.length; const me = bullet.length;
const dir = m.angle; const dir = m.angle;
const RADIUS = (14 + 6 * Math.random()) const RADIUS = (14 + 6 * Math.random())
@@ -5833,10 +5586,7 @@ const b = {
const mag = Math.min(farAway, 4) * this.mass * this.acceleration const mag = Math.min(farAway, 4) * this.mass * this.acceleration
this.force = Vector.mult(Vector.normalise(Vector.sub(playerPos, this.position)), mag) this.force = Vector.mult(Vector.normalise(Vector.sub(playerPos, this.position)), mag)
//manual friction to not lose rotational velocity //manual friction to not lose rotational velocity
Matter.Body.setVelocity(this, { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 });
x: this.velocity.x * 0.95,
y: this.velocity.y * 0.95
});
//find targets //find targets
if (!(simulation.cycle % this.lookFrequency)) { if (!(simulation.cycle % this.lookFrequency)) {
this.lockedOn = null; this.lockedOn = null;
@@ -5858,11 +5608,13 @@ const b = {
} }
} }
//randomize position relative to player //randomize position relative to player
if (Math.random() < 0.15) { if (Math.random() < 0.1) {
const range = 110 + 4 * b.totalBots() if (isKeep) {
this.offPlayer = { const range = 110 + 4 * b.totalBots()
x: range * (Math.random() - 0.5), this.offPlayer = { x: range * (Math.random() - 0.5), y: range * (Math.random() - 0.5) - 20, }
y: range * (Math.random() - 0.5) - 20, } else {
const range = 110 + 4 * b.totalBots() + 100 * Math.random()
this.offPlayer = Vector.mult(Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random()), range)
} }
} }
} }
@@ -6040,11 +5792,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
boomBot(position = { boomBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
x: player.position.x + 50 * (Math.random() - 0.5), // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.boomBot()`);
y: player.position.y + 50 * (Math.random() - 0.5)
}, isConsole = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.boomBot()`);
const me = bullet.length; const me = bullet.length;
const dir = m.angle; const dir = m.angle;
const RADIUS = (7 + 2 * Math.random()) const RADIUS = (7 + 2 * Math.random())
@@ -6059,9 +5808,9 @@ const b = {
dmg: 0, dmg: 0,
minDmgSpeed: 0, minDmgSpeed: 0,
lookFrequency: 43 + Math.floor(7 * Math.random()) - 13 * tech.isBoomBotUpgrade, lookFrequency: 43 + Math.floor(7 * Math.random()) - 13 * tech.isBoomBotUpgrade,
acceleration: 0.005 * (1 + 0.5 * Math.random()), acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
attackAcceleration: 0.012 + 0.006 * tech.isBoomBotUpgrade, attackAcceleration: 0.012 + 0.006 * tech.isBoomBotUpgrade,
range: 500 * (1 + 0.1 * Math.random()) + 350 * tech.isBoomBotUpgrade, range: 500 * (1 + 0.1 * Math.random()) + 350 * tech.isBoomBotUpgrade + !isKeep * 100,
endCycle: Infinity, endCycle: Infinity,
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
@@ -6131,8 +5880,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.plasmaBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.plasmaBot()`);
const me = bullet.length; const me = bullet.length;
const dir = m.angle; const dir = m.angle;
const RADIUS = 21 const RADIUS = 21
@@ -6305,8 +6054,8 @@ const b = {
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
orbitBot(position = player.position, isConsole = true) { orbitBot(position = player.position, isKeep = true) {
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.orbitBot()`); // if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.orbitBot()`);
const me = bullet.length; const me = bullet.length;
bullet[me] = Bodies.polygon(position.x, position.y, 9, 12, { bullet[me] = Bodies.polygon(position.x, position.y, 9, 12, {
isUpgraded: tech.isOrbitBotUpgrade, isUpgraded: tech.isOrbitBotUpgrade,
@@ -6316,6 +6065,7 @@ const b = {
frictionAir: 1, frictionAir: 1,
isStatic: true, isStatic: true,
isSensor: true, isSensor: true,
isKeep: isKeep,
restitution: 0, restitution: 0,
dmg: 0, // 0.14 //damage done in addition to the damage from momentum dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 0, minDmgSpeed: 0,
@@ -6330,17 +6080,17 @@ const b = {
//reorder orbital bot positions around a circle //reorder orbital bot positions around a circle
let totalOrbitalBots = 0 let totalOrbitalBots = 0
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'orbit' && bullet[i] !== this) totalOrbitalBots++ if (bullet[i].botType === 'orbit' && bullet[i] !== this && bullet[i].isKeep) totalOrbitalBots++
} }
let index = 0 let index = 0
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'orbit' && bullet[i] !== this) { if (bullet[i].botType === 'orbit' && bullet[i] !== this && bullet[i].isKeep) {
bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI
index++ index++
} }
} }
}, },
range: 190 + 130 * tech.isOrbitBotUpgrade, //range is set in bot upgrade too! range: 190 + 130 * tech.isOrbitBotUpgrade + !isKeep * 60 * (0.5 - Math.random()), //range is set in bot upgrade too!
orbitalSpeed: 0, orbitalSpeed: 0,
phase: 2 * Math.PI * Math.random(), phase: 2 * Math.PI * Math.random(),
do() { do() {
@@ -6377,10 +6127,7 @@ const b = {
} }
//orbit player //orbit player
const time = simulation.cycle * this.orbitalSpeed + this.phase const time = simulation.cycle * this.orbitalSpeed + this.phase
const orbit = { const orbit = { x: Math.cos(time), y: Math.sin(time) }
x: Math.cos(time),
y: Math.sin(time) //*1.1
}
Matter.Body.setPosition(this, Vector.add(m.pos, Vector.mult(orbit, this.range))) //bullets move with player Matter.Body.setPosition(this, Vector.add(m.pos, Vector.mult(orbit, this.range))) //bullets move with player
} }
}) })
@@ -6392,11 +6139,11 @@ const b = {
//reorder orbital bot positions around a circle //reorder orbital bot positions around a circle
let totalOrbitalBots = 0 let totalOrbitalBots = 0
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'orbit') totalOrbitalBots++ if (bullet[i].botType === 'orbit' && bullet[i].isKeep) totalOrbitalBots++
} }
let index = 0 let index = 0
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'orbit') { if (bullet[i].botType === 'orbit' && bullet[i].isKeep) {
bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI
index++ index++
} }
@@ -6739,7 +6486,7 @@ const b = {
name: "shotgun", //1 name: "shotgun", //1
// description: `fire a wide <strong>burst</strong> of short range <strong> bullets</strong><br>with a low <strong><em>fire rate</em></strong><br><strong>3-4</strong> nails per ${powerUps.orb.ammo()}`, // description: `fire a wide <strong>burst</strong> of short range <strong> bullets</strong><br>with a low <strong><em>fire rate</em></strong><br><strong>3-4</strong> nails per ${powerUps.orb.ammo()}`,
descriptionFunction() { descriptionFunction() {
return `fire a wide <strong>burst</strong> of short range <strong> bullets</strong><br>has a slow <strong><em>fire rate</em></strong><br><strong>${this.ammoPack.toFixed(1)}</strong> nails per ${powerUps.orb.ammo()}` return `fire a wide <strong>burst</strong> of short range <strong> bullets</strong><br>has a slow <strong><em>fire rate</em></strong><br><strong>${this.ammoPack.toFixed(1)}</strong> shots per ${powerUps.orb.ammo()}`
}, },
ammo: 0, ammo: 0,
ammoPack: 3.5, ammoPack: 3.5,
@@ -7995,7 +7742,6 @@ const b = {
} }
//fire //fire
if ((!input.fire && this.charge > 0.6)) { if ((!input.fire && this.charge > 0.6)) {
// tech.harpoonDensity = 0.0065 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
const where = { const where = {
x: m.pos.x + 30 * Math.cos(m.angle), x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle) y: m.pos.y + 30 * Math.sin(m.angle)
@@ -8067,8 +7813,6 @@ const b = {
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.03 : 0.06) const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.03 : 0.06)
player.force.x -= recoil.x player.force.x -= recoil.x
player.force.y -= recoil.y player.force.y -= recoil.y
// tech.harpoonDensity = 0.0065 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1 const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
const thrust = 0.15 * (this.charge) const thrust = 0.15 * (this.charge)
if (tech.extraHarpoons) { if (tech.extraHarpoons) {
@@ -8263,12 +8007,8 @@ const b = {
count++ count++
if (!(count % delay) && this.ammo > 0) { if (!(count % delay) && this.ammo > 0) {
this.ammo-- this.ammo--
b.harpoon({ b.harpoon({ x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, null, angle, harpoonSize, true, totalCycles)
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}, null, angle, harpoonSize, true, totalCycles)
angle += SPREAD angle += SPREAD
tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
} }
if (count < num * delay && m.alive) requestAnimationFrame(harpoonDelay); if (count < num * delay && m.alive) requestAnimationFrame(harpoonDelay);
} }
@@ -8298,7 +8038,6 @@ const b = {
} else { } else {
b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles) b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles)
} }
tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
} }
m.fireCDcycle = m.cycle + 5 + 35 * b.fireCDscale + 60 * (m.energy < 0.05) + tech.extraHarpoons // cool down is set when harpoon bullet returns to player m.fireCDcycle = m.cycle + 5 + 35 * b.fireCDscale + 60 * (m.energy < 0.05) + tech.extraHarpoons // cool down is set when harpoon bullet returns to player
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.015 : 0.035) const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.015 : 0.035)

View File

@@ -967,7 +967,6 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
startExperiment() { //start playing the game after exiting the experiment menu startExperiment() { //start playing the game after exiting the experiment menu
build.isExperimentSelection = false; build.isExperimentSelection = false;
spawn.setSpawnList(); //gives random mobs, not starter mobs spawn.setSpawnList(); //gives random mobs, not starter mobs
spawn.setSpawnList();
if (b.inventory.length > 0) { if (b.inventory.length > 0) {
b.activeGun = b.inventory[0] //set first gun to active gun b.activeGun = b.inventory[0] //set first gun to active gun
b.inventoryGun = 0; b.inventoryGun = 0;

View File

@@ -11,7 +11,7 @@ const level = {
// playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"], // playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
//see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later //see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"], playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave"], communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo"],
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"], trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
levels: [], levels: [],
start() { start() {
@@ -19,17 +19,15 @@ const level = {
// simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// tech.giveTech("performance") // tech.giveTech("performance")
// level.difficultyIncrease(5 * 4) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(8 * 2) //30 is near max on hard //60 is near max on why
// spawn.setSpawnList(); // m.maxHealth = m.health = 1
// spawn.setSpawnList();
// m.maxHealth = m.health = 100
// m.maxEnergy = m.energy = 10000000 // m.maxEnergy = m.energy = 10000000
// tech.isRerollDamage = true // tech.isRerollDamage = true
// powerUps.research.changeRerolls(99999) // powerUps.research.changeRerolls(99999)
// m.immuneCycle = Infinity //you can't take damage // m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100 // tech.tech[297].frequency = 100
// m.couplingChange(10) // m.couplingChange(10)
// m.setField("grappling hook") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook // m.setField("metamaterial cloaking") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// tech.isHookWire = true // tech.isHookWire = true
// m.energy = 0 // m.energy = 0
// simulation.molecularMode = 2 // simulation.molecularMode = 2
@@ -37,22 +35,23 @@ const level = {
// b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.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 // b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("MACHO") }); // requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") });
// for (let i = 0; i < 1; ++i) tech.giveTech("degenerate matter") // for (let i = 0; i < 1; ++i) tech.giveTech("Higgs mechanism")
// for (let i = 0; i < 1; ++i) tech.giveTech("reel") // for (let i = 0; i < 1; ++i) tech.giveTech("topological defect")
// for (let i = 0; i < 1; ++i) tech.giveTech("tokamak") // for (let i = 0; i < 1; ++i) tech.giveTech("Hilbert space")
// requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") }); // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") });
// for (let i = 0; i < 1; i++) tech.giveTech("laser-bot upgrade") // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) });
// for (let i = 0; i < 1; ++i) tech.giveTech("rupture")
// for (let i = 0; i < 1; i++) tech.giveTech("cascading failure")
// for (let i = 0; i < 1; ++i) tech.giveTech("induction furnace")
// for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense") // for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense")
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); // for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling");
// level.skyscrapers();
// level.unchartedCave();
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500) // for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
// for (let i = 0; i < 5; ++i) spawn.starter(1900, -500) // for (let i = 0; i < 10; ++i) spawn.starter(1900, -500, 50)
// for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500) // for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500)
// spawn.beetleBoss(1900, -500, 25) // spawn.beetleBoss(1900, -500, 25)
// spawn.slasher2(2000, -1150) // spawn.slasher2(2000, -1150)
@@ -64,13 +63,14 @@ const level = {
// for (let i = 0; i < 40; ++i) tech.giveTech() // for (let i = 0; i < 40; ++i) tech.giveTech()
level[simulation.isTraining ? "walk" : "intro"]() //normal starting level ************************************************** level[simulation.isTraining ? "walk" : "intro"]() //normal starting level **************************************************
// spawn.bodyRect(2425, -120, 200, 200); // spawn.bodyRect(2425, -120, 200, 200);
// console.log(body[body.length - 1].mass) // console.log(body[body.length - 1].mass)
// simulation.isAutoZoom = false; //look in close // simulation.isAutoZoom = false; //look in close
// simulation.zoomScale *= 0.5; // simulation.zoomScale *= 0.5;
// simulation.setZoom(); // simulation.setZoom();
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "boost"); // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "boost");
// for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo"); // for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo");
// for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false); // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false);
//lore testing //lore testing
@@ -2159,8 +2159,9 @@ const level = {
spawn.mapRect(475, -25, 25, 50); //edge shelf spawn.mapRect(475, -25, 25, 50); //edge shelf
}, },
intro() { intro() {
// console.log(level.levelsCleared)
if (level.levelsCleared === 0) { //if this is the 1st level of the game if (level.levelsCleared === 0) { //if this is the 1st level of the game
if (simulation.difficultyMode > 2) spawn.setSpawnList() // hard and why difficulty don't begin with starter mobs
//wait to spawn power ups until unpaused //wait to spawn power ups until unpaused
//power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode //power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode
const goal = simulation.cycle + 10 const goal = simulation.cycle + 10
@@ -2172,10 +2173,17 @@ const level = {
} else { } else {
powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125); powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125);
} }
if (simulation.difficultyMode < 5) { if (simulation.difficultyMode < 5) { //hard, normal and easy
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false); powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
}
if (simulation.difficultyMode < 3) { //normal and easy
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false); powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); //not on why difficulty }
if (simulation.difficultyMode < 2) { //easy
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
} }
} else { } else {
requestAnimationFrame(cycle); requestAnimationFrame(cycle);
@@ -2548,7 +2556,6 @@ const level = {
if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run
// spawn.setSpawnList();
spawn.pickList.splice(0, 1); spawn.pickList.splice(0, 1);
spawn.pickList.push('starter'); spawn.pickList.push('starter');
spawn.pickList.splice(0, 1); spawn.pickList.splice(0, 1);
@@ -2662,6 +2669,7 @@ const level = {
if (gateButton.isUp) { if (gateButton.isUp) {
gateButton.query(); gateButton.query();
if (!gateButton.isUp) { if (!gateButton.isUp) {
simulation.makeTextLog(`station gate opened`, 360);
if (stationNumber > 0) { if (stationNumber > 0) {
if (!isExitOpen && gatesOpenRight < stationNumber) level.newLevelOrPhase() //run some new level tech effects if (!isExitOpen && gatesOpenRight < stationNumber) level.newLevelOrPhase() //run some new level tech effects
gatesOpenRight = stationNumber gatesOpenRight = stationNumber
@@ -2673,7 +2681,7 @@ const level = {
gatesOpenRight = stationNumber gatesOpenRight = stationNumber
} }
if (Math.abs(stationNumber) > 0 && ((Math.abs(stationNumber) + 1) % stationList.length) === 0) { if (Math.abs(stationNumber) > 0 && ((Math.abs(stationNumber) + 1) % stationList.length) === 0) {
simulation.makeTextLog(`exit opened`); simulation.makeTextLog(`level exit opened`, 360);
isExitOpen = true; isExitOpen = true;
} }
} }
@@ -2725,13 +2733,12 @@ const level = {
var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20 var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
} }
} }
spawn.mapRect(x + -1500, -210, 3000, 400);//station floor spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
spawn.mapRect(x + -1775, -1600, 3400, 1100); //center pillar spawn.mapRect(x + -1775, -1600, 3400, 1000); //center pillar
spawn.mapRect(x + -4100, -3325, 8000, 700); //roof spawn.mapRect(x + -4100, -3325, 8000, 700); //roof
spawn.mapRect(x + -4100, -3325, 325, 1500); spawn.mapRect(x + -4100, -3325, 325, 1500);
spawn.mapRect(x + 3500, -3325, 400, 1500); spawn.mapRect(x + 3500, -3325, 400, 1500);
spawn.mapRect(x + -225, -575, 450, 425); //lower portal blocks spawn.mapRect(x + -225, -700, 450, 600); //lower portal blocks
//upper parts //upper parts
spawn.mapRect(x + -1425, -2400, 1900, 50); spawn.mapRect(x + -1425, -2400, 1900, 50);
@@ -3025,7 +3032,7 @@ const level = {
} }
}, },
() => { //portal fling () => { //portal fling
const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2083 },] const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2080 },]
const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
if (isExitOpen) { if (isExitOpen) {
level.exit.x = buttonsCoords[buttonsCoordsIndex].x; level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
@@ -3219,7 +3226,7 @@ const level = {
} }
}, },
() => { //jump pads and 6 sided platforms () => { //jump pads and 6 sided platforms
const buttonsCoords = [{ x: x + 275, y: -1817 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2420 }, { x: x - 2100, y: -1995 }] const buttonsCoords = [{ x: x + 278, y: -1814 }, { x: x + 778, y: -1814 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2425 }, { x: x - 2100, y: -1995 }]
const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
if (isExitOpen) { if (isExitOpen) {
level.exit.x = buttonsCoords[buttonsCoordsIndex].x; level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
@@ -3375,7 +3382,7 @@ const level = {
} }
}, },
] ]
// stations[1]() //for testing a specific station // stations[4]() //for testing a specific station
stations[stationList[Math.abs(stationNumber % stationList.length)]]() //*************** run this one when uploading stations[stationList[Math.abs(stationNumber % stationList.length)]]() //*************** run this one when uploading
//add in standard station map infrastructure //add in standard station map infrastructure
spawn.mapRect(x + -8000, 0, 16000, 800);//tunnel floor spawn.mapRect(x + -8000, 0, 16000, 800);//tunnel floor
@@ -5034,10 +5041,12 @@ const level = {
powerUps.directSpawn(x + 1950, y - 1525, "ammo"); powerUps.directSpawn(x + 1950, y - 1525, "ammo");
powerUps.directSpawn(x + 1900, y - 1525, "ammo"); powerUps.directSpawn(x + 1900, y - 1525, "ammo");
spawn.hopMotherBoss(x + 800, y + -2200) spawn.hopMotherBoss(x + 800, y + -2200)
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600) for (let i = 0; i < 4; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600) for (let i = 0; i < 4; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
spawn.hopper(x + 1550, y + -775); spawn.hopper(x + 1550, y + -775);
spawn.hopper(x + 500, y + -775); spawn.hopper(x + 500, y + -775);
spawn.hopper(x + 500, y + -2200);
spawn.hopper(x + 1100, y + -2200);
spawn.hopMother(x + 1400, y + -775); spawn.hopMother(x + 1400, y + -775);
spawn.hopMother(x + 550, y + -775); spawn.hopMother(x + 550, y + -775);
spawn.hopMother(x + 525, y + -1475); spawn.hopMother(x + 525, y + -1475);
@@ -30084,9 +30093,6 @@ const level = {
}, },
unchartedCave() { unchartedCave() {
simulation.makeTextLog(`<strong>unchartedCave</strong> by <span class='color-var'>3xionDev</span>`); simulation.makeTextLog(`<strong>unchartedCave</strong> by <span class='color-var'>3xionDev</span>`);
//lore.unlockTesting();
//simulation.enableConstructMode();
level.difficultyIncrease(15);
level.setPosToSpawn(0, -50); //normal spawn level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 20985; level.exit.x = 20985;
level.exit.y = 2816; level.exit.y = 2816;
@@ -30095,7 +30101,6 @@ const level = {
level.defaultZoom = 1900 level.defaultZoom = 1900
simulation.zoomTransition(level.defaultZoom) simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#979797"; document.body.style.backgroundColor = "#979797";
// color.map = "#444" //custom map color
spawn.randomMob(1000, -975, 0); spawn.randomMob(1000, -975, 0);
spawn.randomMob(2550, -575, 0); spawn.randomMob(2550, -575, 0);
@@ -30490,15 +30495,462 @@ const level = {
spawn.randomGroup(5835, -532, 0.4); spawn.randomGroup(5835, -532, 0.4);
if (simulation.difficulty > 1) spawn.randomLevelBoss(18823, 2191); if (simulation.difficulty > 1) spawn.randomLevelBoss(18823, 2191);
spawn.secondaryBossChance(20217, 1913) spawn.secondaryBossChance(20217, 1913)
level.custom = () => { level.custom = () => {
level.exit.drawAndCheck(); level.exit.drawAndCheck();
level.enter.draw(); level.enter.draw();
}; };
}, },
dojo() { // By weird_pusheen
simulation.makeTextLog(`<strong>dojo</strong> by <span class='color-var'>werid_pusheen</span>, fixed by <span class='color-var'>Cornbread 2100</span>`)
const vanishes = [];
const smoofes = [];
const leftRotor = level.rotor(-550, 900, 950, 25);
leftRotor.frictionAir = 0.01;
var leftSchwoof = level.boost(-20, -60, -2000);
var rightSchwoof = level.button(2550, -50);
var rightSchwoofState = false;
var rightSchwoofLive = true;
spawn.mapRect(2513, -39, 200, 100);
var pathPoints = [
[0, 0], // Index 0 is owned by M and is set to M's position during play
// this means that occasionally the boss will bonk M on the way to somewhere else, which gives it a chance to hurt M and gives the player a chance to hurt it
[250, -750], /* Left bases */
[250, -2500],
[350, -1500], // Left doorway
[1150, -1500], // Home base
[1150, -2750], // Upper base
[1950, -1500], // Right doorway
[2050, -750], /* Right bases */
[2050, -2500],
[-150, -250], // Left porthole
];
function isntIn(point, array) {
for (var x = 0; x < array.length; x++) {
if (point[0] == array[x][0] && point[1] == array[x][1]) {
return false;
}
}
return true;
}
function isObstructed(v1, v2) {
var ret = Matter.Query.ray(map,
{
x: v1[0],
y: v1[1],
},
{
x: v2[0],
y: v2[1]
}).length != 0;
return ret; // Kinda-ish stolen from mob.js
}
function pythag(p1, p2) {
var dx = p1[0] - p2[0];
var dy = p1[1] - p2[1];
return Math.sqrt(dx * dx + dy * dy);
}
var path = undefined; // This is a stupid way to go about pathfinding code. I might even clean it up!
function pathFind(goalPoint, startPoint, curPath = []) {
var myPoint = startPoint;
if (curPath.length) {
myPoint = curPath[curPath.length - 1];
}
if (path && (curPath.length >= path.length)) { // If we've already found a shorter or equal path, no reason to continue and waste CPU time
return; // Minimizes for HOP COUNT, not PATH LENGTH - path length was buggy
}
if (!isObstructed(myPoint, goalPoint)) { // If the line to the goal point ain't blocked by a map object, we've arrived!
path = [...curPath];
path.push(goalPoint);
return;
}
pathPoints.forEach(testPoint => {
if (isntIn(testPoint, curPath)) { // If it's reusing points, there's clearly something wrong
if (!isObstructed(myPoint, testPoint)) { // If the line to the test point ain't blocked by a map object
var thing = [...curPath];
thing.push(testPoint);
pathFind(goalPoint, startPoint, thing); // Branch to a valid test point
}
}
});
}
level.setPosToSpawn(1200, 500);
level.exit.x = 51500;
level.exit.y = -1875;
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.defaultZoom = 1500;
simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#d8dadf";
spawn.mapRect(-500, 0, 3300, 300); // Floor
spawn.mapRect(-100, -3000, 2500, 100); // Ceiling
spawn.mapRect(-200, -3000, 100, 2600); // Left wall
spawn.mapRect(2400, -3000, 100, 3000); // Right wall
spawn.mapRect(500, -1000, 100, 500); /* obstruction blocks */
smoofes.push(map[map.length - 1]);
spawn.mapRect(500, -2500, 100, 500);
smoofes.push(map[map.length - 1]);
spawn.mapRect(1700, -1000, 100, 500);
smoofes.push(map[map.length - 1]);
spawn.mapRect(1700, -2500, 100, 500);
smoofes.push(map[map.length - 1]);
spawn.mapRect(-1000, 550, 200, 50); // Left chonky stepppp low
spawn.mapRect(-800, 300, 200, 50); // Left chonky stepppp high
spawn.mapVertex(-1000, 1200, "0 0 100 0 700 500 700 700 0 700"); // Left chonky
spawn.mapRect(3100, 550, 200, 50); // Right chonky stepppp low
spawn.mapRect(2900, 300, 200, 50); // Right chonky stepppp high
spawn.mapVertex(3300, 1200, "0 0 -100 0 -700 500 -700 700 0 700"); // Right chonky
const leftElevator = level.elevator(-1400 - 300, 1450, 300, 100, 500);
const rightElevator = level.elevator(-1400 + 5100, 1450, 300, 100, 500);
spawn.mapRect(-150, -1700, 200, 50);
spawn.mapRect(400, -2050, 200, 50);
spawn.mapRect(1600, -1000, 200, 50);
spawn.randomMob(1200, 700);
spawn.randomMob(600, 1000);
spawn.randomMob(1800, 1000);
spawn.randomMob(3200, 400);
spawn.randomMob(3000, 200);
spawn.randomMob(-900, 400);
spawn.randomMob(-700, 200);
spawn.randomMob(1200, 1000);
for (var i = 0; i < 4; i++) {
spawn.randomSmallMob(Math.random() * 600 - 600, Math.random() * 3000 - 400);
}
spawn.grenadier(-300, -1000);
spawn.grenadier(2600, -1000);
spawn.mapRect(-1400, 1450, 5100, 100); // The True Floor
const slime = level.hazard(-1250, 1400, 4800, 50);
slime.maxHeight = 600;
simulation.draw.body = function () {
ctx.beginPath();
for (let i = 0, len = body.length; i < len; ++i) {
if (!body[i].hidden) {
let vertices = body[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
}
}
ctx.lineWidth = 2;
ctx.fillStyle = color.block;
ctx.fill();
ctx.strokeStyle = color.blockS;
ctx.stroke();
} // Override the old draw code to allow intelligent hiding of blocks - preferably this becomes official code because it's just a single added if statement and makes a lot of things cleaner and more intelligent
const vanish = function (x, y, width, height) { // normal vanishes don't work well on my map for some reason, so I rewrote
x += width / 2;
y += height / 2;
const getVertices = function (bX, bY, bW, bH) { return [{ x: bX, y: bY, index: 0, isInternal: false }, { x: bX + bW, y: bY, index: 1, isInternal: false }, { x: bX + bW, y: bY + bH, index: 4, isInternal: false }, { x: bX, y: bY + bH, index: 3, isInternal: false }] };
const cMask = cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
const vertices = getVertices(x, y, width, height);
const block = body[body.length] = Bodies.fromVertices(x, y, vertices, {
collisionFilter: {
category: cat.map,
mask: cMask
},
isNoSetCollision: true,
inertia: Infinity, //prevents rotation
isNotHoldable: true,
isNonStick: true, //this keep sporangium from sticking
isTouched: false,
cWidth: width,
hiddenCycle: 0,
isStatic: true,
query() {
if (this.cWidth <= 0) {
if (this.cWidth > -100) {
this.cWidth = -100;
Matter.Body.setVertices(this, vertices);
}
this.isTouched = false;
this.collisionFilter.mask = undefined;
this.hidden = true;
this.hiddenCycle++;
if (this.hiddenCycle > 100) {
if (Matter.Query.collides(this, [player]).length) {
this.hiddenCycle = 50;
}
else {
this.hiddenCycle = 0;
this.cWidth = width;
this.collisionFilter.mask = cMask;
this.hidden = false;
}
}
}
else if (this.isTouched) {
Matter.Body.setVertices(this, getVertices(x, y, this.cWidth, height * (this.cWidth / width)));
this.cWidth -= 3;
}
else if (Matter.Query.collides(this, [player]).length) { // Elseif short circuit avoids expensive collision detection
this.isTouched = true;
}
}
});
return block;
};
vanishes.push(vanish(800, 800, 800, 50));
vanishes.push(vanish(400, 1100, 400, 50));
vanishes.push(vanish(1600, 1100, 400, 50));
for (const vanishBlock of vanishes) Composite.add(engine.world, vanishBlock);
spawn.bodyRect(1700, 812, 300, 25, 1, {
collisionFilter: {
category: cat.body,
mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.map
},
isNoSetCollision: true,
isNotHoldable: true,
isNonStick: true, //this keep sporangium from sticking
restitution: 1,
friction: 0,
frictionAir: 0,
frictionStatic: 0,
query() {
Matter.Body.setAngularVelocity(this, 0);
Matter.Body.applyForce(this, this.position, {
x: 0,
y: -(this.position.y - 812) * 0.002
});
}
});
const zigzag = body[body.length - 1];
Matter.Body.applyForce(zigzag, zigzag.position, {
x: 0.1,
y: 0
});
var buttonWasDown = false;
level.customTopLayer = () => {
}
level.custom = () => {
rightSchwoof.isUp = false;
level.exit.drawAndCheck();
leftSchwoof.query();
level.enter.draw();
pathPoints[0][0] = m.pos.x;
pathPoints[0][1] = m.pos.y;
leftElevator.move();
rightElevator.move();
slime.query();
zigzag.query();
slime.levelRise(0.2);
for (var i = 0; i < vanishes.length; i++) {
vanishes[i].query();
}
if (!rightSchwoofState) {
var math = m.pos.y < leftRotor.position.y;
Matter.Body.setAngularVelocity(leftRotor, (math ? 1 : -1) * Math.PI / 45);
}
if (rightSchwoofLive) {
rightSchwoof.query();
rightSchwoof.draw();
if (rightSchwoofState) {
ctx.fillStyle = "lightgreen";
}
else {
ctx.fillStyle = "red";
}
ctx.beginPath();
ctx.arc(2615, -220, 40, 0, Math.PI * 2);
ctx.fill();
}
if (rightSchwoof.isUp) {
buttonWasDown = true;
}
else if (buttonWasDown) {
buttonWasDown = false;
rightSchwoofState = !rightSchwoofState;
}
if (Matter.Query.collides(player, smoofes).length) {
Matter.Body.applyForce(player, player.position, {
x: 0,
y: -0.015
});
}
};
mobs.spawn(500, -500, 10, 100, "yellow"); /* TacticalBoss
Modes:
Spawn:
Pathfinds to a point above M and starts dropping mobs. Learns which mobs to drop to cause the most damage, of course.
Occasionally strikes at M.
Hide:
Pathfinds to the point furthest from M
Strike:
Pathfind really, really fast to M
Recharge:
Stop moving for a bit to "recharge" (this is so the player has a chance to hit it)
It must always Hide or Recharge after Spawning or Striking. Which one it does is based on some factor I'll figure out.
Pathfinding is a hypersimplified algorithm with hard-coded "points" that it can travel between. M is one of these.
*/
var boss = mob[mob.length - 1];
boss.isBoss = true;
boss.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
boss.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y);
level.exit.x = 2560;
level.exit.y = -90;
rightSchwoofLive = false;
};
var spawnables = {};
["hopper", "stabber", "springer", "striker", "sneaker", "grower"].forEach((m) => { /* Used to be spawn.fullPickList, but some of those mobs don't do collision-only damage and would thus never be properly selected for */
if (spawn[m]) {
spawnables[m] = {
fun: spawn[m],
name: m,
weight: 1
}
}
});
boss.stabCycle = 0;
boss.spawnCycle = 0;
function spawny() {
var totalWeight = 0;
Object.keys(spawnables).forEach(key => {
totalWeight += spawnables[key].weight;
});
var cursorWeight = 0;
var choice = Math.random();
var mC = undefined;
Object.values(spawnables).forEach((thing) => {
var lower = cursorWeight / totalWeight;
cursorWeight += thing.weight;
var upper = cursorWeight / totalWeight;
if ((choice > lower && choice <= upper) || !mC) {
mC = thing;
}
});
mC.fun(boss.position.x, boss.position.y);
var sp = mob[mob.length - 1];
sp.typeName = mC.name;
sp.onHit = () => {
spawnables[sp.typeName].weight += 1;
};
var oldFun = sp.onDeath;
sp.onDeath = () => { /* Mobs that die are worth less */
oldFun.call(sp);
spawnables[sp.typeName].weight -= 0.3; /* But not too much less */
};
}
boss.spawnDelay = 40;
boss.mode = "hide";
boss.modeSwitch = -1; // Randomize mode immediately
boss.damageReduction = 0.1;
var oldOnHit = boss.onHit;
boss.onHit = () => {
boss.modeSwitch = -1; // After striking the player, always switch modes
oldOnHit.call(boss); //this is the line that is bugging <-----
};
boss.do = () => {
path = undefined;
var pfGoal = [0, 0];
boss.modeSwitch--;
if (boss.modeSwitch < 0) {
if (!boss.isShielded) {
spawn.shield(boss, boss.position.x, boss.position.y, 0.75); // Every time the mode switches, have a 75% chance to gain a new shield
}
if (boss.mode == "hide" || boss.mode == "recharge") {
if (Math.random() > 0.5) {
boss.mode = "spawn";
}
else {
boss.mode = "strike";
}
boss.modeSwitch = 600;
}
else {
if (boss.mode == "strike") {
boss.mode = "hide"; // Always hides after striking
}
else {
if (Math.random() > 0.5) {
boss.mode = "hide";
}
else {
boss.mode = "recharge"; // same when it goes into recharge mode
spawn.shield(boss, boss.position.x, boss.position.y, 1);
}
}
boss.modeSwitch = 200;
}
}
if (boss.mode == "hide") { /* Find the furthest point from M and get to it */
var longest = 0;
pathPoints.forEach(item => {
if (item[0] == 1150) {
return;
}
var iL = pythag(item, [m.pos.x, m.pos.y]);
if (iL > longest) {
longest = iL;
pfGoal = item;
}
});
}
else if (boss.mode == "strike") {
pfGoal = pathPoints[0]; // Target M
}
else if (boss.mode == "spawn") {
pfGoal = pathPoints[4]; // Go to Home Base to spawn
}
if (boss.mode != "recharge") {
if (m.pos.x > 2350 || m.pos.x < -150 || m.pos.y > 50) {
boss.mode = "hide";
}
pathFind(pfGoal, [boss.position.x, boss.position.y]);
if (!path) {
return; // If it couldn't pathfind, just drift
}
var goalX = path[0][0];
var goalY = path[0][1];
var dX = goalX - boss.position.x;
var dY = goalY - boss.position.y;
var hyp = Math.sqrt(dX * dX + dY * dY);
Matter.Body.applyForce(boss, {
x: goalX,
y: goalY
}, {
x: dX / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1),
y: dY / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1)// - 0.005
});
}
if (boss.mode == "spawn") {
boss.stabCycle++;
if (boss.stabCycle > 25) {
if (Math.abs(dX) < 200 && dY > 0) {
Matter.Body.applyForce(boss, {
x: player.position.x,
y: player.position.y
}, {
x: 0,
y: 5
});
}
boss.stabCycle = 0;
}
boss.spawnCycle++;
if (boss.spawnCycle > boss.spawnDelay) {
spawny();
boss.spawnDelay += 4;
boss.spawnCycle = 0;
}
}
};
boss.showHealthBar = true;
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
// ******************************************************************************************************** // ********************************************************************************************************
// ******************************************************************************************************** // ********************************************************************************************************
// ***************************************** training levels ********************************************** // ***************************************** training levels **********************************************

View File

@@ -242,7 +242,7 @@ const mobs = {
deathCount: 0, deathCount: 0,
mobSpawnWithHealth: 1, mobSpawnWithHealth: 1,
setMobSpawnHealth() { setMobSpawnHealth() {
mobs.mobSpawnWithHealth = 0.89 ** (tech.mobSpawnWithHealth) mobs.mobSpawnWithHealth = 0.88 ** (tech.mobSpawnWithHealth)
}, },
//********************************************************************************************** //**********************************************************************************************
//********************************************************************************************** //**********************************************************************************************
@@ -1133,6 +1133,85 @@ const mobs = {
if ((!this.isShielded || isBypassShield) && this.alive) { if ((!this.isShielded || isBypassShield) && this.alive) {
if (dmg !== Infinity) { if (dmg !== Infinity) {
dmg *= tech.damageFromTech() dmg *= tech.damageFromTech()
if (this.isDropPowerUp) {
if (this.health === 1) {
if (tech.isMobFullHealth) {
dmg *= 1.55
simulation.ephemera.push({
name: "damage outline",
count: 5, //cycles before it self removes
vertices: this.vertices,
do() {
this.count--
if (this.count < 0) simulation.removeEphemera(this.name)
//draw body
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
ctx.strokeStyle = `#f05` //"rgba(150,150,225,0.5)";
ctx.stroke();
},
})
} else if (tech.isMobFullHealthCloak) {
dmg *= 1.88
simulation.ephemera.push({
name: "damage outline",
count: 7, //cycles before it self removes
vertices: this.vertices,
do() {
this.count--
if (this.count < 0) simulation.removeEphemera(this.name)
//draw body
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.fillStyle = `rgba(255,0,100,0.15)` //"rgba(150,150,225,0.5)";
ctx.fill()
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
ctx.strokeStyle = `#f08` //"rgba(150,150,225,0.5)";
ctx.stroke();
},
})
}
} else if (tech.isMobLowHealth && this.health < 0.25) {
dmg *= 3.22
simulation.ephemera.push({
name: "damage outline",
count: 2, //cycles before it self removes
vertices: this.vertices,
do() {
this.count--
if (this.count < 0) simulation.removeEphemera(this.name)
//draw body
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.fillStyle = `rgba(255,50,100,0.2)` //"rgba(150,150,225,0.5)";
ctx.fill()
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
ctx.strokeStyle = `#f38` //"rgba(150,150,225,0.5)";
ctx.stroke();
},
})
}
}
//mobs specific damage changes //mobs specific damage changes
if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 33% dmg at max range of 3000 if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 33% dmg at max range of 3000
dmg *= this.damageReduction dmg *= this.damageReduction
@@ -1143,6 +1222,7 @@ const mobs = {
} }
dmg /= Math.sqrt(this.mass) dmg /= Math.sqrt(this.mass)
} }
this.health -= dmg this.health -= dmg
//this.fill = this.color + this.health + ')'; //this.fill = this.color + this.health + ')';
this.onDamage(dmg); //custom damage effects this.onDamage(dmg); //custom damage effects
@@ -1187,7 +1267,7 @@ const mobs = {
leaveBody: true, leaveBody: true,
isDropPowerUp: true, isDropPowerUp: true,
death() { death() {
if (tech.collidePowerUps && Math.random() < tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups if (tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups
this.onDeath(this); //custom death effects this.onDeath(this); //custom death effects
this.removeConsBB(); this.removeConsBB();
this.alive = false; //triggers mob removal in mob[i].replace(i) this.alive = false; //triggers mob removal in mob[i].replace(i)
@@ -1261,22 +1341,23 @@ const mobs = {
} }
if (tech.isBotSpawnerReset) { if (tech.isBotSpawnerReset) {
for (let i = 0, len = bullet.length; i < len; i++) { for (let i = 0, len = bullet.length; i < len; i++) {
if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 780 //13 seconds if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 900 //15 seconds
} }
} }
if (Math.random() < tech.botSpawner) { if (Math.random() < tech.botSpawner) {
b.randomBot(this.position, false) b.randomBot(this.position, false)
bullet[bullet.length - 1].endCycle = simulation.cycle + 780 //13 seconds bullet[bullet.length - 1].endCycle = simulation.cycle + 900 //15 seconds
this.leaveBody = false; // no body since it turned into the bot this.leaveBody = false; // no body since it turned into the bot
} }
if (tech.isAddRemoveMaxHealth) { if (tech.isAddRemoveMaxHealth) {
if (this.isBoss && this.isDropPowerUp) { if (this.isBoss && this.isDropPowerUp) {
powerUps.spawn(this.position.x + 20, this.position.y, "tech", false) powerUps.spawn(this.position.x + 20, this.position.y, "tech", false)
powerUps.spawn(this.position.x - 20, this.position.y, "ammo", false) powerUps.spawn(this.position.x - 20, this.position.y, "research", false)
powerUps.spawn(this.position.x - 40, this.position.y, "research", false)
powerUps.spawn(this.position.x + 40, this.position.y, "research", false)
powerUps.spawn(this.position.x, this.position.y + 20, "research", false) powerUps.spawn(this.position.x, this.position.y + 20, "research", false)
powerUps.spawn(this.position.x, this.position.y - 20, "heal", false) powerUps.spawn(this.position.x, this.position.y - 20, "heal", false)
powerUps.spawn(this.position.x - 40, this.position.y, "ammo", false) powerUps.spawn(this.position.x, this.position.y + 40, "heal", false)
powerUps.spawn(this.position.x, this.position.y + 40, "research", false)
powerUps.spawn(this.position.x, this.position.y - 40, "heal", false) powerUps.spawn(this.position.x, this.position.y - 40, "heal", false)
} else { } else {
const amount = 0.005 const amount = 0.005
@@ -1292,7 +1373,7 @@ const mobs = {
} }
} }
if (tech.cloakDuplication && !this.isBoss) { if (tech.cloakDuplication && !this.isBoss) {
tech.cloakDuplication -= 0.02 tech.cloakDuplication -= 0.01
powerUps.setPowerUpMode(); //needed after adjusting duplication chance powerUps.setPowerUpMode(); //needed after adjusting duplication chance
} }
} else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) { } else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) {

View File

@@ -393,7 +393,7 @@ const m = {
for (let i = 0, len = b.inventory.length; i < len; i++) { for (let i = 0, len = b.inventory.length; i < len; i++) {
if (b.guns[b.inventory[i]].ammo !== Infinity) b.guns[b.inventory[i]].ammo = Math.max(0, Math.floor(ammoCount / b.inventory.length * b.guns[b.inventory[i]].ammoPack * (1.15 + 0.3 * (Math.random() - 0.5)))) if (b.guns[b.inventory[i]].ammo !== Infinity) b.guns[b.inventory[i]].ammo = Math.max(0, Math.floor(ammoCount / b.inventory.length * b.guns[b.inventory[i]].ammoPack * (1.15 + 0.3 * (Math.random() - 0.5))))
} }
console.log(b.activeGun) // console.log(b.activeGun)
//randomize tech //randomize tech
for (let i = 0; i < totalTech; i++) { for (let i = 0; i < totalTech; i++) {
//find what tech I could get //find what tech I could get
@@ -568,7 +568,7 @@ const m = {
if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4) if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1 if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0193, 0.88) //capped at speed of 55 if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0193, 0.88) //capped at speed of 55
if (tech.isHarmReduce && input.field) dmg *= 0.15 if (tech.isHarmReduce && input.field) dmg *= 0.12
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05 if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots() if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
@@ -935,83 +935,6 @@ const m = {
ctx.restore(); ctx.restore();
} }
}, },
// resetSkin() {
// simulation.isAutoZoom = true;
// m.yOffWhen.jump = 70
// m.yOffWhen.stand = 49
// m.yOffWhen.crouch = 22
// m.isAltSkin = false
// m.color = {
// hue: 0,
// sat: 0,
// light: 100,
// }
// m.setFillColors();
// m.draw = function () {
// ctx.fillStyle = m.fillColor;
// m.walk_cycle += m.flipLegs * m.Vx;
// ctx.save();
// ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
// ctx.translate(m.pos.x, m.pos.y);
// m.calcLeg(Math.PI, -3);
// m.drawLeg("#4a4a4a");
// m.calcLeg(0, 0);
// m.drawLeg("#333");
// ctx.rotate(m.angle);
// ctx.beginPath();
// ctx.arc(0, 0, 30, 0, 2 * Math.PI);
// ctx.fillStyle = m.bodyGradient
// ctx.fill();
// ctx.arc(15, 0, 4, 0, 2 * Math.PI);
// ctx.strokeStyle = "#333";
// ctx.lineWidth = 2;
// ctx.stroke();
// ctx.restore();
// m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
// powerUps.boost.draw()
// }
// m.drawLeg = function (stroke) {
// // if (simulation.mouseInGame.x > m.pos.x) {
// if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
// m.flipLegs = 1;
// } else {
// m.flipLegs = -1;
// }
// ctx.save();
// ctx.scale(m.flipLegs, 1); //leg lines
// ctx.beginPath();
// ctx.moveTo(m.hip.x, m.hip.y);
// ctx.lineTo(m.knee.x, m.knee.y);
// ctx.lineTo(m.foot.x, m.foot.y);
// ctx.strokeStyle = stroke;
// ctx.lineWidth = 7;
// ctx.stroke();
// //toe lines
// ctx.beginPath();
// ctx.moveTo(m.foot.x, m.foot.y);
// ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
// ctx.moveTo(m.foot.x, m.foot.y);
// ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
// ctx.lineWidth = 4;
// ctx.stroke();
// //hip joint
// ctx.beginPath();
// ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
// //knee joint
// ctx.moveTo(m.knee.x + 7, m.knee.y);
// ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
// //foot joint
// ctx.moveTo(m.foot.x + 6, m.foot.y);
// ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
// ctx.fillStyle = m.fillColor;
// ctx.fill();
// ctx.lineWidth = 2;
// ctx.stroke();
// ctx.restore();
// }
// },
skin: { skin: {
none() { none() {
m.isAltSkin = true m.isAltSkin = true
@@ -1146,6 +1069,96 @@ const m = {
ctx.restore(); ctx.restore();
} }
}, },
strokeGap() {
m.isAltSkin = true
m.yOffWhen.stand = 52
m.yOffWhen.jump = 72
// m.yOffWhen.crouch = 22
// m.color = {
// hue: 184,
// sat: 0,
// light: 55,
// }
// m.setFillColors();
m.draw = function () {
m.walk_cycle += m.flipLegs * m.Vx;
ctx.save();
ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
ctx.translate(m.pos.x, m.pos.y);
m.calcLeg(Math.PI, -1.25);
m.drawLeg("#606070");
m.calcLeg(0, 0);
m.drawLeg("#445");
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
// ctx.arc(0, 0, 30, m.angle + 1, m.angle - 1);
ctx.fillStyle = "#fff"//m.bodyGradient
ctx.fill();
ctx.beginPath();
const arc = 0.7 + 0.17 * Math.sin(m.cycle * 0.012)
ctx.arc(0, 0, 30, -arc, arc, true); //- Math.PI / 2
ctx.strokeStyle = "#445";
ctx.lineWidth = 2;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(13, 0)
ctx.lineTo(20, 0)
// ctx.beginPath();
// ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.lineWidth = 5;
ctx.strokeStyle = "#445";
ctx.stroke();
ctx.restore();
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
powerUps.boost.draw()
}
m.drawLeg = function (stroke) {
// if (simulation.mouseInGame.x > m.pos.x) {
if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
m.flipLegs = 1;
} else {
m.flipLegs = -1;
}
ctx.save();
ctx.scale(m.flipLegs, 1); //leg lines
ctx.beginPath();
ctx.moveTo(m.hip.x, m.hip.y);
ctx.lineTo(m.knee.x, m.knee.y);
ctx.lineTo(m.foot.x, m.foot.y);
ctx.strokeStyle = stroke;
ctx.lineWidth = 5;
ctx.stroke();
//toe lines
ctx.beginPath();
ctx.moveTo(m.foot.x, m.foot.y);
ctx.lineTo(m.foot.x - 14, m.foot.y + 5);
ctx.moveTo(m.foot.x, m.foot.y);
ctx.lineTo(m.foot.x + 14, m.foot.y + 5);
ctx.lineWidth = 4;
ctx.stroke();
//hip joint
ctx.beginPath();
ctx.arc(m.hip.x, m.hip.y, 8, 0, 2 * Math.PI);
//knee joint
ctx.moveTo(m.knee.x + 4, m.knee.y);
ctx.arc(m.knee.x, m.knee.y, 4, 0, 2 * Math.PI);
//foot joint
ctx.moveTo(m.foot.x + 4, m.foot.y + 1);
ctx.arc(m.foot.x, m.foot.y + 1, 4, 0, 2 * Math.PI);
ctx.fillStyle = m.fillColor;
ctx.fill();
ctx.lineWidth = 2;
ctx.stroke();
ctx.restore();
}
},
energy() { energy() {
m.isAltSkin = true m.isAltSkin = true
m.color = { m.color = {
@@ -1333,17 +1346,9 @@ const m = {
sat: 14, sat: 14,
light: 65, light: 65,
} }
// m.setFillColors();
m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)` m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 50}%)` m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 50}%)`
// let grd = ctx.createLinearGradient(-30, 0, 30, 0);
const grd = ctx.createRadialGradient(16, 0, 0, 0, 0, 40); const grd = ctx.createRadialGradient(16, 0, 0, 0, 0, 40);
// grd.addColorStop(0, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
// grd.addColorStop(0.25, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 20}%)`);
// grd.addColorStop(0.5, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
// grd.addColorStop(1, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 10}%)`);
grd.addColorStop(0, `#c78034`); grd.addColorStop(0, `#c78034`);
grd.addColorStop(0.04, `#bd5235`); grd.addColorStop(0.04, `#bd5235`);
grd.addColorStop(0.08, `#ab554d`); grd.addColorStop(0.08, `#ab554d`);
@@ -1369,10 +1374,8 @@ const m = {
grd.addColorStop(0.92, `#00e19b`); grd.addColorStop(0.92, `#00e19b`);
grd.addColorStop(0.96, `#19f5aa`); grd.addColorStop(0.96, `#19f5aa`);
grd.addColorStop(1, `#aaf5af`); grd.addColorStop(1, `#aaf5af`);
m.bodyGradient = grd m.bodyGradient = grd
m.draw = function () { m.draw = function () {
ctx.fillStyle = m.fillColor; ctx.fillStyle = m.fillColor;
m.walk_cycle += m.flipLegs * m.Vx; m.walk_cycle += m.flipLegs * m.Vx;
@@ -1410,7 +1413,7 @@ const m = {
ctx.lineTo(m.knee.x, m.knee.y); ctx.lineTo(m.knee.x, m.knee.y);
ctx.lineTo(m.foot.x, m.foot.y); ctx.lineTo(m.foot.x, m.foot.y);
ctx.strokeStyle = stroke; ctx.strokeStyle = stroke;
ctx.lineWidth = 7; ctx.lineWidth = 5;
ctx.stroke(); ctx.stroke();
//toe lines //toe lines
@@ -1424,21 +1427,22 @@ const m = {
//hip joint //hip joint
ctx.beginPath(); ctx.beginPath();
ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI); ctx.arc(m.hip.x, m.hip.y, 9, 0, 2 * Math.PI);
ctx.fillStyle = "#1b85cf"; ctx.fillStyle = "#222";
// ctx.fillStyle = "#1b85cf";
ctx.fill(); ctx.fill();
//knee joint //knee joint
ctx.beginPath(); ctx.beginPath();
ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI); ctx.arc(m.knee.x, m.knee.y, 5, 0, 2 * Math.PI);
ctx.fillStyle = "#ffa050"; // ctx.fillStyle = "#ffa050";
ctx.fill(); ctx.fill();
//foot joint //foot joint
ctx.beginPath(); ctx.beginPath();
ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI); ctx.arc(m.foot.x, m.foot.y, 4, 0, 2 * Math.PI);
ctx.fillStyle = "#878cf0"; // ctx.fillStyle = "#878cf0";
ctx.fill(); ctx.fill();
ctx.lineWidth = 2; // ctx.lineWidth = 3;
ctx.stroke(); // ctx.stroke();
ctx.restore(); ctx.restore();
} }
}, },
@@ -2636,7 +2640,7 @@ const m = {
}, },
fieldUpgrades: [{ fieldUpgrades: [{
name: "field emitter", name: "field emitter",
imageNumber: Math.floor(Math.random() * 23), imageNumber: Math.floor(Math.random() * 26), //pick one of the 25 field emitter image files at random
description: `<em>initial field</em><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs and <strong>throw</strong> <strong class='color-block'>blocks</strong> description: `<em>initial field</em><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs and <strong>throw</strong> <strong class='color-block'>blocks</strong>
<br>generate <strong>4</strong> <strong class='color-f'>energy</strong> per second`, // <br><strong>100</strong> max <strong class='color-f'>energy</strong> <br>generate <strong>4</strong> <strong class='color-f'>energy</strong> per second`, // <br><strong>100</strong> max <strong class='color-f'>energy</strong>
effect: () => { effect: () => {
@@ -2934,7 +2938,6 @@ const m = {
// if (m.energy < m.fieldRegen) m.fieldCDcycle = m.cycle + 90; // if (m.energy < m.fieldRegen) m.fieldCDcycle = m.cycle + 90;
// } // }
if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
m.grabPowerUp(); m.grabPowerUp();
m.lookForPickUp(); m.lookForPickUp();
@@ -3998,7 +4001,7 @@ const m = {
}, },
{ {
name: "metamaterial cloaking", name: "metamaterial cloaking",
description: "<strong>+50%</strong> <strong class='color-defense'>defense</strong> while <strong class='color-cloaked'>cloaked</strong><br>after <strong class='color-cloaked'>decloaking</strong> <strong>+333%</strong> <strong class='color-d'>damage</strong> for <strong>2</strong> s<br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", description: "<strong>+66%</strong> <strong class='color-defense'>defense</strong> while <strong class='color-cloaked'>cloaked</strong><br>after <strong class='color-cloaked'>decloaking</strong> <strong>+333%</strong> <strong class='color-d'>damage</strong> for <strong>2</strong> s<br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second",
effect: () => { effect: () => {
m.fieldFire = true; m.fieldFire = true;
m.fieldMeterColor = "#333"; m.fieldMeterColor = "#333";
@@ -4013,29 +4016,6 @@ const m = {
m.walk_cycle -= m.flipLegs * m.Vx; m.walk_cycle -= m.flipLegs * m.Vx;
m.pos.x += 4 m.pos.x += 4
m.draw(); m.draw();
// let history = m.history[(m.cycle - 1) % 600]
// m.pos.x = history.position.x
// m.pos.y = history.position.y + m.yPosDifference - history.yOff
// m.pos.x += 4
// ctx.fillStyle = m.fillColor;
// ctx.save();
// ctx.translate(m.pos.x, m.pos.y);
// m.calcLeg(Math.PI, -3);
// m.drawLeg("#ccc");
// m.calcLeg(0, 0);
// m.drawLeg("#ccc");
// ctx.rotate(m.angle);
// ctx.beginPath();
// ctx.arc(0, 0, 30, 0, 2 * Math.PI);
// ctx.fillStyle = "#fff"
// ctx.fill();
// ctx.arc(15, 0, 4, 0, 2 * Math.PI);
// ctx.strokeStyle = "#333";
// ctx.lineWidth = 2;
// ctx.stroke();
// ctx.restore()
} }
m.drawCloak = function () { m.drawCloak = function () {
m.fieldPhase += 0.007 m.fieldPhase += 0.007
@@ -4067,27 +4047,27 @@ const m = {
} }
//not shooting (or using field) enable cloak //not shooting (or using field) enable cloak
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing if (m.fireCDcycle + 10 < m.cycle && !input.fire) { //automatically cloak if not firing
const drain = 0.02 const drain = 0.02
if (!m.isCloak && m.energy > drain + 0.03) { if (!m.isCloak && m.energy > drain + 0.03) {
m.energy -= drain m.energy -= drain
m.isCloak = true //enter cloak m.isCloak = true //enter cloak
m.fieldHarmReduction = 0.5; m.fieldHarmReduction = 0.33; //66% reduction
m.enterCloakCycle = m.cycle m.enterCloakCycle = m.cycle
if (tech.isCloakHealLastHit && m.lastHit > 0) { if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy) const heal = Math.min(0.75 * m.lastHit, m.energy)
if (m.energy > heal) { // if (m.energy > heal) {
m.energy -= heal // m.energy -= heal * 0.8
m.addHealth(heal); //heal from last hit m.addHealth(heal); //heal from last hit
m.lastHit = 0 m.lastHit = 0
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x, x: m.pos.x,
y: m.pos.y, y: m.pos.y,
radius: Math.sqrt(heal) * 200, radius: Math.sqrt(heal) * 200,
color: "rgba(0,255,200,0.6)", color: "rgba(0,255,200,0.6)",
time: 16 time: 16
}); });
} // }
} }
if (tech.isIntangible) { if (tech.isIntangible) {
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
@@ -4133,9 +4113,16 @@ const m = {
m.fieldRange = m.fieldRange * 0.85 + 130 m.fieldRange = m.fieldRange * 0.85 + 130
m.fieldDrawRadius = m.fieldRange * 1.1 //* 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy)); m.fieldDrawRadius = m.fieldRange * 1.1 //* 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak() m.drawCloak()
ctx.globalCompositeOperation = "lighter"; // ctx.globalCompositeOperation = "lighter";
m.drawCloakedM() // m.drawCloakedM()
ctx.globalCompositeOperation = "source-over"; // ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 35, 0, 2 * Math.PI);
ctx.strokeStyle = "rgba(255,255,255,0.25)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
ctx.lineWidth = 10
ctx.stroke();
} else if (m.fieldRange < 4000) { } else if (m.fieldRange < 4000) {
m.fieldRange += 90 m.fieldRange += 90
m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy)); m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
@@ -4148,8 +4135,8 @@ const m = {
if (inPlayer.length > 0) { if (inPlayer.length > 0) {
for (let i = 0; i < inPlayer.length; i++) { for (let i = 0; i < inPlayer.length; i++) {
if (m.energy > 0) { if (m.energy > 0) {
if (!inPlayer[i].isUnblockable) m.energy -= 0.007; if (!inPlayer[i].isUnblockable) m.energy -= 0.003;
if (inPlayer[i].shield) m.energy -= 0.025; if (inPlayer[i].shield) m.energy -= 0.011;
} }
} }
} }
@@ -4158,10 +4145,17 @@ const m = {
} }
} }
this.drawRegenEnergyCloaking() this.drawRegenEnergyCloaking()
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
ctx.globalCompositeOperation = "multiply"; const timeLeft = (m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) - m.cycle) * 0.5
m.drawCloakedM() ctx.beginPath();
ctx.globalCompositeOperation = "source-over"; ctx.arc(m.pos.x, m.pos.y, 32, 0, 2 * Math.PI);
ctx.strokeStyle = "rgba(180,30,70,0.5)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
ctx.lineWidth = Math.max(Math.min(10, timeLeft), 3);
ctx.stroke();
// ctx.globalCompositeOperation = "multiply";
// m.drawCloakedM()
// ctx.globalCompositeOperation = "source-over";
} }
} }
} }

View File

@@ -534,26 +534,24 @@ const powerUps = {
if (!tech.isEnergyHealth && m.alive) { if (!tech.isEnergyHealth && m.alive) {
powerUps.animatePowerUpGrab('rgba(0, 238, 187,0.25)') powerUps.animatePowerUpGrab('rgba(0, 238, 187,0.25)')
let heal = (this.size / 40 / (simulation.healScale ** 0.25)) ** 2 //simulation.healScale is undone here because heal scale is already properly affected on m.addHealth() let heal = (this.size / 40 / (simulation.healScale ** 0.25)) ** 2 //simulation.healScale is undone here because heal scale is already properly affected on m.addHealth()
// console.log("size = " + this.size, "heal = " + heal)
if (heal > 0) { if (heal > 0) {
const overHeal = m.health + heal * simulation.healScale - m.maxHealth //used with tech.isOverHeal const overHeal = m.health + heal * simulation.healScale - m.maxHealth //used with tech.isOverHeal
const healOutput = Math.min(m.maxHealth - m.health, heal) * simulation.healScale const healOutput = Math.min(m.maxHealth - m.health, heal) * simulation.healScale
m.addHealth(heal); m.addHealth(heal);
if (healOutput > 0) simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(healOutput).toFixed(3)}`) // <br>${m.health.toFixed(3)} if (healOutput > 0) simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(healOutput).toFixed(3)}`) // <br>${m.health.toFixed(3)}
if (tech.isOverHeal && overHeal > 0) { //tech quenching if (tech.isOverHeal && overHeal > 0) { //tech quenching
const scaledOverHeal = overHeal // * 0.9 m.damage(overHeal);
m.damage(scaledOverHeal); simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>-=</span> ${(overHeal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>-=</span> ${(scaledOverHeal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x, x: m.pos.x,
y: m.pos.y, y: m.pos.y,
radius: scaledOverHeal * 500 * simulation.healScale, radius: overHeal * 500 * simulation.healScale,
color: simulation.mobDmgColor, color: simulation.mobDmgColor,
time: simulation.drawTime time: simulation.drawTime
}); });
tech.extraMaxHealth += scaledOverHeal * simulation.healScale //increase max health tech.extraMaxHealth += overHeal * Math.sqrt(simulation.healScale) //increase max health
m.setMaxHealth(); m.setMaxHealth();
} else if (overHeal > 0.1) { } else if (overHeal > 0.13) { //if leftover heals spawn a new spammer heal power up
requestAnimationFrame(() => { requestAnimationFrame(() => {
powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
}); });

View File

@@ -1272,7 +1272,7 @@ const simulation = {
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isDropPowerUp && mob[i].alive) count++ if (mob[i].isDropPowerUp && mob[i].alive) count++
} }
count *= 0.17 //to fake the chance, this makes it not random, and maybe less confusing count *= 0.22 //to fake the 20% chance, this makes it not random, and more predictable
let cycle = () => { //run after waiting a cycle for the map to be cleared let cycle = () => { //run after waiting a cycle for the map to be cleared
const types = ["heal", "ammo", "heal", "ammo", "research", "coupling", "boost", "tech", "gun", "field"] const types = ["heal", "ammo", "heal", "ammo", "research", "coupling", "boost", "tech", "gun", "field"]
for (let i = 0; i < count; i++) powerUps.spawnDelay(types[Math.floor(Math.random() * types.length)], 1) for (let i = 0; i < count; i++) powerUps.spawnDelay(types[Math.floor(Math.random() * types.length)], 1)

View File

@@ -200,7 +200,7 @@ const spawn = {
for (let i = 0, len = mob.length; i < len; ++i) { for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isShielded) { if (mob[i].alive && !mob[i].isShielded) {
if (Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius < this.radius) { if (Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius < this.radius) {
mob[i].damage(0.02 * m.dmgScale); mob[i].damage(0.025 * m.dmgScale);
// mob[i].locatePlayer();// // mob[i].locatePlayer();//
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
@@ -366,7 +366,7 @@ const spawn = {
me.maxMobs = 400 me.maxMobs = 400
me.mode = [{ me.mode = [{
name: "boulders", name: "boulders",
spawnRate: 170 - 6 * simulation.difficultyMode, spawnRate: Math.max(30, 170 - 5 * simulation.difficultyMode),
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.boulder(me.position.x, me.position.y + 250) me.boulder(me.position.x, me.position.y + 250)
@@ -374,10 +374,11 @@ const spawn = {
}, },
enter() { }, enter() { },
exit() { }, exit() { },
}, { },
{
name: "mobs", name: "mobs",
// whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)], // whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
spawnRate: 280 - 20 * simulation.difficultyMode, spawnRate: Math.max(60, 240 - 20 * simulation.difficultyMode),
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.torque += 0.000015 * me.inertia; //spin me.torque += 0.000015 * me.inertia; //spin
@@ -397,7 +398,7 @@ const spawn = {
}, },
{ {
name: "hoppers", name: "hoppers",
spawnRate: 480 - 16 * simulation.difficultyMode, spawnRate: Math.max(90, 480 - 16 * simulation.difficultyMode),
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.torque += 0.00002 * me.inertia; //spin me.torque += 0.00002 * me.inertia; //spin
@@ -422,7 +423,7 @@ const spawn = {
}, },
{ {
name: "seekers", name: "seekers",
spawnRate: 100 - 3 * simulation.difficultyMode, spawnRate: Math.max(15, 100 - 3 * simulation.difficultyMode),
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
const index = Math.floor((me.cycle % 360) / 60) const index = Math.floor((me.cycle % 360) / 60)
@@ -440,7 +441,7 @@ const spawn = {
{ {
name: "mines", name: "mines",
bombCycle: 0, bombCycle: 0,
bombInterval: 10 - simulation.difficultyMode, bombInterval: Math.max(2, 10 - simulation.difficultyMode),
do() { do() {
const yOff = 120 const yOff = 120
this.bombCycle++ this.bombCycle++
@@ -498,7 +499,7 @@ const spawn = {
}, },
{ {
name: "orbiters", name: "orbiters",
spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode), spawnRate: Math.ceil(Math.max(2, 5 - 0.2 * simulation.difficultyMode)),
orbitersCycle: 0, orbitersCycle: 0,
do() { do() {
this.orbitersCycle++ this.orbitersCycle++
@@ -522,7 +523,7 @@ const spawn = {
this.fadeCycle++ this.fadeCycle++
if (this.fadeCycle > 0) { if (this.fadeCycle > 0) {
me.torque += this.spinForce * me.inertia; //spin //0.00000015 me.torque += this.spinForce * me.inertia; //spin //0.00000015
if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset if (this.fadeCycle > 360) this.fadeCycle = -200 + simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
ctx.strokeStyle = "#50f"; ctx.strokeStyle = "#50f";
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
ctx.lineWidth = 1.5; ctx.lineWidth = 1.5;
@@ -561,7 +562,7 @@ const spawn = {
{ {
name: "black hole", name: "black hole",
eventHorizon: 0, eventHorizon: 0,
eventHorizonRadius: 1900, eventHorizonRadius: 1700,
eventHorizonCycle: 0, eventHorizonCycle: 0,
do() { do() {
this.eventHorizonCycle++ this.eventHorizonCycle++
@@ -629,15 +630,121 @@ const spawn = {
spawn.shield(me, me.position.x, me.position.y, 1); spawn.shield(me, me.position.x, me.position.y, 1);
}, },
exit() { this.waveCycle = 0 }, exit() { this.waveCycle = 0 },
},
{
name: "slow zone",
waveCycle: 0,
whereX: simulation.isHorizontalFlipped ? -3000 : 3000,
width: 1200,
// isActive: false,
cycle: 0,
cycleDuration: 150,
zone: 0,
isMovingRight: true,
playerSlowTime: 0,
do() {
// console.log(zone)
this.cycle++
if (this.cycle % this.cycleDuration === 0) { //next zone
this.zone += this.isMovingRight ? 1 : -1
if (this.zone > 0) this.isMovingRight = false
if (this.zone < -1) this.isMovingRight = true
this.whereX = (simulation.isHorizontalFlipped ? -3000 : 3000) + this.width * this.zone
}
//draw slow zone
if (this.cycle % this.cycleDuration > 0.45 * this.cycleDuration) {
ctx.fillStyle = `rgba(0, 100, 255, ${0.19 + 0.015 * Math.sin(simulation.cycle * 0.36)})`;
ctx.fillRect(this.whereX, -1500, this.width, 1500);
//check for player in range and apply slow debuff
if (player.position.x > this.whereX && player.position.x < this.whereX + this.width) {
this.playerSlowTime = 180
//damage player
const dmg = 0.0001 * simulation.dmgScale
m.damage(dmg);
}
} else { //show where slow zone is about to show up
ctx.fillStyle = `rgba(0, 100, 255, ${0.2 + 0.25 * Math.random()})`;
ctx.fillRect(this.whereX, -1500, this.width, 12);
ctx.fillRect(this.whereX, -12, this.width, 12);
}
if (this.playerSlowTime > 0) {
this.playerSlowTime-- //warm up player when outside of slow zone
//slow player
// Matter.Body.setVelocity(player, Vector.mult(player.velocity, (1 - 0.01 * this.playerSlowTime)));
// Matter.Body.setVelocity(player, { x: (1 - 0.01 * this.playerSlowTime) * player.velocity.x, y: (1 - 0.0025 * this.playerSlowTime) * player.velocity.y }); //makes the player get stuck slow when walking horizontally
Matter.Body.setVelocity(player, { x: Math.max(0.05, 1 - 0.01 * Math.max(10, this.playerSlowTime)) * player.velocity.x, y: Math.max(0.2, 1 - 0.0025 * this.playerSlowTime) * player.velocity.y });
//draw effect on player
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 45, 0, 2 * Math.PI);
ctx.fillStyle = `rgba(0,100,255,${(0.003 * Math.max(10, this.playerSlowTime))})`;
ctx.fill();
}
},
enter() {
},
exit() { },
},
{
name: "antigravity",
cycle: 0,
startCycle: 420,
totalCycles: 600,
rectX: simulation.isHorizontalFlipped ? -5400 : -150, //for positioning graphics
do() {
this.cycle++
if (this.cycle > this.totalCycles) this.cycle = 0
if (this.cycle === this.startCycle) {
//initial push up
for (let i = 0, len = body.length; i < len; ++i) {
body[i].force.y -= 0.05 * body[i].mass
}
for (let i = 0, len = powerUp.length; i < len; ++i) {
powerUp[i].force.y -= 0.07 * powerUp[i].mass
}
for (let i = 0, len = bullet.length; i < len; ++i) {
bullet[i].force.y -= 0.05 * bullet[i].mass
}
for (let i = 0, len = mob.length; i < len; ++i) {
mob[i].force.y -= 0.15 * mob[i].mass
}
player.force.y -= 0.04 * player.mass
} else if (this.cycle > this.startCycle) { //antigravity
for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
body[i].force.y -= simulation.g * body[i].mass
Matter.Body.setVelocity(body[i], Vector.mult(body[i].velocity, 0.98)); //friction
}
for (let i = 0, len = powerUp.length; i < len; ++i) {
powerUp[i].force.y -= simulation.g * powerUp[i].mass
}
// for (let i = 0, len = bullet.length; i < len; ++i) {
// bullet[i].force.y -= simulation.g * bullet[i].mass
// Matter.Body.setVelocity(bullet[i], Vector.mult(bullet[i].velocity, 0.98)); //friction
// }
// for (let i = 0, len = mob.length; i < len; ++i) {
// mob[i].force.y -= 0.7 * simulation.g * mob[i].mass
// }
player.force.y -= simulation.g * player.mass //g = 0.0024
Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.985)); //friction
//graphics
ctx.fillStyle = `rgba(0, 0, 0, ${0.03 + 0.03 * Math.random()})`;
ctx.fillRect(this.rectX, -1500, 5650, 1500); //cover everything
} else if (this.cycle > this.startCycle - 60) {
//graphical warning of antigravity
ctx.fillStyle = `rgba(0, 0, 0, ${0.2 + 0.25 * Math.random()})`;
ctx.fillRect(this.rectX, -25, 5650, 25); //cover floor
}
},
enter() { spawn.shield(me, me.position.x, me.position.y, 1); },
exit() { this.cycle = 0 },
}, },
// { // {
// name: "__", // name: "__",
// do() {}, // do() { },
// enter() {}, // enter() { },
// exit() {}, // exit() { },
// }, // },
] ]
shuffle(me.mode); //THIS SHOULDN'T BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! shuffle(me.mode); //THIS SHOULD NOT BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
me.do = function () { me.do = function () {
this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)` this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
if (this.health < 1) { if (this.health < 1) {
@@ -648,7 +755,8 @@ const spawn = {
this.damageReductionDecay(); this.damageReductionDecay();
for (let i = 0; i < this.totalModes; i++) this.mode[i].do() for (let i = 0; i < this.totalModes; i++) this.mode[i].do()
} }
// this.mode[5].do() //deelete this // this.mode[10].do() //comment out this
// console.log(this.mode[9].name)
// this.cycle++; // this.cycle++;
// this.mode[4].do() // this.mode[4].do()
// this.mode[7].do() // this.mode[7].do()
@@ -719,7 +827,7 @@ const spawn = {
} }
} }
Matter.Body.setDensity(me, 0.003); //normal is 0.001 Matter.Body.setDensity(me, 0.003); //normal is 0.001
me.timeLeft = 360; me.timeLeft = 300;
me.g = 0.0005; //required if using this.gravity me.g = 0.0005; //required if using this.gravity
me.frictionAir = 0.005; me.frictionAir = 0.005;
me.friction = 1; me.friction = 1;
@@ -740,6 +848,12 @@ const spawn = {
this.torque += this.spin; this.torque += this.spin;
this.gravity(); this.gravity();
this.timeLimit(); this.timeLimit();
if (this.timeLeft < 60) {
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.explodeRange, 0, 2 * Math.PI);
ctx.fillStyle = `rgba(255,255,255,0.15)`;
ctx.fill();
}
}; };
} }
me.orbitalNoVelocity = function (who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss me.orbitalNoVelocity = function (who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
@@ -2502,7 +2616,7 @@ const spawn = {
spawn.hopBullet(this.position.x, this.position.y) spawn.hopBullet(this.position.x, this.position.y)
this.death(); this.death();
} }
if (Matter.Query.collides(this, [player]).length > 0) this.isExploding = true if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) this.isExploding = true
if (this.isExploding) { if (this.isExploding) {
if (this.countDown-- < 0) { //explode if (this.countDown-- < 0) { //explode
this.death(); this.death();
@@ -2538,7 +2652,7 @@ const spawn = {
// me.isBadTarget = true; // me.isBadTarget = true;
me.isMobBullet = true; me.isMobBullet = true;
me.showHealthBar = false; me.showHealthBar = false;
me.timeLeft = 1140 + Math.floor(480 * Math.random()); me.timeLeft = 1020 + Math.floor(480 * Math.random());
me.isRandomMove = Math.random() < 0.3 //most chase player, some don't me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
me.accelMag = 0.01; //jump height me.accelMag = 0.01; //jump height
@@ -2547,7 +2661,7 @@ const spawn = {
me.friction = 1 me.friction = 1
me.frictionStatic = 1 me.frictionStatic = 1
me.restitution = 0; me.restitution = 0;
me.delay = 130 + 60 * simulation.CDScale; me.delay = 120 + 60 * simulation.CDScale;
// Matter.Body.rotate(me, Math.random() * Math.PI); // Matter.Body.rotate(me, Math.random() * Math.PI);
me.collisionFilter.category = cat.mobBullet; me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet; me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
@@ -3673,12 +3787,54 @@ const spawn = {
} else if (c < -threshold) { } else if (c < -threshold) {
this.torque -= turn; this.torque -= turn;
} }
const flapArc = 0.7 //don't go past 1.57 for normal flaps
const flapArc = 0.7 //don't go past 1.57 for normal flaps
ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)"; ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
} }
// else { //flocking behavior (not working yet)
// this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
// this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
// //set direction to turn to fire
// if (!(simulation.cycle % this.seePlayerFreq)) {
// //find nearest mob and maintain a distance
// let nearestMob = null
// let nearestMobDistance = Infinity
// for (let i = 0; i < mob.length; i++) {
// const newMobDistance = Vector.magnitude(Vector.sub(this.position, mob[i].position))
// if (mob[i].isDropPowerUp && mob[i].alive && newMobDistance < nearestMobDistance) { //&& !mob[i].isBoss
// nearestMobDistance = newMobDistance
// nearestMob = mob[i]
// }
// }
// if (nearestMob) {
// // console.log(nearestMob)
// this.fireDir = Vector.normalise(Vector.sub(nearestMob.position, this.position));
// //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
// const mod = (a, n) => {
// return a - Math.floor(a / n) * n
// }
// const sub = Vector.sub(nearestMob.position, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
// const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
// if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
// }
// }
// //rotate towards fireDir
// const angle = this.angle + Math.PI / 2;
// c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
// const threshold = 0.4;
// const turn = 0.000025 * this.inertia
// if (c > threshold) {
// this.torque += turn;
// } else if (c < -threshold) {
// this.torque -= turn;
// }
// const flapArc = 0.7 //don't go past 1.57 for normal flaps
// ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
// this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
// this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
// }
}; };
}, },
beetleBoss(x, y, radius = 50) { beetleBoss(x, y, radius = 50) {
@@ -5237,9 +5393,7 @@ const spawn = {
me.do = function () { me.do = function () {
this.checkStatus(); this.checkStatus();
if (Matter.Query.collides(this, [player]).length > 0) { if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) this.isExploding = true
this.isExploding = true
}
if (this.isExploding) { if (this.isExploding) {
if (this.countDown-- < 0) { //explode if (this.countDown-- < 0) { //explode

View File

@@ -237,7 +237,7 @@ const tech = {
if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage
if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.015 * m.coupling if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.015 * m.coupling
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling) if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling)
if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime
if (tech.isTechDebt) dmg *= tech.totalCount > 20 ? Math.pow(0.85, tech.totalCount - 20) : 4 - 0.15 * tech.totalCount // if (tech.isTechDebt) dmg *= Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount) if (tech.isTechDebt) dmg *= tech.totalCount > 20 ? Math.pow(0.85, tech.totalCount - 20) : 4 - 0.15 * tech.totalCount // if (tech.isTechDebt) dmg *= Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount)
if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555 if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555
@@ -365,6 +365,57 @@ const tech = {
if (this.count) m.resetSkin(); if (this.count) m.resetSkin();
} }
}, },
{
name: "Higgs mechanism",
description: "<strong>+77%</strong> <strong><em>fire rate</em></strong><br>while <strong>firing</strong> your <strong>position</strong> is fixed",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isSkin: true,
allowed() {
return !m.isAltSkin && !m.isShipMode && !tech.isAlwaysFire
},
requires: "not skinned, ship mode, automatic",
effect() {
tech.isFireMoveLock = true;
b.setFireCD();
b.setFireMethod();
m.skin.strokeGap();
},
remove() {
if (tech.isFireMoveLock) {
tech.isFireMoveLock = false
b.setFireCD();
b.setFireMethod();
if (this.count) m.resetSkin();
}
}
},
{
name: "Hilbert space",
description: "<strong>+142%</strong> <strong class='color-d'>damage</strong><br>after a <strong>collision</strong> enter an <strong class='alt'>alternate reality</strong>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isAltRealityTech: true,
isSkin: true,
allowed() {
return !tech.isResearchReality && !tech.isSwitchReality
},
requires: "not Ψ(t) collapse, many-worlds",
damage: 2.42,
effect() {
m.skin.anodize();
tech.damage *= this.damage
tech.isCollisionRealitySwitch = true;
},
remove() {
if (this.count) tech.damage /= this.damage
tech.isCollisionRealitySwitch = false;
}
},
{ {
name: "aperture", name: "aperture",
description: "every <strong>6</strong> seconds your <strong class='color-d'>damage</strong> cycles<br>between <strong>-10%</strong> and <strong>+110%</strong> <strong class='color-d'>damage</strong>", description: "every <strong>6</strong> seconds your <strong class='color-d'>damage</strong> cycles<br>between <strong>-10%</strong> and <strong>+110%</strong> <strong class='color-d'>damage</strong>",
@@ -460,9 +511,9 @@ const tech = {
frequency: 4, frequency: 4,
frequencyDefault: 4, frequencyDefault: 4,
allowed() { allowed() {
return tech.isEnergyHealth return tech.isEnergyHealth && !tech.isOverHeal
}, },
requires: "mass-energy equivalence", requires: "mass-energy equivalence, not quenching",
effect() { effect() {
powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
powerUps.heal.color = "#ff0" //"#0ae" powerUps.heal.color = "#ff0" //"#0ae"
@@ -947,30 +998,6 @@ const tech = {
tech.isFarAwayDmg = false; tech.isFarAwayDmg = false;
} }
}, },
{
name: "Higgs mechanism",
description: "<strong>+45%</strong> <strong><em>fire rate</em></strong><br>while <strong>firing</strong> your <strong>position</strong> is fixed",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !m.isShipMode && !tech.isAlwaysFire
},
requires: "not ship mode, automatic",
effect() {
tech.isFireMoveLock = true;
b.setFireCD();
b.setFireMethod();
},
remove() {
if (tech.isFireMoveLock) {
tech.isFireMoveLock = false
b.setFireCD();
b.setFireMethod();
}
}
},
{ {
name: "integrated armament", name: "integrated armament",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Weapon' class="link">integrated armament</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Weapon' class="link">integrated armament</a>`,
@@ -1278,21 +1305,21 @@ const tech = {
{ {
name: "collider", name: "collider",
descriptionFunction() { descriptionFunction() {
return `after mobs <strong>die</strong> there is a <strong>+50%</strong> chance to<br>collide <strong>power ups</strong> to form different <strong>power ups</strong>` return `after mobs <strong>die</strong> <strong>power ups</strong><br>randomly collide to form different <strong>power ups</strong>`
// return `after mobs <strong>die</strong> there is a <strong>+33%</strong> chance to convert<br>${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, ${powerUps.orb.research(1)}, <strong class='color-m'>tech</strong>, <strong class='color-f'>field</strong>, <strong class='color-g'>gun</strong> into other types` // return `after mobs <strong>die</strong> there is a <strong>+33%</strong> chance to convert<br>${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, ${powerUps.orb.research(1)}, <strong class='color-m'>tech</strong>, <strong class='color-f'>field</strong>, <strong class='color-g'>gun</strong> into other types`
}, },
maxCount: 2, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed: () => true, allowed: () => true,
requires: "", requires: "",
effect() { effect() {
tech.collidePowerUps += 0.5 tech.collidePowerUps = true
}, },
remove() { remove() {
tech.collidePowerUps = 0 tech.collidePowerUps = false
} }
}, },
{ {
@@ -1316,17 +1343,53 @@ const tech = {
tech.isShieldAmmo = false; tech.isShieldAmmo = false;
} }
}, },
{
name: "yield stress",
description: "<strong>+55%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return m.fieldMode !== 7 && tech.mobSpawnWithHealth === 0
},
requires: "not cloaking, reaction inhibitor",
effect() {
tech.isMobFullHealth = true
},
remove() {
tech.isMobFullHealth = false
}
},
{
name: "cascading failure",
description: "<strong>+222%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> below <strong>25%</strong> <strong>health</strong>",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.mobSpawnWithHealth > 0
},
requires: "reaction inhibitor",
effect() {
tech.isMobLowHealth = true
},
remove() {
tech.isMobLowHealth = false
}
},
{ {
name: "reaction inhibitor", name: "reaction inhibitor",
description: "<strong>-11%</strong> maximum mob <strong>health</strong>", //<strong class='color-h'>health</strong> description: "<strong>mobs</strong> spawn with <strong>-12%</strong> initial <strong>health</strong>",
maxCount: 3, maxCount: 3,
count: 0, count: 0,
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed() { allowed() {
return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath return !tech.isMobFullHealth
}, },
requires: "", //"any mob death tech", requires: "not topological defect",
effect() { effect() {
tech.mobSpawnWithHealth++ tech.mobSpawnWithHealth++
mobs.setMobSpawnHealth() mobs.setMobSpawnHealth()
@@ -1343,7 +1406,7 @@ const tech = {
{ {
name: "scrap bots", name: "scrap bots",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Scrap' class="link">scrap bots</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Scrap' class="link">scrap bots</a>`,
description: "after mobs <strong>die</strong> you have a <strong>+33%</strong> chance<br>to build scrap <strong class='color-bot'>bots</strong> that operate for <strong>13</strong> seconds", description: "after mobs <strong>die</strong> you have a <strong>+33%</strong> chance<br>to build scrap <strong class='color-bot'>bots</strong> that operate for <strong>15</strong> seconds",
maxCount: 3, maxCount: 3,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -1363,7 +1426,7 @@ const tech = {
{ {
name: "scrap refit", name: "scrap refit",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Scrap' class="link">scrap refit</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Scrap' class="link">scrap refit</a>`,
description: "after mobs <strong>die</strong><br>reset scrap <strong class='color-bot'>bots</strong> to <strong>13</strong> seconds of operation", description: "after mobs <strong>die</strong><br>reset scrap <strong class='color-bot'>bots</strong> to <strong>15</strong> seconds of operation",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 3, frequency: 3,
@@ -3108,9 +3171,9 @@ const tech = {
frequencyDefault: 1, frequencyDefault: 1,
isHealTech: true, isHealTech: true,
allowed() { allowed() {
return true return !tech.isEnergyHealth
}, },
requires: "", requires: "not mass-energy",
effect() { effect() {
tech.isOverHeal = true; tech.isOverHeal = true;
}, },
@@ -3121,7 +3184,7 @@ const tech = {
{ {
name: "accretion", name: "accretion",
descriptionFunction() { descriptionFunction() {
return `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(5)}` return `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(7)}`
}, },
// description: `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(5)}`, // description: `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(5)}`,
maxCount: 1, maxCount: 1,
@@ -3136,7 +3199,7 @@ const tech = {
effect() { effect() {
tech.isHealAttract = true tech.isHealAttract = true
powerUps.setPowerUpMode(); powerUps.setPowerUpMode();
for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal"); for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal");
}, },
remove() { remove() {
tech.isHealAttract = false tech.isHealAttract = false
@@ -3295,28 +3358,6 @@ const tech = {
tech.isImmortal = false; tech.isImmortal = false;
} }
}, },
{
name: "Hilbert space",
description: "<strong>+99%</strong> <strong class='color-d'>damage</strong><br>after a <strong>collision</strong> enter an <strong class='alt'>alternate reality</strong>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isAltRealityTech: true,
allowed() {
return !tech.isResearchReality && !tech.isSwitchReality
},
requires: "not Ψ(t) collapse, many-worlds",
damage: 1.99,
effect() {
tech.damage *= this.damage
tech.isCollisionRealitySwitch = true;
},
remove() {
if (this.count) tech.damage /= this.damage
tech.isCollisionRealitySwitch = false;
}
},
{ {
name: "many-worlds", name: "many-worlds",
// description: "each <strong>level</strong> is an <strong class='alt'>alternate reality</strong>, where you<br>find a <strong class='color-m'>tech</strong> at the start of each level", // description: "each <strong>level</strong> is an <strong class='alt'>alternate reality</strong>, where you<br>find a <strong class='color-m'>tech</strong> at the start of each level",
@@ -3415,7 +3456,10 @@ const tech = {
}, },
{ {
name: "perturbation theory", name: "perturbation theory",
description: `if you have no ${powerUps.orb.research(1)} in your inventory<br><strong>+70%</strong> <strong><em>fire rate</em></strong>`, description: `if you have no ${powerUps.orb.research(1)} in your inventory<br><strong>+60%</strong> <strong><em>fire rate</em></strong>`,
// descriptionFunction() {
// return `<strong>+40%</strong> <strong class='color-d'>damage</strong>, but <strong>-10%</strong> <strong class='color-d'>damage</strong><br>for each ${powerUps.orb.research(1)} in your inventory <em>(${40 - 10 * powerUps.research.count}% damage)</em>`
// },
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3426,7 +3470,7 @@ const tech = {
requires: "no research", requires: "no research",
effect() { effect() {
tech.isRerollHaste = true; tech.isRerollHaste = true;
tech.researchHaste = 0.3; tech.researchHaste = 0.4; //+60% fire rate
b.setFireCD(); b.setFireCD();
}, },
remove() { remove() {
@@ -3482,7 +3526,7 @@ const tech = {
{ {
name: "mass production", name: "mass production",
descriptionFunction() { descriptionFunction() {
return `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} &nbsp;&nbsp; or ${powerUps.orb.research(5)}` return `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(10)} ${powerUps.orb.heal(10)} &nbsp;&nbsp; or ${powerUps.orb.research(7)}`
}, },
// description: `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} &nbsp;&nbsp; or ${powerUps.orb.research(5)}`, // description: `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} &nbsp;&nbsp; or ${powerUps.orb.research(5)}`,
maxCount: 1, maxCount: 1,
@@ -3500,7 +3544,7 @@ const tech = {
}, },
{ {
name: "research", name: "research",
description: `spawn ${powerUps.orb.research(5)}`, description: `spawn ${powerUps.orb.research(7)}`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 0, frequency: 0,
@@ -3510,13 +3554,13 @@ const tech = {
allowed() { return true }, allowed() { return true },
requires: "", requires: "",
effect() { effect() {
powerUps.spawnDelay("research", 5); powerUps.spawnDelay("research", 7);
}, },
remove() { } remove() { }
}, },
{ {
name: "ammo", name: "ammo",
description: `spawn ${powerUps.orb.ammo(8)}`, description: `spawn ${powerUps.orb.ammo(10)}`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 0, frequency: 0,
@@ -3526,14 +3570,14 @@ const tech = {
allowed() { return true }, allowed() { return true },
requires: "", requires: "",
effect() { effect() {
powerUps.spawnDelay("ammo", 8); powerUps.spawnDelay("ammo", 10);
}, },
remove() { } remove() { }
}, },
{ {
name: "heals", name: "heals",
descriptionFunction() { descriptionFunction() {
return `spawn ${powerUps.orb.heal(8)}` return `spawn ${powerUps.orb.heal(10)}`
}, },
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -3544,7 +3588,7 @@ const tech = {
allowed() { return true }, allowed() { return true },
requires: "mass production", requires: "mass production",
effect() { effect() {
powerUps.spawnDelay("heal", 8); powerUps.spawnDelay("heal", 10);
}, },
remove() { } remove() { }
}, },
@@ -5339,7 +5383,7 @@ const tech = {
} }
}, },
{ {
name: "phonon", //longitudinal //gravitational wave? name: "phonon",
description: "waves are low <strong>frequency</strong>, high <strong class='color-d'>damage</strong><br><strong>expanding arcs</strong> that propagate through <strong>solids</strong>", description: "waves are low <strong>frequency</strong>, high <strong class='color-d'>damage</strong><br><strong>expanding arcs</strong> that propagate through <strong>solids</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
@@ -6818,7 +6862,7 @@ const tech = {
}, },
remove() { remove() {
tech.railChargeRate = 0.97; tech.railChargeRate = 0.97;
tech.harpoonDensity = 0.007 tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
} }
}, },
{ {
@@ -6837,6 +6881,7 @@ const tech = {
ammoBonus: 9, ammoBonus: 9,
effect() { effect() {
tech.isRailGun = true; tech.isRailGun = true;
tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
b.guns[9].chooseFireMethod() b.guns[9].chooseFireMethod()
b.guns[9].ammoPack = 5; b.guns[9].ammoPack = 5;
b.guns[9].ammo = b.guns[9].ammo * 6; b.guns[9].ammo = b.guns[9].ammo * 6;
@@ -6845,6 +6890,7 @@ const tech = {
remove() { remove() {
if (tech.isRailGun) { if (tech.isRailGun) {
tech.isRailGun = false; tech.isRailGun = false;
tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
b.guns[9].chooseFireMethod() b.guns[9].chooseFireMethod()
b.guns[9].ammoPack = 1.7; b.guns[9].ammoPack = 1.7;
b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6); b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6);
@@ -7025,21 +7071,41 @@ const tech = {
}, },
{ {
name: "induction furnace", name: "induction furnace",
description: "after using <strong>harpoon</strong> to collect a <strong>power up</strong><br><strong>+600%</strong> <strong>harpoon</strong> <strong class='color-d'>damage</strong>", description: "after using <strong>harpoon</strong> or <strong>grapple</strong> to collect <strong>power ups</strong><br><strong>+77%</strong> <strong>harpoon</strong> or <strong>grapple</strong> <strong class='color-d'>damage</strong> for 8 seconds",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("harpoon") && !tech.isRailGun return ((tech.haveGunCheck("harpoon") && !tech.isRailGun) || m.fieldMode === 10) && !tech.isHarpoonFullHealth
}, },
requires: "harpoon, not railgun", requires: "harpoon, grappling hook, not railgun, brittle",
effect() { effect() {
tech.isHarpoonPowerUp = true tech.isHarpoonPowerUp = true
}, },
remove() { remove() {
tech.isHarpoonPowerUp = false tech.isHarpoonPowerUp = false
tech.harpoonPowerUpCycle = 0
}
},
{
name: "brittle",
description: "<strong>+88%</strong> <strong>harpoon</strong> and <strong>grapple</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("harpoon") || m.fieldMode === 10) && !tech.isHarpoonPowerUp
},
requires: "harpoon, grappling hook, not induction furnace",
effect() {
tech.isHarpoonFullHealth = true
},
remove() {
tech.isHarpoonFullHealth = false
} }
}, },
{ {
@@ -7437,7 +7503,7 @@ const tech = {
//************************************************** //**************************************************
{ {
name: "spherical harmonics", name: "spherical harmonics",
description: "<strong>+50%</strong> <strong>standing wave</strong> deflection efficiency<br>shield deflection radius maintains it's maximum range", //<strong>standing wave</strong> oscillates in a 3rd dimension<br> description: "<strong>+50%</strong> <strong>standing wave</strong> deflection efficiency<br>shield deflection radius holds it's max range", //<strong>standing wave</strong> oscillates in a 3rd dimension<br>
isFieldTech: true, isFieldTech: true,
maxCount: 9, maxCount: 9,
count: 0, count: 0,
@@ -8133,7 +8199,7 @@ const tech = {
}, },
{ {
name: "degenerate matter", name: "degenerate matter",
description: "if your <strong class='color-f'>field</strong> is active<br><strong>+85%</strong> <strong class='color-defense'>defense</strong>", description: "if your <strong class='color-f'>field</strong> is active<br><strong>+88%</strong> <strong class='color-defense'>defense</strong>",
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -8400,7 +8466,7 @@ const tech = {
{ {
name: "no-cloning theorem", name: "no-cloning theorem",
// descriptionFunction() { return `<strong>+45%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>after a mob <strong>dies</strong> <strong>2%</strong> <strong class='color-dup'>duplication</strong> <em>(${tech.duplicationChance()})</em>` }, // descriptionFunction() { return `<strong>+45%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>after a mob <strong>dies</strong> <strong>2%</strong> <strong class='color-dup'>duplication</strong> <em>(${tech.duplicationChance()})</em>` },
description: `<strong>+45%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>after a mob <strong>dies</strong> <strong>2%</strong> <strong class='color-dup'>duplication</strong>`, description: `<strong>+40%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>after a mob <strong>dies</strong> <strong>1%</strong> <strong class='color-dup'>duplication</strong>`,
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -8411,7 +8477,7 @@ const tech = {
}, },
requires: "cloaking, time dilation", requires: "cloaking, time dilation",
effect() { effect() {
tech.cloakDuplication = 0.45 tech.cloakDuplication = 0.4
powerUps.setPowerUpMode(); //needed after adjusting duplication chance powerUps.setPowerUpMode(); //needed after adjusting duplication chance
if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4); if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
}, },
@@ -8423,7 +8489,7 @@ const tech = {
{ {
name: "metamaterial absorber", //quantum eraser name: "metamaterial absorber", //quantum eraser
descriptionFunction() { descriptionFunction() {
return `for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br>there is a <strong>17%</strong> chance to spawn a random <strong>power up</strong>` return `for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br>there is a <strong>22%</strong> chance to spawn a random <strong>power up</strong>`
}, },
// descriptionFunction() { // descriptionFunction() {
// return `for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br>` // return `for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br>`
@@ -8447,7 +8513,7 @@ const tech = {
{ {
name: "symbiosis", name: "symbiosis",
descriptionFunction() { descriptionFunction() {
return `after a <strong>boss</strong> <strong>dies</strong> spawn ${powerUps.orb.research(3)}${powerUps.orb.heal(3)} and a <strong class='color-m'>tech</strong><br>after a <strong>mob</strong> <strong>dies</strong> <strong>0.5</strong> maximum ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"}` return `after a <strong>boss</strong> <strong>dies</strong> spawn ${powerUps.orb.research(4)}${powerUps.orb.heal(3)} and a <strong class='color-m'>tech</strong><br>after a <strong>mob</strong> <strong>dies</strong> <strong>0.5</strong> maximum ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"}`
}, },
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
@@ -8491,7 +8557,7 @@ const tech = {
{ {
name: "patch", name: "patch",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Patch_(computing)' class="link">patch</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Patch_(computing)' class="link">patch</a>`,
description: "after <strong class='color-cloaked'>cloaking</strong> recover <strong>75%</strong> of your<br>last <strong class='color-h'>health</strong> loss using that much <strong class='color-f'>energy</strong>", description: "after <strong class='color-cloaked'>cloaking</strong> recover <strong>75%</strong><br>of your last <strong class='color-h'>health</strong> lost",
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -8528,6 +8594,25 @@ const tech = {
tech.isCloakStun = false; tech.isCloakStun = false;
} }
}, },
{
name: "topological defect",
description: "<strong>+88%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return (m.fieldMode === 8 || m.fieldMode === 7) && tech.mobSpawnWithHealth === 0 && !tech.isMobFullHealth
},
requires: "cloaking, pilot wave, not reaction inhibitor, yield stress",
effect() {
tech.isMobFullHealthCloak = true
},
remove() {
tech.isMobFullHealthCloak = false
}
},
// { // {
// name: "ambush", // name: "ambush",
// description: "metamaterial cloaking field <strong class='color-d'>damage</strong> effect<br>is increased from <span style = 'text-decoration: line-through;'>333%</span> to <strong>555%</strong>", // description: "metamaterial cloaking field <strong class='color-d'>damage</strong> effect<br>is increased from <span style = 'text-decoration: line-through;'>333%</span> to <strong>555%</strong>",
@@ -9192,6 +9277,23 @@ const tech = {
}, },
remove() { } remove() { }
}, },
{
name: "planned obsolescence",
description: "build <strong>100</strong> scrap <strong class='color-bot'>bots</strong><br>bots might last for <strong>30</strong> seconds",
maxCount: 1,
count: 0,
frequency: 0,
isJunk: true,
allowed: () => true,
requires: "",
effect() {
for (let i = 0; i < 100; i++) {
b.randomBot(m.pos, false)
bullet[bullet.length - 1].endCycle = simulation.cycle + 800 + 1000 * Math.random() //15 seconds
}
},
remove() { }
},
// { // {
// name: "synchrotron", // name: "synchrotron",
// descriptionFunction() { // descriptionFunction() {
@@ -11921,4 +12023,9 @@ const tech = {
isHookExplosion: null, isHookExplosion: null,
isHarpoonDefense: null, isHarpoonDefense: null,
isReel: null, isReel: null,
harpoonPowerUpCycle: null,
isHarpoonFullHealth: null,
isMobFullHealth: null,
isMobFullHealthCloak: null,
isMobLowHealth: null
} }

154
todo.txt
View File

@@ -1,24 +1,64 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
why mode is now 20% easier, but still 25% harder than hard mode mob health tech
easy:1, normal:2, hard:4, why:6->5 tech: cascading failure - +222% damage to mobs below 25% health
tech: yield stress - +55% damage to mobs at maximum health
cloaking tech: topological defect - +88% damage to mobs at maximum health
harpoon tech: brittle - +88% harpoon/grapple damage to mobs at maximum health
new community map unchartedCave by 3xionDev! cloaking buffs
50->66% defense while cloaked
recloak 0.25s faster
simplified cloaking field graphics
boson composite drains much less energy while moving through mobs and shields
fixed bug where mines and egg mobs were colliding with player while intangible
patch no longer drains energy when you heal on cloaking
metamaterial absorber gets 17->22% chance to spawn a power up for each mob alive
no-cloning theorem changes to 45->40% duplication and 2->1% duplication loss on killing a mob
Newtons 1st law 66->88% defense when moving fast finalBoss phases:
Newtons 2nd law 66->88% damage when moving fast new: slow zone, antigravity pulse
CIWS energy 20->18 per shot nerfed: laser, black hole, orbitals
rupture disables reel and tokamak buffed: oscillation, mobs
improved graphics: boulder
Hilbert space has a skin. 99->142% damage increase, but randomize tech after taking damage
Higgs mechanism has a skin. +45->77% fire rate, player can't move while firing
induction furnace gives +77% harpoon/grapple damage for 8 seconds after picking up a power up
collider 50->100% chance to combine and randomize power ups
quenching gives more bonus max health at high difficulty level (maybe around 30% more health)
accretion gives 5->7 heal power ups
dynamo bots follow player much closer when you have many of them
scrap-bots don't follow the player as accurately or as quickly
scrap bot duration 13->15 seconds
JUNK tech: planned obsolescence - make 100 scrap bots that last for about 30 seconds
community map dojo by werid_pusheen
fixed by Cornbread 2100
hard mode gets 1 less heal at the start
hard and why difficulty don't begin with starter mobs
hopBullet mobs last 2 seconds less time
adjusted button heights on train station level to be consistently the same height
*********************************************************** TODO ***************************************************** *********************************************************** TODO *****************************************************
hexagon head skin
maybe give defense
scrap bots don't follow player
adjust spawn rates to balance
foam tech: increase size of foam and increase duration, but drop speed down, so they come to a stop and just hang
allow them to harm player?
this is probably just too annoying
make a flutter variant
just move the wings to the back?
slow flap, and acceleration that increases when the flap occurs, like swimming
make grappling hook of different shapes make grappling hook of different shapes
shapes
longer
circular with spikes
indicate tech upgrades? indicate tech upgrades?
rupture, reel, tokamak rupture, reel, tokamak
do this in draw or in verticies? do this in draw or in verticies?
@@ -31,8 +71,6 @@ grappling hook field
field tech ideas field tech ideas
Buoyancy - aerostat, but for defense: +70% defense while off the ground Buoyancy - aerostat, but for defense: +70% defense while off the ground
too similar to degenerate matter too similar to degenerate matter
generate ___ after destroying blocks
energy, drones, iceIX, explosion, nails, junk bots?
tech - killing a mob heals for the last damage you took 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 disable cloaking heal? maybe you don't need to disable, just don't heal twice
@@ -43,9 +81,6 @@ on sucker mob death trigger radiation damage AoE and a graphic (Hawking radiati
tech prismatic laser - cycles between different laser colors every 1-2 seconds tech prismatic laser - cycles between different laser colors every 1-2 seconds
make phonon the default wave gun type and make a tech to switch to the normal wave beam
nerf phonon, buff wave
sword slash for plasma torch (giving up on this for now, had trouble making graphics look good) sword slash for plasma torch (giving up on this for now, had trouble making graphics look good)
activates when mouse is close to player activates when mouse is close to player
gradual activation gradual activation
@@ -83,12 +118,6 @@ use cross product rotation for other mobs?
super-bot: fires super balls super-bot: fires super balls
tech - only allow 1,2 turrets at time. spawning a new mine removes the oldest mine
turrets never run out of ammo
or turrets automatically use one of your mine ammos when they run out?
good with multi gun builds
conflict with booby trap?
tech: after a needle hits a mobs tech: after a needle hits a mobs
the needle splits into 3 needles? the needle splits into 3 needles?
reset your fire CD? reset your fire CD?
@@ -183,32 +212,6 @@ hookBoss fires a hook that pulls player towards it
player targeted unless cloaking player targeted unless cloaking
also add effect to finalBoss also add effect to finalBoss
finalBoss
add synergies between modes:
new modes:
something that needs to be killed quickly
if you don't kill it boss gets a shield
rotating quadrant immunity shield, can't take damage from that quadrant
maybe also attack player near that quadrant
but how to tell the angle of incoming damage
maybe a physics body like the shield but it only covers 1/3 of mob?
falling object warps to ceiling after hitting floor
doesn't end, player needs to kill it
slowly grows?
slow effect zones
random placement or place over player or both!
draw white dot and an outline of area of effect
expanding circle stroke, freeze effect triggers when stroke circle hits fill circle
after 1-2 seconds freeze player if in the zone
also freeze mobs
effect that makes player have to be close to boss
hook that tries to yank the player into hitting finalBoss
does damage
pulls player into center
counter with wormhole, negative mass
player targeted unless cloaking
mob status effect - emit - mobs fire lasers for a few seconds mob status effect - emit - mobs fire lasers for a few seconds
tech: phosphorescence - mobs emit after being hit with laser beams tech: phosphorescence - mobs emit after being hit with laser beams
@@ -226,7 +229,7 @@ tech increase max energy and energy to 5000, but you can no longer regen energy
it would be nice if there was incentive to go slow when choosing tech so n-gon is more relaxing it would be nice if there was incentive to go slow when choosing tech so n-gon is more relaxing
add some css based visual effects for opening up a tech,gun,field add some css based visual effects for opening up a tech,gun,field
make a new coupling effect for perfect diamagnetism or standing wave make a new coupling effect for perfect diamagnetism
make a faster smaller version of cell boss that also has map collisions make a faster smaller version of cell boss that also has map collisions
@@ -237,22 +240,11 @@ JUNK tech description that changes similar to cards in inscription
that changes based on mouse position that changes based on mouse position
can you tell if mouse is over card? can you tell if mouse is over card?
tech - buff MACHO range, effect, move speed?
while you are inside MACHO it will damage mobs?
PWA? PWA?
https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps
https://codeburst.io/how-to-easily-turn-your-static-website-to-a-progressive-web-app-pwa-b0af08da9693 https://codeburst.io/how-to-easily-turn-your-static-website-to-a-progressive-web-app-pwa-b0af08da9693
https://github.com/landgreen/n-gon/pull/32/files https://github.com/landgreen/n-gon/pull/32/files
bug blocks and power ups falling through map
always foam gun (4-5 times)
might be about tech pressure vessel
happens rarely, doesn't repeat
only occurs for 3 people so far
normally after level 6
occurred once on the first level, didn't fire gun and was able to walk through a body
Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when relay swicth/flip flop is off, ammo powerups remain ammo powerups Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when relay swicth/flip flop is off, ammo powerups remain ammo powerups
or toggle other power ups or toggle other power ups
health/ammo health/ammo
@@ -260,9 +252,6 @@ Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when rel
JUNK: what the golf? JUNK: what the golf?
trying to throw a block throws you instead trying to throw a block throws you instead
tech for lens - you can only fire through the lens
and some buff? damage or energy?
complete blowSuckBoss... or don't complete blowSuckBoss... or don't
tech: laser reflections increase damage tech: laser reflections increase damage
@@ -272,18 +261,6 @@ JUNK tech different effects based on night or day
Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back
coupling
put coupling description as 4th line on field description
raw text no function call
no need for coupling description in power ups, pause
negative coupling?
wouldn't work for iceIX
coupling tech
names: strongly coupled, Vibronic coupling, NMR coupling
tech: +x% field coupling, your field changes randomly every y seconds
tech: coupling starts at 200%, but decays when the field is in use, coupling recharges when the field is not in use
some fields aren't used much (that's ok?)
tech give laser mines more lasers (3->4? 5?) tech give laser mines more lasers (3->4? 5?)
rewindBoss: after hitting 1/5 damage thresholds the boss rewinds back in time to where it was a few seconds ago rewindBoss: after hitting 1/5 damage thresholds the boss rewinds back in time to where it was a few seconds ago
@@ -307,11 +284,6 @@ immediately fire all of your ammo
after taking damage explode while invulnerable after taking damage explode while invulnerable
scale explosion radius with damage scale explosion radius with damage
quantum immortality: send you to a new tab after you die with a random load out
basically everything is the same as it is now, but you switch tabs
Tech: Tech/guns/fields can no longer be duplicated. Duplication applies twice
tech: get sent to a new tab that closes in 3 minutes tech: get sent to a new tab that closes in 3 minutes
in the new tab you play reactor in the new tab you play reactor
if you die in reactor you die in game, if you win you get 2-3 tech in the original game? if you die in reactor you die in game, if you win you get 2-3 tech in the original game?
@@ -319,31 +291,8 @@ tech: get sent to a new tab that closes in 3 minutes
count guns, field, tech and give random stuff on new tab count guns, field, tech and give random stuff on new tab
i-frame instead of tab? i-frame instead of tab?
reduce the amount of research and nerf anti randomization tech
increase possible synergies that go nuts
tech expansion: field coupling also expands each fields in different ways
how to make the description work
change description based on your current field?
perfect diamagnetism moves forward when you hold down the shield
it's great, but maybe annoying?
maybe only with crouch?
perfect diamagnetism just replace or increase Messier effect
time dilation drains 1/2 as much energy when paused
grow plasma torch as you hold it down
negative mass effects much more space
needs more benefit?
reduces the cloaking vision effect?
needs more benefit?
tech: missiles explode a 2nd time after 1/2 a second (with a slightly different position determined by original velocity) tech: missiles explode a 2nd time after 1/2 a second (with a slightly different position determined by original velocity)
The tech that makes blocks that fall into a wormhole give energy should scale with block size, with the same formula as tokomak
junk suggestion: useless machine - ejects itself and removes itself from the item pool
seed isn't working right from shared URL seed isn't working right from shared URL
mob mechanics mob mechanics
@@ -359,8 +308,6 @@ mob mechanics
spawns new nodes spawns new nodes
draws connections as quad lines draws connections as quad lines
tech: You can place an extra perfect diamagnatism field on the map
standing wave no longer pushes mobs away, but it can do damage to mobs caught in area effect standing wave no longer pushes mobs away, but it can do damage to mobs caught in area effect
Standing wave harmonics no longer deflects, but instead discharges excess energy as lightning toward nearby enemies Standing wave harmonics no longer deflects, but instead discharges excess energy as lightning toward nearby enemies
negative mass field does damage to mobs inside field negative mass field does damage to mobs inside field
@@ -1157,6 +1104,7 @@ possible names for tech
Josephson junction - superconducting junction Josephson junction - superconducting junction
Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity
perturbation perturbation
Unruh effect - accelerating makes heat/thermal particles
******************************************************** CARS IMAGES ******************************************************** ******************************************************** CARS IMAGES ********************************************************