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:
599
js/bullet.js
599
js/bullet.js
@@ -288,7 +288,7 @@ const b = {
|
||||
if (m.fieldMode === 6) b.fireCDscale *= 0.8
|
||||
if (tech.isFastTime) b.fireCDscale *= 0.5
|
||||
if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, Math.max(0, b.inventory.length - 1))
|
||||
if (tech.isFireMoveLock) b.fireCDscale *= 0.55
|
||||
if (tech.isFireMoveLock) b.fireCDscale *= 0.23 // 77% fire rate
|
||||
},
|
||||
fireAttributes(dir, rotate = true) {
|
||||
if (rotate) {
|
||||
@@ -1508,8 +1508,9 @@ const b = {
|
||||
},
|
||||
minDmgSpeed: 4,
|
||||
// lookFrequency: Math.floor(7 + Math.random() * 3),
|
||||
density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon
|
||||
drain: 0.001,
|
||||
powerUpDamage: tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle,
|
||||
draw() {
|
||||
// draw rope
|
||||
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
|
||||
@@ -1559,9 +1560,26 @@ const b = {
|
||||
// ctx.stroke();
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
if (this.powerUpDamage) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
|
||||
ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
|
||||
ctx.lineTo(this.vertices[2].x, this.vertices[2].y);
|
||||
ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
|
||||
ctx.lineTo(this.vertices[4].x, this.vertices[4].y);
|
||||
ctx.lineJoin = "miter"
|
||||
ctx.miterLimit = 30;
|
||||
ctx.lineWidth = 25;
|
||||
ctx.strokeStyle = "rgba(0,255,255,0.4)";
|
||||
ctx.stroke();
|
||||
ctx.lineWidth = 8;
|
||||
ctx.strokeStyle = "rgb(0,255,255)";
|
||||
ctx.stroke();
|
||||
ctx.lineJoin = "round"
|
||||
ctx.miterLimit = 5
|
||||
ctx.fillStyle = "#000"
|
||||
ctx.fill();
|
||||
}
|
||||
//draw hook
|
||||
ctx.beginPath();
|
||||
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
@@ -1581,6 +1599,42 @@ const b = {
|
||||
}
|
||||
if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
|
||||
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
|
||||
// if (this.powerUpDamage) this.density = 2 * 0.004 //double damage after pick up power up for 8 seconds
|
||||
|
||||
|
||||
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
|
||||
Matter.Body.setDensity(this, 1.8 * 0.004); //+90% damage after pick up power up for 8 seconds
|
||||
} else if (tech.isHarpoonFullHealth && who.health === 1) {
|
||||
Matter.Body.setDensity(this, 1.9 * 0.004); //+90% damage if mob has full health do
|
||||
simulation.ephemera.push({
|
||||
name: "grapple outline",
|
||||
count: 3, //cycles before it self removes
|
||||
vertices: this.vertices,
|
||||
do() {
|
||||
this.count--
|
||||
if (this.count < 0) simulation.removeEphemera(this.name)
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
|
||||
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
|
||||
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
ctx.lineJoin = "miter"
|
||||
ctx.miterLimit = 20;
|
||||
ctx.lineWidth = 40;
|
||||
ctx.strokeStyle = "rgba(255,0,100,0.35)";
|
||||
ctx.stroke();
|
||||
ctx.lineWidth = 10;
|
||||
ctx.strokeStyle = `#f07`;
|
||||
ctx.stroke();
|
||||
ctx.lineJoin = "round"
|
||||
ctx.miterLimit = 5
|
||||
ctx.fillStyle = "#000"
|
||||
ctx.fill();
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
this.retract()
|
||||
},
|
||||
caughtPowerUp: null,
|
||||
@@ -1602,7 +1656,7 @@ const b = {
|
||||
this.caughtPowerUp.effect();
|
||||
Matter.Composite.remove(engine.world, this.caughtPowerUp);
|
||||
powerUp.splice(index, 1);
|
||||
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
|
||||
if (tech.isHarpoonPowerUp) tech.harpoonPowerUpCycle = simulation.cycle
|
||||
} else {
|
||||
this.dropCaughtPowerUp()
|
||||
}
|
||||
@@ -1893,321 +1947,6 @@ const b = {
|
||||
});
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
// grapple(where, angle = m.angle, harpoonSize = 1) {
|
||||
// const me = bullet.length;
|
||||
// const returnRadius = 100 * Math.sqrt(harpoonSize)
|
||||
// bullet[me] = Bodies.fromVertices(where.x, where.y, [{
|
||||
// x: -50 * harpoonSize,
|
||||
// y: 2 * harpoonSize,
|
||||
// index: 0,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: -50 * harpoonSize,
|
||||
// y: -2 * harpoonSize,
|
||||
// index: 1,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 45 * harpoonSize,
|
||||
// y: -3 * harpoonSize,
|
||||
// index: 2,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 50 * harpoonSize,
|
||||
// y: 0,
|
||||
// index: 3,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 45 * harpoonSize,
|
||||
// y: 3 * harpoonSize,
|
||||
// index: 4,
|
||||
// isInternal: false
|
||||
// }], {
|
||||
// angle: angle,
|
||||
// friction: 1,
|
||||
// frictionAir: 0.4,
|
||||
// thrustMag: 0.1,
|
||||
// dmg: 6, //damage done in addition to the damage from momentum
|
||||
// classType: "bullet",
|
||||
// endCycle: simulation.cycle + 70,
|
||||
// collisionFilter: {
|
||||
// category: cat.bullet,
|
||||
// mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
|
||||
// },
|
||||
// minDmgSpeed: 4,
|
||||
// lookFrequency: Math.floor(7 + Math.random() * 3),
|
||||
// density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
// drain: tech.isRailEnergy ? 0.0006 : 0.006,
|
||||
// beforeDmg(who) {
|
||||
// if (tech.isShieldPierce && who.isShielded) { //disable shields
|
||||
// who.isShielded = false
|
||||
// requestAnimationFrame(() => {
|
||||
// who.isShielded = true
|
||||
// });
|
||||
// }
|
||||
// if (tech.fragments) {
|
||||
// b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random()))
|
||||
// }
|
||||
// if (tech.isFoamBall) {
|
||||
// for (let i = 0, len = 4 * this.mass; i < len; i++) {
|
||||
// const radius = 5 + 8 * Math.random()
|
||||
// const velocity = {
|
||||
// x: Math.max(0.5, 2 - radius * 0.1),
|
||||
// y: 0
|
||||
// }
|
||||
// b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
|
||||
// }
|
||||
// // this.endCycle = 0;
|
||||
// }
|
||||
// },
|
||||
// caughtPowerUp: null,
|
||||
// dropCaughtPowerUp() {
|
||||
// if (this.caughtPowerUp) {
|
||||
// this.caughtPowerUp.collisionFilter.category = cat.powerUp
|
||||
// this.caughtPowerUp.collisionFilter.mask = cat.map | cat.powerUp
|
||||
// this.caughtPowerUp = null
|
||||
// }
|
||||
// },
|
||||
// onEnd() {
|
||||
// if (this.caughtPowerUp && !simulation.isChoosing && (this.caughtPowerUp.name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)) {
|
||||
// let index = null //find index
|
||||
// for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
// if (powerUp[i] === this.caughtPowerUp) index = i
|
||||
// }
|
||||
// if (index !== null) {
|
||||
// powerUps.onPickUp(this.caughtPowerUp);
|
||||
// this.caughtPowerUp.effect();
|
||||
// Matter.Composite.remove(engine.world, this.caughtPowerUp);
|
||||
// powerUp.splice(index, 1);
|
||||
// if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
|
||||
// } else {
|
||||
// this.dropCaughtPowerUp()
|
||||
// }
|
||||
// } else {
|
||||
// this.dropCaughtPowerUp()
|
||||
// }
|
||||
// },
|
||||
// draw() {
|
||||
// const where = {
|
||||
// x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
// y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
// }
|
||||
// const sub = Vector.sub(where, this.vertices[0])
|
||||
// const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
|
||||
// ctx.strokeStyle = "#000" // "#0ce"
|
||||
// ctx.lineWidth = 0.5
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(where.x, where.y);
|
||||
// ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
|
||||
// // ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
// ctx.stroke();
|
||||
// //draw harpoon spikes
|
||||
// const spikeLength = 2
|
||||
// ctx.beginPath();
|
||||
// const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
|
||||
// ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
|
||||
// ctx.lineTo(spike1.x, spike1.y);
|
||||
// ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
|
||||
|
||||
// const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
|
||||
// ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
|
||||
// ctx.lineTo(spike2.x, spike2.y);
|
||||
// ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
|
||||
// ctx.fillStyle = '#000'
|
||||
// ctx.fill();
|
||||
// },
|
||||
// returnToPlayer() {
|
||||
// if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
|
||||
// this.endCycle = 0;
|
||||
// // if (m.energy < 0.05) {
|
||||
// // m.fireCDcycle = m.cycle + 120; //fire cooldown
|
||||
// // } else if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) {
|
||||
// // m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 25 if it is above 25
|
||||
// // }
|
||||
|
||||
// if (m.energy < 0.05) this.dropCaughtPowerUp()
|
||||
|
||||
// //recoil on catching
|
||||
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
// player.force.x += momentum.x
|
||||
// player.force.y += momentum.y
|
||||
// // refund ammo
|
||||
// b.guns[9].ammo++;
|
||||
// simulation.updateGunHUD();
|
||||
|
||||
// // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
// // if (b.guns[i].name === "harpoon") {
|
||||
// // b.guns[i].ammo++;
|
||||
// // simulation.updateGunHUD();
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
// } else {
|
||||
// if (m.energy > this.drain) m.energy -= this.drain
|
||||
// const sub = Vector.sub(this.position, m.pos)
|
||||
// const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
|
||||
// const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
|
||||
// this.force.x -= returnForce.x
|
||||
// this.force.y -= returnForce.y
|
||||
// this.grabPowerUp()
|
||||
// }
|
||||
// this.draw();
|
||||
// },
|
||||
// grabPowerUp() { //grab power ups near the tip of the harpoon
|
||||
// if (this.caughtPowerUp) {
|
||||
// Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
|
||||
// Matter.Body.setVelocity(this.caughtPowerUp, {
|
||||
// x: 0,
|
||||
// y: 0
|
||||
// })
|
||||
// } else { //&& simulation.cycle % 2
|
||||
// for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
// const radius = powerUp[i].circleRadius + 50
|
||||
// if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) {
|
||||
// if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
|
||||
// this.caughtPowerUp = powerUp[i]
|
||||
// Matter.Body.setVelocity(powerUp[i], {
|
||||
// x: 0,
|
||||
// y: 0
|
||||
// })
|
||||
// Matter.Body.setPosition(powerUp[i], this.vertices[2])
|
||||
// powerUp[i].collisionFilter.category = 0
|
||||
// powerUp[i].collisionFilter.mask = 0
|
||||
// this.thrustMag *= 0.6
|
||||
// this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
|
||||
// break //just pull 1 power up if possible
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// do() {
|
||||
// if (input.fire) { //&& !Matter.Query.collides(this, body).length
|
||||
// this.grabPowerUp()
|
||||
// if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction
|
||||
// this.endCycle = simulation.cycle + 60
|
||||
// // m.fireCDcycle = m.cycle + 120 // cool down
|
||||
// this.do = this.returnToPlayer
|
||||
// Matter.Body.setDensity(this, 0.0005); //reduce density on return
|
||||
// if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
|
||||
// this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
|
||||
// }
|
||||
// } else {
|
||||
// //if not enough energy
|
||||
// if (m.energy < 0.05) this.dropCaughtPowerUp()
|
||||
// // const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
|
||||
// // this.force.x -= returnForce.x
|
||||
// // this.force.y -= returnForce.y
|
||||
// // this.frictionAir = 0.002
|
||||
// // this.do = () => {
|
||||
// // if (this.speed < 20) this.force.y += 0.0005 * this.mass;
|
||||
// // }
|
||||
|
||||
// // } else {
|
||||
// //return to player
|
||||
// this.do = this.returnToPlayer
|
||||
// this.endCycle = simulation.cycle + 60
|
||||
// Matter.Body.setDensity(this, 0.0005); //reduce density on return
|
||||
// if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
|
||||
// this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
|
||||
// //recoil on catching
|
||||
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
// player.force.x += momentum.x
|
||||
// player.force.y += momentum.y
|
||||
// // }
|
||||
// }
|
||||
// //grappling hook
|
||||
// if (input.fire && Matter.Query.collides(this, map).length) {
|
||||
// Matter.Body.setPosition(this, Vector.add(this.position, {
|
||||
// x: 20 * Math.cos(this.angle),
|
||||
// y: 20 * Math.sin(this.angle)
|
||||
// }))
|
||||
// if (Matter.Query.collides(this, map).length) {
|
||||
// Matter.Body.setVelocity(this, {
|
||||
// x: 0,
|
||||
// y: 0
|
||||
// });
|
||||
// Matter.Sleeping.set(this, true)
|
||||
// this.endCycle = simulation.cycle + 5
|
||||
// this.dropCaughtPowerUp()
|
||||
// this.do = () => {
|
||||
// //between player nose and the grapple
|
||||
// const sub = Vector.sub(this.vertices[0], {
|
||||
// x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
// y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
// })
|
||||
// let dist = Vector.magnitude(sub)
|
||||
// if (input.fire) {
|
||||
// // m.fireCDcycle = m.cycle + 30; // cool down if out of energy
|
||||
// m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
|
||||
// this.endCycle = simulation.cycle + 10
|
||||
// if (input.down) { //down
|
||||
// dist = 0
|
||||
// player.force.y += 5 * player.mass * simulation.g;
|
||||
// }
|
||||
// if (m.energy > this.drain) {
|
||||
// Matter.Body.setVelocity(player, {
|
||||
// x: player.velocity.x * 0.8,
|
||||
// y: player.velocity.y * 0.8
|
||||
// });
|
||||
// const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), 200))
|
||||
// player.force.x += pull.x
|
||||
// player.force.y += pull.y
|
||||
|
||||
// if (dist > 500) {
|
||||
// m.energy -= this.drain
|
||||
// if (m.energy < 0) {
|
||||
// this.endCycle = 0;
|
||||
// if (m.cycle + 50 < m.fireCDcycle) m.fireCDcycle = m.cycle + 50
|
||||
// // refund ammo
|
||||
// b.guns[9].ammo++;
|
||||
// simulation.updateGunHUD();
|
||||
// // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
// // if (b.guns[i].name === "harpoon") {
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (tech.isImmuneGrapple && m.immuneCycle < m.cycle + 10) {
|
||||
// m.immuneCycle = m.cycle + 10;
|
||||
// if (m.energy > 0.001) {
|
||||
// m.energy -= 0.001
|
||||
// } else { //out of energy
|
||||
// Matter.Sleeping.set(this, false)
|
||||
// this.collisionFilter.category = 0
|
||||
// this.collisionFilter.mask = 0
|
||||
// this.do = this.returnToPlayer
|
||||
// this.endCycle = simulation.cycle + 60
|
||||
// m.fireCDcycle = m.cycle + 120; //fire cooldown
|
||||
// //recoil on catching
|
||||
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
// player.force.x += momentum.x
|
||||
// player.force.y += momentum.y
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// Matter.Sleeping.set(this, false)
|
||||
// this.collisionFilter.category = 0
|
||||
// this.collisionFilter.mask = 0
|
||||
// this.do = this.returnToPlayer
|
||||
// this.endCycle = simulation.cycle + 60
|
||||
// //recoil on catching
|
||||
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
// player.force.x += momentum.x
|
||||
// player.force.y += momentum.y
|
||||
// }
|
||||
// this.draw();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
|
||||
// this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
|
||||
// this.draw()
|
||||
// },
|
||||
// });
|
||||
// Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
// },
|
||||
harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {
|
||||
const me = bullet.length;
|
||||
const returnRadius = 100 * Math.sqrt(harpoonSize)
|
||||
@@ -2274,12 +2013,43 @@ const b = {
|
||||
}
|
||||
}
|
||||
if (tech.isFoamBall) {
|
||||
for (let i = 0, len = Math.min(50, 2.5 + 3 * Math.sqrt(this.mass)); i < len; i++) {
|
||||
for (let i = 0, len = Math.min(30, 2 + 2 * Math.sqrt(this.mass)); i < len; i++) {
|
||||
const radius = 5 + 8 * Math.random()
|
||||
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
|
||||
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
|
||||
}
|
||||
}
|
||||
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
|
||||
Matter.Body.setDensity(this, 1.8 * tech.harpoonDensity); //+90% damage after pick up power up for 8 seconds
|
||||
} else if (tech.isHarpoonFullHealth && who.health === 1) {
|
||||
Matter.Body.setDensity(this, 1.9 * tech.harpoonDensity); //+90% damage if mob has full health do
|
||||
simulation.ephemera.push({
|
||||
name: "harpoon outline",
|
||||
count: 2, //cycles before it self removes
|
||||
vertices: this.vertices,
|
||||
do() {
|
||||
this.count--
|
||||
if (this.count < 0) simulation.removeEphemera(this.name)
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
|
||||
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
|
||||
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
ctx.lineJoin = "miter"
|
||||
ctx.miterLimit = 20;
|
||||
ctx.lineWidth = 40;
|
||||
ctx.strokeStyle = "rgba(255,0,100,0.35)";
|
||||
ctx.stroke();
|
||||
ctx.lineWidth = 10;
|
||||
ctx.strokeStyle = `#f07`;
|
||||
ctx.stroke();
|
||||
ctx.lineJoin = "round"
|
||||
ctx.miterLimit = 5
|
||||
ctx.fillStyle = "#000"
|
||||
ctx.fill();
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
caughtPowerUp: null,
|
||||
dropCaughtPowerUp() {
|
||||
@@ -2300,7 +2070,7 @@ const b = {
|
||||
this.caughtPowerUp.effect();
|
||||
Matter.Composite.remove(engine.world, this.caughtPowerUp);
|
||||
powerUp.splice(index, 1);
|
||||
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.006 is normal
|
||||
if (tech.isHarpoonPowerUp) tech.harpoonPowerUpCycle = simulation.cycle
|
||||
} else {
|
||||
this.dropCaughtPowerUp()
|
||||
}
|
||||
@@ -2308,29 +2078,26 @@ const b = {
|
||||
this.dropCaughtPowerUp()
|
||||
}
|
||||
},
|
||||
drawToggleHarpoon() {
|
||||
drawDamageAura() {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
|
||||
for (let j = 1, len = this.vertices.length; j < len; j += 1) ctx.lineTo(this.vertices[j].x, this.vertices[j].y);
|
||||
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
ctx.lineJoin = "miter"
|
||||
ctx.miterLimit = 100;
|
||||
ctx.lineWidth = 60;
|
||||
ctx.strokeStyle = "rgba(0,255,255,0.25)";
|
||||
ctx.miterLimit = 20;
|
||||
ctx.lineWidth = 15;
|
||||
ctx.strokeStyle = "rgba(255,0,100,0.25)";
|
||||
ctx.stroke();
|
||||
ctx.lineWidth = 20;
|
||||
ctx.strokeStyle = "rgb(0,255,255)";
|
||||
ctx.lineWidth = 4;
|
||||
ctx.strokeStyle = `#f07`;
|
||||
ctx.stroke();
|
||||
ctx.lineJoin = "round"
|
||||
ctx.miterLimit = 10
|
||||
ctx.miterLimit = 5
|
||||
ctx.fillStyle = "#000"
|
||||
ctx.fill();
|
||||
},
|
||||
drawString() {
|
||||
const where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
}
|
||||
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
|
||||
const sub = Vector.sub(where, this.vertices[0])
|
||||
const perpendicular = Vector.mult(Vector.normalise(Vector.perp(sub)), this.drawStringFlip * Math.min(80, 10 + this.drawStringControlMagnitude / (10 + Vector.magnitude(sub))))
|
||||
const controlPoint = Vector.add(Vector.add(where, Vector.mult(sub, -0.5)), perpendicular)
|
||||
@@ -2384,10 +2151,7 @@ const b = {
|
||||
grabPowerUp() { //grab power ups near the tip of the harpoon
|
||||
if (this.caughtPowerUp) {
|
||||
Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
|
||||
Matter.Body.setVelocity(this.caughtPowerUp, {
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
|
||||
} else { //&& simulation.cycle % 2
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
const radius = powerUp[i].circleRadius + 50
|
||||
@@ -2395,10 +2159,7 @@ const b = {
|
||||
if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
|
||||
powerUp[i].isGrabbed = true
|
||||
this.caughtPowerUp = powerUp[i]
|
||||
Matter.Body.setVelocity(powerUp[i], {
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
|
||||
Matter.Body.setPosition(powerUp[i], this.vertices[2])
|
||||
powerUp[i].collisionFilter.category = 0
|
||||
powerUp[i].collisionFilter.mask = 0
|
||||
@@ -2459,15 +2220,15 @@ const b = {
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
if (tech.isHarpoonPowerUp && bullet[me].density > 0.01) {
|
||||
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) { //8 seconds
|
||||
if (isReturn) {
|
||||
bullet[me].draw = function () {
|
||||
this.drawToggleHarpoon()
|
||||
this.drawDamageAura()
|
||||
this.drawString()
|
||||
}
|
||||
} else {
|
||||
bullet[me].draw = function () {
|
||||
this.drawToggleHarpoon()
|
||||
this.drawDamageAura()
|
||||
}
|
||||
}
|
||||
} else if (isReturn) {
|
||||
@@ -2628,15 +2389,9 @@ const b = {
|
||||
if (dist < radius * radius) {
|
||||
if (mob[i].speed > 2) {
|
||||
if (mob[i].isBoss || mob[i].isShielded) {
|
||||
Matter.Body.setVelocity(mob[i], {
|
||||
x: mob[i].velocity.x * 0.95,
|
||||
y: mob[i].velocity.y * 0.95
|
||||
});
|
||||
Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.95, y: mob[i].velocity.y * 0.95 });
|
||||
} else {
|
||||
Matter.Body.setVelocity(mob[i], {
|
||||
x: mob[i].velocity.x * 0.25,
|
||||
y: mob[i].velocity.y * 0.25
|
||||
});
|
||||
Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.25, y: mob[i].velocity.y * 0.25 });
|
||||
}
|
||||
}
|
||||
// Matter.Body.setPosition(this, Vector.add(this.position, mob[i].velocity)) //move with the medium
|
||||
@@ -5139,39 +4894,39 @@ const b = {
|
||||
for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.soundBotCount; i++) b.soundBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
for (let i = 0; i < tech.missileBotCount; i++) b.missileBot({
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, false)
|
||||
})
|
||||
if (tech.isIntangible && m.isCloak) {
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType) bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield
|
||||
@@ -5250,7 +5005,6 @@ const b = {
|
||||
|
||||
},
|
||||
setDynamoBotDelay() {
|
||||
//reorder orbital bot positions around a circle
|
||||
let total = 0
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType === 'dynamo') total++
|
||||
@@ -5259,13 +5013,17 @@ const b = {
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType === 'dynamo') {
|
||||
count++
|
||||
const step = Math.max(60 - 3 * total, 20)
|
||||
bullet[i].followDelay = (step * count) % 600
|
||||
const step = Math.max(60 - 3 * total, 10)
|
||||
if (bullet[i].isKeep) {
|
||||
bullet[i].followDelay = (step * count) % 600
|
||||
} else {
|
||||
bullet[i].followDelay = Math.floor(step * bullet.length * Math.random()) % 600
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
dynamoBot(position = player.position, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.dynamoBot()`);
|
||||
dynamoBot(position = player.position, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.dynamoBot()`);
|
||||
const me = bullet.length;
|
||||
bullet[me] = Bodies.polygon(position.x, position.y, 5, 10, {
|
||||
isUpgraded: tech.isDynamoBotUpgrade,
|
||||
@@ -5274,7 +5032,8 @@ const b = {
|
||||
frictionStatic: 0,
|
||||
frictionAir: 0.02,
|
||||
spin: 0.07 * (Math.random() < 0.5 ? -1 : 1),
|
||||
// isStatic: true,
|
||||
// isStatic: true,
|
||||
isKeep: isKeep,
|
||||
isSensor: true,
|
||||
restitution: 0,
|
||||
dmg: 0, // 0.14 //damage done in addition to the damage from momentum
|
||||
@@ -5359,17 +5118,14 @@ const b = {
|
||||
}
|
||||
}
|
||||
let history = m.history[(m.cycle - this.followDelay) % 600]
|
||||
Matter.Body.setPosition(this, {
|
||||
x: history.position.x,
|
||||
y: history.position.y - history.yOff + 24.2859
|
||||
}) //bullets move with player
|
||||
Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
|
||||
}
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
b.setDynamoBotDelay()
|
||||
},
|
||||
nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.nailBot()`);
|
||||
nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.nailBot()`);
|
||||
const me = bullet.length;
|
||||
const dir = m.angle;
|
||||
const RADIUS = (12 + 4 * Math.random())
|
||||
@@ -5386,8 +5142,8 @@ const b = {
|
||||
// lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20,
|
||||
lastLookCycle: simulation.cycle + 60 * Math.random(),
|
||||
delay: Math.floor((tech.isNailBotUpgrade ? 18 : 85) * b.fireCDscale),
|
||||
acceleration: 0.005 * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(),
|
||||
acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100,
|
||||
endCycle: Infinity,
|
||||
classType: "bullet",
|
||||
collisionFilter: {
|
||||
@@ -5433,8 +5189,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.missileBot()`);
|
||||
missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.missileBot()`);
|
||||
const me = bullet.length;
|
||||
bullet[me] = Bodies.rectangle(position.x, position.y, 28, 11, {
|
||||
botType: "missile",
|
||||
@@ -5504,8 +5260,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.foamBot()`);
|
||||
foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.foamBot()`);
|
||||
const me = bullet.length;
|
||||
const dir = m.angle;
|
||||
const RADIUS = (10 + 5 * Math.random())
|
||||
@@ -5524,8 +5280,8 @@ const b = {
|
||||
fireCount: 0,
|
||||
fireLimit: 5 + 2 * tech.isFoamBotUpgrade,
|
||||
delay: Math.floor((145 + (tech.isFoamBotUpgrade ? 0 : 230)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
|
||||
acceleration: 0.005 * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move
|
||||
acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move
|
||||
endCycle: Infinity,
|
||||
classType: "bullet",
|
||||
collisionFilter: {
|
||||
@@ -5625,8 +5381,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
soundBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.soundBot()`);
|
||||
soundBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.soundBot()`);
|
||||
const me = bullet.length;
|
||||
const dir = m.angle;
|
||||
bullet[me] = Bodies.rectangle(position.x, position.y, 12, 30, {
|
||||
@@ -5644,8 +5400,8 @@ const b = {
|
||||
fireCount: 0,
|
||||
fireLimit: 5 + 2 * tech.isSoundBotUpgrade,
|
||||
delay: Math.floor((120 + (tech.isSoundBotUpgrade ? 0 : 70)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
|
||||
acceleration: 0.005 * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move
|
||||
acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move
|
||||
endCycle: Infinity,
|
||||
classType: "bullet",
|
||||
collisionFilter: {
|
||||
@@ -5791,11 +5547,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
laserBot(position = {
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.laserBot()`);
|
||||
laserBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.laserBot()`);
|
||||
const me = bullet.length;
|
||||
const dir = m.angle;
|
||||
const RADIUS = (14 + 6 * Math.random())
|
||||
@@ -5833,10 +5586,7 @@ const b = {
|
||||
const mag = Math.min(farAway, 4) * this.mass * this.acceleration
|
||||
this.force = Vector.mult(Vector.normalise(Vector.sub(playerPos, this.position)), mag)
|
||||
//manual friction to not lose rotational velocity
|
||||
Matter.Body.setVelocity(this, {
|
||||
x: this.velocity.x * 0.95,
|
||||
y: this.velocity.y * 0.95
|
||||
});
|
||||
Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 });
|
||||
//find targets
|
||||
if (!(simulation.cycle % this.lookFrequency)) {
|
||||
this.lockedOn = null;
|
||||
@@ -5858,11 +5608,13 @@ const b = {
|
||||
}
|
||||
}
|
||||
//randomize position relative to player
|
||||
if (Math.random() < 0.15) {
|
||||
const range = 110 + 4 * b.totalBots()
|
||||
this.offPlayer = {
|
||||
x: range * (Math.random() - 0.5),
|
||||
y: range * (Math.random() - 0.5) - 20,
|
||||
if (Math.random() < 0.1) {
|
||||
if (isKeep) {
|
||||
const range = 110 + 4 * b.totalBots()
|
||||
this.offPlayer = { x: range * (Math.random() - 0.5), y: range * (Math.random() - 0.5) - 20, }
|
||||
} else {
|
||||
const range = 110 + 4 * b.totalBots() + 100 * Math.random()
|
||||
this.offPlayer = Vector.mult(Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random()), range)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6040,11 +5792,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
boomBot(position = {
|
||||
x: player.position.x + 50 * (Math.random() - 0.5),
|
||||
y: player.position.y + 50 * (Math.random() - 0.5)
|
||||
}, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.boomBot()`);
|
||||
boomBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.boomBot()`);
|
||||
const me = bullet.length;
|
||||
const dir = m.angle;
|
||||
const RADIUS = (7 + 2 * Math.random())
|
||||
@@ -6059,9 +5808,9 @@ const b = {
|
||||
dmg: 0,
|
||||
minDmgSpeed: 0,
|
||||
lookFrequency: 43 + Math.floor(7 * Math.random()) - 13 * tech.isBoomBotUpgrade,
|
||||
acceleration: 0.005 * (1 + 0.5 * Math.random()),
|
||||
acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()),
|
||||
attackAcceleration: 0.012 + 0.006 * tech.isBoomBotUpgrade,
|
||||
range: 500 * (1 + 0.1 * Math.random()) + 350 * tech.isBoomBotUpgrade,
|
||||
range: 500 * (1 + 0.1 * Math.random()) + 350 * tech.isBoomBotUpgrade + !isKeep * 100,
|
||||
endCycle: Infinity,
|
||||
classType: "bullet",
|
||||
collisionFilter: {
|
||||
@@ -6131,8 +5880,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.plasmaBot()`);
|
||||
plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.plasmaBot()`);
|
||||
const me = bullet.length;
|
||||
const dir = m.angle;
|
||||
const RADIUS = 21
|
||||
@@ -6305,8 +6054,8 @@ const b = {
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
orbitBot(position = player.position, isConsole = true) {
|
||||
if (isConsole) simulation.makeTextLog(`<span class='color-var'>b</span>.orbitBot()`);
|
||||
orbitBot(position = player.position, isKeep = true) {
|
||||
// if (isKeep) simulation.makeTextLog(`<span class='color-var'>b</span>.orbitBot()`);
|
||||
const me = bullet.length;
|
||||
bullet[me] = Bodies.polygon(position.x, position.y, 9, 12, {
|
||||
isUpgraded: tech.isOrbitBotUpgrade,
|
||||
@@ -6316,6 +6065,7 @@ const b = {
|
||||
frictionAir: 1,
|
||||
isStatic: true,
|
||||
isSensor: true,
|
||||
isKeep: isKeep,
|
||||
restitution: 0,
|
||||
dmg: 0, // 0.14 //damage done in addition to the damage from momentum
|
||||
minDmgSpeed: 0,
|
||||
@@ -6330,17 +6080,17 @@ const b = {
|
||||
//reorder orbital bot positions around a circle
|
||||
let totalOrbitalBots = 0
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType === 'orbit' && bullet[i] !== this) totalOrbitalBots++
|
||||
if (bullet[i].botType === 'orbit' && bullet[i] !== this && bullet[i].isKeep) totalOrbitalBots++
|
||||
}
|
||||
let index = 0
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType === 'orbit' && bullet[i] !== this) {
|
||||
if (bullet[i].botType === 'orbit' && bullet[i] !== this && bullet[i].isKeep) {
|
||||
bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI
|
||||
index++
|
||||
}
|
||||
}
|
||||
},
|
||||
range: 190 + 130 * tech.isOrbitBotUpgrade, //range is set in bot upgrade too!
|
||||
range: 190 + 130 * tech.isOrbitBotUpgrade + !isKeep * 60 * (0.5 - Math.random()), //range is set in bot upgrade too!
|
||||
orbitalSpeed: 0,
|
||||
phase: 2 * Math.PI * Math.random(),
|
||||
do() {
|
||||
@@ -6377,10 +6127,7 @@ const b = {
|
||||
}
|
||||
//orbit player
|
||||
const time = simulation.cycle * this.orbitalSpeed + this.phase
|
||||
const orbit = {
|
||||
x: Math.cos(time),
|
||||
y: Math.sin(time) //*1.1
|
||||
}
|
||||
const orbit = { x: Math.cos(time), y: Math.sin(time) }
|
||||
Matter.Body.setPosition(this, Vector.add(m.pos, Vector.mult(orbit, this.range))) //bullets move with player
|
||||
}
|
||||
})
|
||||
@@ -6392,11 +6139,11 @@ const b = {
|
||||
//reorder orbital bot positions around a circle
|
||||
let totalOrbitalBots = 0
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType === 'orbit') totalOrbitalBots++
|
||||
if (bullet[i].botType === 'orbit' && bullet[i].isKeep) totalOrbitalBots++
|
||||
}
|
||||
let index = 0
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
if (bullet[i].botType === 'orbit') {
|
||||
if (bullet[i].botType === 'orbit' && bullet[i].isKeep) {
|
||||
bullet[i].phase = (index / totalOrbitalBots) * 2 * Math.PI
|
||||
index++
|
||||
}
|
||||
@@ -6739,7 +6486,7 @@ const b = {
|
||||
name: "shotgun", //1
|
||||
// description: `fire a wide <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() {
|
||||
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,
|
||||
ammoPack: 3.5,
|
||||
@@ -7995,7 +7742,6 @@ const b = {
|
||||
}
|
||||
//fire
|
||||
if ((!input.fire && this.charge > 0.6)) {
|
||||
// tech.harpoonDensity = 0.0065 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
const where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
@@ -8067,8 +7813,6 @@ const b = {
|
||||
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.03 : 0.06)
|
||||
player.force.x -= recoil.x
|
||||
player.force.y -= recoil.y
|
||||
// tech.harpoonDensity = 0.0065 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
|
||||
const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
|
||||
const thrust = 0.15 * (this.charge)
|
||||
if (tech.extraHarpoons) {
|
||||
@@ -8263,12 +8007,8 @@ const b = {
|
||||
count++
|
||||
if (!(count % delay) && this.ammo > 0) {
|
||||
this.ammo--
|
||||
b.harpoon({
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
}, null, angle, harpoonSize, true, totalCycles)
|
||||
b.harpoon({ x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, null, angle, harpoonSize, true, totalCycles)
|
||||
angle += SPREAD
|
||||
tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
}
|
||||
if (count < num * delay && m.alive) requestAnimationFrame(harpoonDelay);
|
||||
}
|
||||
@@ -8298,7 +8038,6 @@ const b = {
|
||||
} else {
|
||||
b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles)
|
||||
}
|
||||
tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
}
|
||||
m.fireCDcycle = m.cycle + 5 + 35 * b.fireCDscale + 60 * (m.energy < 0.05) + tech.extraHarpoons // cool down is set when harpoon bullet returns to player
|
||||
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.015 : 0.035)
|
||||
|
||||
@@ -967,7 +967,6 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
|
||||
startExperiment() { //start playing the game after exiting the experiment menu
|
||||
build.isExperimentSelection = false;
|
||||
spawn.setSpawnList(); //gives random mobs, not starter mobs
|
||||
spawn.setSpawnList();
|
||||
if (b.inventory.length > 0) {
|
||||
b.activeGun = b.inventory[0] //set first gun to active gun
|
||||
b.inventoryGun = 0;
|
||||
|
||||
526
js/level.js
526
js/level.js
@@ -11,7 +11,7 @@ const level = {
|
||||
// playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
|
||||
//see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later
|
||||
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
|
||||
communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave"],
|
||||
communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo"],
|
||||
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
|
||||
levels: [],
|
||||
start() {
|
||||
@@ -19,17 +19,15 @@ const level = {
|
||||
// simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
|
||||
// simulation.isHorizontalFlipped = true
|
||||
// tech.giveTech("performance")
|
||||
// level.difficultyIncrease(5 * 4) //30 is near max on hard //60 is near max on why
|
||||
// spawn.setSpawnList();
|
||||
// spawn.setSpawnList();
|
||||
// m.maxHealth = m.health = 100
|
||||
// level.difficultyIncrease(8 * 2) //30 is near max on hard //60 is near max on why
|
||||
// m.maxHealth = m.health = 1
|
||||
// m.maxEnergy = m.energy = 10000000
|
||||
// tech.isRerollDamage = true
|
||||
// powerUps.research.changeRerolls(99999)
|
||||
// m.immuneCycle = Infinity //you can't take damage
|
||||
// tech.tech[297].frequency = 100
|
||||
// m.couplingChange(10)
|
||||
// m.setField("grappling hook") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
|
||||
// m.setField("metamaterial cloaking") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
|
||||
// tech.isHookWire = true
|
||||
// m.energy = 0
|
||||
// simulation.molecularMode = 2
|
||||
@@ -37,22 +35,23 @@ const level = {
|
||||
// b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
|
||||
// b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
|
||||
// b.guns[8].ammo = 100000000
|
||||
// requestAnimationFrame(() => { tech.giveTech("MACHO") });
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("degenerate matter")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("reel")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("tokamak")
|
||||
// requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") });
|
||||
// for (let i = 0; i < 1; i++) tech.giveTech("laser-bot upgrade")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("rupture")
|
||||
// requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") });
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("Higgs mechanism")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("topological defect")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("Hilbert space")
|
||||
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") });
|
||||
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) });
|
||||
|
||||
// for (let i = 0; i < 1; i++) tech.giveTech("cascading failure")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("induction furnace")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense")
|
||||
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
|
||||
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
|
||||
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling");
|
||||
|
||||
// level.unchartedCave();
|
||||
// level.skyscrapers();
|
||||
|
||||
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
|
||||
// for (let i = 0; i < 5; ++i) spawn.starter(1900, -500)
|
||||
// for (let i = 0; i < 10; ++i) spawn.starter(1900, -500, 50)
|
||||
// for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500)
|
||||
// spawn.beetleBoss(1900, -500, 25)
|
||||
// spawn.slasher2(2000, -1150)
|
||||
@@ -64,13 +63,14 @@ const level = {
|
||||
// for (let i = 0; i < 40; ++i) tech.giveTech()
|
||||
|
||||
level[simulation.isTraining ? "walk" : "intro"]() //normal starting level **************************************************
|
||||
|
||||
// spawn.bodyRect(2425, -120, 200, 200);
|
||||
// console.log(body[body.length - 1].mass)
|
||||
// simulation.isAutoZoom = false; //look in close
|
||||
// simulation.zoomScale *= 0.5;
|
||||
// simulation.setZoom();
|
||||
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
|
||||
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "boost");
|
||||
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "boost");
|
||||
// for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo");
|
||||
// for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false);
|
||||
//lore testing
|
||||
@@ -2159,8 +2159,9 @@ const level = {
|
||||
spawn.mapRect(475, -25, 25, 50); //edge shelf
|
||||
},
|
||||
intro() {
|
||||
// console.log(level.levelsCleared)
|
||||
if (level.levelsCleared === 0) { //if this is the 1st level of the game
|
||||
if (simulation.difficultyMode > 2) spawn.setSpawnList() // hard and why difficulty don't begin with starter mobs
|
||||
|
||||
//wait to spawn power ups until unpaused
|
||||
//power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode
|
||||
const goal = simulation.cycle + 10
|
||||
@@ -2172,10 +2173,17 @@ const level = {
|
||||
} else {
|
||||
powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125);
|
||||
}
|
||||
if (simulation.difficultyMode < 5) {
|
||||
if (simulation.difficultyMode < 5) { //hard, normal and easy
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false);
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
|
||||
}
|
||||
if (simulation.difficultyMode < 3) { //normal and easy
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); //not on why difficulty
|
||||
}
|
||||
if (simulation.difficultyMode < 2) { //easy
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
|
||||
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(cycle);
|
||||
@@ -2548,7 +2556,6 @@ const level = {
|
||||
|
||||
|
||||
if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run
|
||||
// spawn.setSpawnList();
|
||||
spawn.pickList.splice(0, 1);
|
||||
spawn.pickList.push('starter');
|
||||
spawn.pickList.splice(0, 1);
|
||||
@@ -2662,6 +2669,7 @@ const level = {
|
||||
if (gateButton.isUp) {
|
||||
gateButton.query();
|
||||
if (!gateButton.isUp) {
|
||||
simulation.makeTextLog(`station gate opened`, 360);
|
||||
if (stationNumber > 0) {
|
||||
if (!isExitOpen && gatesOpenRight < stationNumber) level.newLevelOrPhase() //run some new level tech effects
|
||||
gatesOpenRight = stationNumber
|
||||
@@ -2673,7 +2681,7 @@ const level = {
|
||||
gatesOpenRight = stationNumber
|
||||
}
|
||||
if (Math.abs(stationNumber) > 0 && ((Math.abs(stationNumber) + 1) % stationList.length) === 0) {
|
||||
simulation.makeTextLog(`exit opened`);
|
||||
simulation.makeTextLog(`level exit opened`, 360);
|
||||
isExitOpen = true;
|
||||
}
|
||||
}
|
||||
@@ -2725,13 +2733,12 @@ const level = {
|
||||
var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
|
||||
}
|
||||
}
|
||||
|
||||
spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
|
||||
spawn.mapRect(x + -1775, -1600, 3400, 1100); //center pillar
|
||||
spawn.mapRect(x + -1775, -1600, 3400, 1000); //center pillar
|
||||
spawn.mapRect(x + -4100, -3325, 8000, 700); //roof
|
||||
spawn.mapRect(x + -4100, -3325, 325, 1500);
|
||||
spawn.mapRect(x + 3500, -3325, 400, 1500);
|
||||
spawn.mapRect(x + -225, -575, 450, 425); //lower portal blocks
|
||||
spawn.mapRect(x + -225, -700, 450, 600); //lower portal blocks
|
||||
|
||||
//upper parts
|
||||
spawn.mapRect(x + -1425, -2400, 1900, 50);
|
||||
@@ -3025,7 +3032,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
() => { //portal fling
|
||||
const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2083 },]
|
||||
const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2080 },]
|
||||
const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
|
||||
if (isExitOpen) {
|
||||
level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
|
||||
@@ -3219,7 +3226,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
() => { //jump pads and 6 sided platforms
|
||||
const buttonsCoords = [{ x: x + 275, y: -1817 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2420 }, { x: x - 2100, y: -1995 }]
|
||||
const buttonsCoords = [{ x: x + 278, y: -1814 }, { x: x + 778, y: -1814 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2425 }, { x: x - 2100, y: -1995 }]
|
||||
const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
|
||||
if (isExitOpen) {
|
||||
level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
|
||||
@@ -3375,7 +3382,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
]
|
||||
// stations[1]() //for testing a specific station
|
||||
// stations[4]() //for testing a specific station
|
||||
stations[stationList[Math.abs(stationNumber % stationList.length)]]() //*************** run this one when uploading
|
||||
//add in standard station map infrastructure
|
||||
spawn.mapRect(x + -8000, 0, 16000, 800);//tunnel floor
|
||||
@@ -5034,10 +5041,12 @@ const level = {
|
||||
powerUps.directSpawn(x + 1950, y - 1525, "ammo");
|
||||
powerUps.directSpawn(x + 1900, y - 1525, "ammo");
|
||||
spawn.hopMotherBoss(x + 800, y + -2200)
|
||||
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
|
||||
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
|
||||
for (let i = 0; i < 4; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
|
||||
for (let i = 0; i < 4; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
|
||||
spawn.hopper(x + 1550, y + -775);
|
||||
spawn.hopper(x + 500, y + -775);
|
||||
spawn.hopper(x + 500, y + -2200);
|
||||
spawn.hopper(x + 1100, y + -2200);
|
||||
spawn.hopMother(x + 1400, y + -775);
|
||||
spawn.hopMother(x + 550, y + -775);
|
||||
spawn.hopMother(x + 525, y + -1475);
|
||||
@@ -30084,9 +30093,6 @@ const level = {
|
||||
},
|
||||
unchartedCave() {
|
||||
simulation.makeTextLog(`<strong>unchartedCave</strong> by <span class='color-var'>3xionDev</span>`);
|
||||
//lore.unlockTesting();
|
||||
//simulation.enableConstructMode();
|
||||
level.difficultyIncrease(15);
|
||||
level.setPosToSpawn(0, -50); //normal spawn
|
||||
level.exit.x = 20985;
|
||||
level.exit.y = 2816;
|
||||
@@ -30095,7 +30101,6 @@ const level = {
|
||||
level.defaultZoom = 1900
|
||||
simulation.zoomTransition(level.defaultZoom)
|
||||
document.body.style.backgroundColor = "#979797";
|
||||
// color.map = "#444" //custom map color
|
||||
|
||||
spawn.randomMob(1000, -975, 0);
|
||||
spawn.randomMob(2550, -575, 0);
|
||||
@@ -30490,15 +30495,462 @@ const level = {
|
||||
spawn.randomGroup(5835, -532, 0.4);
|
||||
if (simulation.difficulty > 1) spawn.randomLevelBoss(18823, 2191);
|
||||
spawn.secondaryBossChance(20217, 1913)
|
||||
|
||||
|
||||
|
||||
level.custom = () => {
|
||||
level.exit.drawAndCheck();
|
||||
|
||||
level.enter.draw();
|
||||
};
|
||||
},
|
||||
dojo() { // By weird_pusheen
|
||||
simulation.makeTextLog(`<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 **********************************************
|
||||
|
||||
97
js/mob.js
97
js/mob.js
@@ -242,7 +242,7 @@ const mobs = {
|
||||
deathCount: 0,
|
||||
mobSpawnWithHealth: 1,
|
||||
setMobSpawnHealth() {
|
||||
mobs.mobSpawnWithHealth = 0.89 ** (tech.mobSpawnWithHealth)
|
||||
mobs.mobSpawnWithHealth = 0.88 ** (tech.mobSpawnWithHealth)
|
||||
},
|
||||
//**********************************************************************************************
|
||||
//**********************************************************************************************
|
||||
@@ -1133,6 +1133,85 @@ const mobs = {
|
||||
if ((!this.isShielded || isBypassShield) && this.alive) {
|
||||
if (dmg !== Infinity) {
|
||||
dmg *= tech.damageFromTech()
|
||||
if (this.isDropPowerUp) {
|
||||
if (this.health === 1) {
|
||||
if (tech.isMobFullHealth) {
|
||||
dmg *= 1.55
|
||||
|
||||
simulation.ephemera.push({
|
||||
name: "damage outline",
|
||||
count: 5, //cycles before it self removes
|
||||
vertices: this.vertices,
|
||||
do() {
|
||||
this.count--
|
||||
if (this.count < 0) simulation.removeEphemera(this.name)
|
||||
//draw body
|
||||
ctx.beginPath();
|
||||
const vertices = this.vertices;
|
||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
||||
for (let j = 1, len = vertices.length; j < len; ++j) {
|
||||
ctx.lineTo(vertices[j].x, vertices[j].y);
|
||||
}
|
||||
ctx.lineTo(vertices[0].x, vertices[0].y);
|
||||
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
|
||||
ctx.strokeStyle = `#f05` //"rgba(150,150,225,0.5)";
|
||||
ctx.stroke();
|
||||
},
|
||||
})
|
||||
} else if (tech.isMobFullHealthCloak) {
|
||||
dmg *= 1.88
|
||||
|
||||
simulation.ephemera.push({
|
||||
name: "damage outline",
|
||||
count: 7, //cycles before it self removes
|
||||
vertices: this.vertices,
|
||||
do() {
|
||||
this.count--
|
||||
if (this.count < 0) simulation.removeEphemera(this.name)
|
||||
//draw body
|
||||
ctx.beginPath();
|
||||
const vertices = this.vertices;
|
||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
||||
for (let j = 1, len = vertices.length; j < len; ++j) {
|
||||
ctx.lineTo(vertices[j].x, vertices[j].y);
|
||||
}
|
||||
ctx.lineTo(vertices[0].x, vertices[0].y);
|
||||
ctx.fillStyle = `rgba(255,0,100,0.15)` //"rgba(150,150,225,0.5)";
|
||||
ctx.fill()
|
||||
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
|
||||
ctx.strokeStyle = `#f08` //"rgba(150,150,225,0.5)";
|
||||
ctx.stroke();
|
||||
},
|
||||
})
|
||||
}
|
||||
} else if (tech.isMobLowHealth && this.health < 0.25) {
|
||||
dmg *= 3.22
|
||||
|
||||
simulation.ephemera.push({
|
||||
name: "damage outline",
|
||||
count: 2, //cycles before it self removes
|
||||
vertices: this.vertices,
|
||||
do() {
|
||||
this.count--
|
||||
if (this.count < 0) simulation.removeEphemera(this.name)
|
||||
//draw body
|
||||
ctx.beginPath();
|
||||
const vertices = this.vertices;
|
||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
||||
for (let j = 1, len = vertices.length; j < len; ++j) {
|
||||
ctx.lineTo(vertices[j].x, vertices[j].y);
|
||||
}
|
||||
ctx.lineTo(vertices[0].x, vertices[0].y);
|
||||
ctx.fillStyle = `rgba(255,50,100,0.2)` //"rgba(150,150,225,0.5)";
|
||||
ctx.fill()
|
||||
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
|
||||
ctx.strokeStyle = `#f38` //"rgba(150,150,225,0.5)";
|
||||
ctx.stroke();
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//mobs specific damage changes
|
||||
if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 33% dmg at max range of 3000
|
||||
dmg *= this.damageReduction
|
||||
@@ -1143,6 +1222,7 @@ const mobs = {
|
||||
}
|
||||
dmg /= Math.sqrt(this.mass)
|
||||
}
|
||||
|
||||
this.health -= dmg
|
||||
//this.fill = this.color + this.health + ')';
|
||||
this.onDamage(dmg); //custom damage effects
|
||||
@@ -1187,7 +1267,7 @@ const mobs = {
|
||||
leaveBody: true,
|
||||
isDropPowerUp: true,
|
||||
death() {
|
||||
if (tech.collidePowerUps && Math.random() < tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups
|
||||
if (tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups
|
||||
this.onDeath(this); //custom death effects
|
||||
this.removeConsBB();
|
||||
this.alive = false; //triggers mob removal in mob[i].replace(i)
|
||||
@@ -1261,22 +1341,23 @@ const mobs = {
|
||||
}
|
||||
if (tech.isBotSpawnerReset) {
|
||||
for (let i = 0, len = bullet.length; i < len; i++) {
|
||||
if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 780 //13 seconds
|
||||
if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 900 //15 seconds
|
||||
}
|
||||
}
|
||||
if (Math.random() < tech.botSpawner) {
|
||||
b.randomBot(this.position, false)
|
||||
bullet[bullet.length - 1].endCycle = simulation.cycle + 780 //13 seconds
|
||||
bullet[bullet.length - 1].endCycle = simulation.cycle + 900 //15 seconds
|
||||
this.leaveBody = false; // no body since it turned into the bot
|
||||
}
|
||||
if (tech.isAddRemoveMaxHealth) {
|
||||
if (this.isBoss && this.isDropPowerUp) {
|
||||
powerUps.spawn(this.position.x + 20, this.position.y, "tech", false)
|
||||
powerUps.spawn(this.position.x - 20, this.position.y, "ammo", false)
|
||||
powerUps.spawn(this.position.x - 20, this.position.y, "research", false)
|
||||
powerUps.spawn(this.position.x - 40, this.position.y, "research", false)
|
||||
powerUps.spawn(this.position.x + 40, this.position.y, "research", false)
|
||||
powerUps.spawn(this.position.x, this.position.y + 20, "research", false)
|
||||
powerUps.spawn(this.position.x, this.position.y - 20, "heal", false)
|
||||
powerUps.spawn(this.position.x - 40, this.position.y, "ammo", false)
|
||||
powerUps.spawn(this.position.x, this.position.y + 40, "research", false)
|
||||
powerUps.spawn(this.position.x, this.position.y + 40, "heal", false)
|
||||
powerUps.spawn(this.position.x, this.position.y - 40, "heal", false)
|
||||
} else {
|
||||
const amount = 0.005
|
||||
@@ -1292,7 +1373,7 @@ const mobs = {
|
||||
}
|
||||
}
|
||||
if (tech.cloakDuplication && !this.isBoss) {
|
||||
tech.cloakDuplication -= 0.02
|
||||
tech.cloakDuplication -= 0.01
|
||||
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
|
||||
}
|
||||
} else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) {
|
||||
|
||||
288
js/player.js
288
js/player.js
@@ -393,7 +393,7 @@ const m = {
|
||||
for (let i = 0, len = b.inventory.length; i < len; i++) {
|
||||
if (b.guns[b.inventory[i]].ammo !== Infinity) b.guns[b.inventory[i]].ammo = Math.max(0, Math.floor(ammoCount / b.inventory.length * b.guns[b.inventory[i]].ammoPack * (1.15 + 0.3 * (Math.random() - 0.5))))
|
||||
}
|
||||
console.log(b.activeGun)
|
||||
// console.log(b.activeGun)
|
||||
//randomize tech
|
||||
for (let i = 0; i < totalTech; i++) {
|
||||
//find what tech I could get
|
||||
@@ -568,7 +568,7 @@ const m = {
|
||||
if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
|
||||
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
|
||||
if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0193, 0.88) //capped at speed of 55
|
||||
if (tech.isHarmReduce && input.field) dmg *= 0.15
|
||||
if (tech.isHarmReduce && input.field) dmg *= 0.12
|
||||
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05
|
||||
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
|
||||
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
|
||||
@@ -935,83 +935,6 @@ const m = {
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
// resetSkin() {
|
||||
// simulation.isAutoZoom = true;
|
||||
// m.yOffWhen.jump = 70
|
||||
// m.yOffWhen.stand = 49
|
||||
// m.yOffWhen.crouch = 22
|
||||
// m.isAltSkin = false
|
||||
// m.color = {
|
||||
// hue: 0,
|
||||
// sat: 0,
|
||||
// light: 100,
|
||||
// }
|
||||
// m.setFillColors();
|
||||
// m.draw = function () {
|
||||
// ctx.fillStyle = m.fillColor;
|
||||
// m.walk_cycle += m.flipLegs * m.Vx;
|
||||
// ctx.save();
|
||||
// ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
|
||||
// ctx.translate(m.pos.x, m.pos.y);
|
||||
// m.calcLeg(Math.PI, -3);
|
||||
// m.drawLeg("#4a4a4a");
|
||||
// m.calcLeg(0, 0);
|
||||
// m.drawLeg("#333");
|
||||
// ctx.rotate(m.angle);
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(0, 0, 30, 0, 2 * Math.PI);
|
||||
// ctx.fillStyle = m.bodyGradient
|
||||
// ctx.fill();
|
||||
// ctx.arc(15, 0, 4, 0, 2 * Math.PI);
|
||||
// ctx.strokeStyle = "#333";
|
||||
// ctx.lineWidth = 2;
|
||||
// ctx.stroke();
|
||||
// ctx.restore();
|
||||
// m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
|
||||
// powerUps.boost.draw()
|
||||
// }
|
||||
// m.drawLeg = function (stroke) {
|
||||
// // if (simulation.mouseInGame.x > m.pos.x) {
|
||||
// if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
|
||||
// m.flipLegs = 1;
|
||||
// } else {
|
||||
// m.flipLegs = -1;
|
||||
// }
|
||||
// ctx.save();
|
||||
// ctx.scale(m.flipLegs, 1); //leg lines
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(m.hip.x, m.hip.y);
|
||||
// ctx.lineTo(m.knee.x, m.knee.y);
|
||||
// ctx.lineTo(m.foot.x, m.foot.y);
|
||||
// ctx.strokeStyle = stroke;
|
||||
// ctx.lineWidth = 7;
|
||||
// ctx.stroke();
|
||||
|
||||
// //toe lines
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(m.foot.x, m.foot.y);
|
||||
// ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
|
||||
// ctx.moveTo(m.foot.x, m.foot.y);
|
||||
// ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
|
||||
// ctx.lineWidth = 4;
|
||||
// ctx.stroke();
|
||||
|
||||
// //hip joint
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
|
||||
// //knee joint
|
||||
// ctx.moveTo(m.knee.x + 7, m.knee.y);
|
||||
// ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
|
||||
// //foot joint
|
||||
// ctx.moveTo(m.foot.x + 6, m.foot.y);
|
||||
// ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
|
||||
// ctx.fillStyle = m.fillColor;
|
||||
// ctx.fill();
|
||||
// ctx.lineWidth = 2;
|
||||
// ctx.stroke();
|
||||
// ctx.restore();
|
||||
// }
|
||||
// },
|
||||
skin: {
|
||||
none() {
|
||||
m.isAltSkin = true
|
||||
@@ -1146,6 +1069,96 @@ const m = {
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
strokeGap() {
|
||||
m.isAltSkin = true
|
||||
m.yOffWhen.stand = 52
|
||||
m.yOffWhen.jump = 72
|
||||
// m.yOffWhen.crouch = 22
|
||||
// m.color = {
|
||||
// hue: 184,
|
||||
// sat: 0,
|
||||
// light: 55,
|
||||
// }
|
||||
// m.setFillColors();
|
||||
m.draw = function () {
|
||||
m.walk_cycle += m.flipLegs * m.Vx;
|
||||
ctx.save();
|
||||
ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
|
||||
ctx.translate(m.pos.x, m.pos.y);
|
||||
m.calcLeg(Math.PI, -1.25);
|
||||
m.drawLeg("#606070");
|
||||
m.calcLeg(0, 0);
|
||||
m.drawLeg("#445");
|
||||
|
||||
|
||||
ctx.rotate(m.angle);
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
|
||||
// ctx.arc(0, 0, 30, m.angle + 1, m.angle - 1);
|
||||
ctx.fillStyle = "#fff"//m.bodyGradient
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
const arc = 0.7 + 0.17 * Math.sin(m.cycle * 0.012)
|
||||
ctx.arc(0, 0, 30, -arc, arc, true); //- Math.PI / 2
|
||||
ctx.strokeStyle = "#445";
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(13, 0)
|
||||
ctx.lineTo(20, 0)
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(15, 0, 4, 0, 2 * Math.PI);
|
||||
ctx.lineWidth = 5;
|
||||
ctx.strokeStyle = "#445";
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
|
||||
powerUps.boost.draw()
|
||||
}
|
||||
m.drawLeg = function (stroke) {
|
||||
// if (simulation.mouseInGame.x > m.pos.x) {
|
||||
if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
|
||||
m.flipLegs = 1;
|
||||
} else {
|
||||
m.flipLegs = -1;
|
||||
}
|
||||
ctx.save();
|
||||
ctx.scale(m.flipLegs, 1); //leg lines
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(m.hip.x, m.hip.y);
|
||||
ctx.lineTo(m.knee.x, m.knee.y);
|
||||
ctx.lineTo(m.foot.x, m.foot.y);
|
||||
ctx.strokeStyle = stroke;
|
||||
ctx.lineWidth = 5;
|
||||
ctx.stroke();
|
||||
|
||||
//toe lines
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(m.foot.x, m.foot.y);
|
||||
ctx.lineTo(m.foot.x - 14, m.foot.y + 5);
|
||||
ctx.moveTo(m.foot.x, m.foot.y);
|
||||
ctx.lineTo(m.foot.x + 14, m.foot.y + 5);
|
||||
ctx.lineWidth = 4;
|
||||
ctx.stroke();
|
||||
|
||||
//hip joint
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.hip.x, m.hip.y, 8, 0, 2 * Math.PI);
|
||||
//knee joint
|
||||
ctx.moveTo(m.knee.x + 4, m.knee.y);
|
||||
ctx.arc(m.knee.x, m.knee.y, 4, 0, 2 * Math.PI);
|
||||
//foot joint
|
||||
ctx.moveTo(m.foot.x + 4, m.foot.y + 1);
|
||||
ctx.arc(m.foot.x, m.foot.y + 1, 4, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = m.fillColor;
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
energy() {
|
||||
m.isAltSkin = true
|
||||
m.color = {
|
||||
@@ -1333,17 +1346,9 @@ const m = {
|
||||
sat: 14,
|
||||
light: 65,
|
||||
}
|
||||
// m.setFillColors();
|
||||
m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
|
||||
m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 50}%)`
|
||||
// let grd = ctx.createLinearGradient(-30, 0, 30, 0);
|
||||
const grd = ctx.createRadialGradient(16, 0, 0, 0, 0, 40);
|
||||
|
||||
// grd.addColorStop(0, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
|
||||
// grd.addColorStop(0.25, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 20}%)`);
|
||||
// grd.addColorStop(0.5, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
|
||||
// grd.addColorStop(1, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 10}%)`);
|
||||
|
||||
grd.addColorStop(0, `#c78034`);
|
||||
grd.addColorStop(0.04, `#bd5235`);
|
||||
grd.addColorStop(0.08, `#ab554d`);
|
||||
@@ -1369,10 +1374,8 @@ const m = {
|
||||
grd.addColorStop(0.92, `#00e19b`);
|
||||
grd.addColorStop(0.96, `#19f5aa`);
|
||||
grd.addColorStop(1, `#aaf5af`);
|
||||
|
||||
m.bodyGradient = grd
|
||||
|
||||
|
||||
m.draw = function () {
|
||||
ctx.fillStyle = m.fillColor;
|
||||
m.walk_cycle += m.flipLegs * m.Vx;
|
||||
@@ -1410,7 +1413,7 @@ const m = {
|
||||
ctx.lineTo(m.knee.x, m.knee.y);
|
||||
ctx.lineTo(m.foot.x, m.foot.y);
|
||||
ctx.strokeStyle = stroke;
|
||||
ctx.lineWidth = 7;
|
||||
ctx.lineWidth = 5;
|
||||
ctx.stroke();
|
||||
|
||||
//toe lines
|
||||
@@ -1424,21 +1427,22 @@ const m = {
|
||||
|
||||
//hip joint
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = "#1b85cf";
|
||||
ctx.arc(m.hip.x, m.hip.y, 9, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = "#222";
|
||||
// ctx.fillStyle = "#1b85cf";
|
||||
ctx.fill();
|
||||
//knee joint
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = "#ffa050";
|
||||
ctx.arc(m.knee.x, m.knee.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.fillStyle = "#ffa050";
|
||||
ctx.fill();
|
||||
//foot joint
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = "#878cf0";
|
||||
ctx.arc(m.foot.x, m.foot.y, 4, 0, 2 * Math.PI);
|
||||
// ctx.fillStyle = "#878cf0";
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
// ctx.lineWidth = 3;
|
||||
// ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
@@ -2636,7 +2640,7 @@ const m = {
|
||||
},
|
||||
fieldUpgrades: [{
|
||||
name: "field emitter",
|
||||
imageNumber: Math.floor(Math.random() * 23),
|
||||
imageNumber: Math.floor(Math.random() * 26), //pick one of the 25 field emitter image files at random
|
||||
description: `<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>
|
||||
effect: () => {
|
||||
@@ -2934,7 +2938,6 @@ const m = {
|
||||
// if (m.energy < m.fieldRegen) m.fieldCDcycle = m.cycle + 90;
|
||||
// }
|
||||
|
||||
|
||||
if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
|
||||
m.grabPowerUp();
|
||||
m.lookForPickUp();
|
||||
@@ -3998,7 +4001,7 @@ const m = {
|
||||
},
|
||||
{
|
||||
name: "metamaterial cloaking",
|
||||
description: "<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: () => {
|
||||
m.fieldFire = true;
|
||||
m.fieldMeterColor = "#333";
|
||||
@@ -4013,29 +4016,6 @@ const m = {
|
||||
m.walk_cycle -= m.flipLegs * m.Vx;
|
||||
m.pos.x += 4
|
||||
m.draw();
|
||||
|
||||
// let history = m.history[(m.cycle - 1) % 600]
|
||||
// m.pos.x = history.position.x
|
||||
// m.pos.y = history.position.y + m.yPosDifference - history.yOff
|
||||
|
||||
// m.pos.x += 4
|
||||
// ctx.fillStyle = m.fillColor;
|
||||
// ctx.save();
|
||||
// ctx.translate(m.pos.x, m.pos.y);
|
||||
// m.calcLeg(Math.PI, -3);
|
||||
// m.drawLeg("#ccc");
|
||||
// m.calcLeg(0, 0);
|
||||
// m.drawLeg("#ccc");
|
||||
// ctx.rotate(m.angle);
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(0, 0, 30, 0, 2 * Math.PI);
|
||||
// ctx.fillStyle = "#fff"
|
||||
// ctx.fill();
|
||||
// ctx.arc(15, 0, 4, 0, 2 * Math.PI);
|
||||
// ctx.strokeStyle = "#333";
|
||||
// ctx.lineWidth = 2;
|
||||
// ctx.stroke();
|
||||
// ctx.restore()
|
||||
}
|
||||
m.drawCloak = function () {
|
||||
m.fieldPhase += 0.007
|
||||
@@ -4067,27 +4047,27 @@ const m = {
|
||||
}
|
||||
//not shooting (or using field) enable cloak
|
||||
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
|
||||
if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing
|
||||
if (m.fireCDcycle + 10 < m.cycle && !input.fire) { //automatically cloak if not firing
|
||||
const drain = 0.02
|
||||
if (!m.isCloak && m.energy > drain + 0.03) {
|
||||
m.energy -= drain
|
||||
m.isCloak = true //enter cloak
|
||||
m.fieldHarmReduction = 0.5;
|
||||
m.fieldHarmReduction = 0.33; //66% reduction
|
||||
m.enterCloakCycle = m.cycle
|
||||
if (tech.isCloakHealLastHit && m.lastHit > 0) {
|
||||
const heal = Math.min(0.75 * m.lastHit, m.energy)
|
||||
if (m.energy > heal) {
|
||||
m.energy -= heal
|
||||
m.addHealth(heal); //heal from last hit
|
||||
m.lastHit = 0
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: m.pos.x,
|
||||
y: m.pos.y,
|
||||
radius: Math.sqrt(heal) * 200,
|
||||
color: "rgba(0,255,200,0.6)",
|
||||
time: 16
|
||||
});
|
||||
}
|
||||
// if (m.energy > heal) {
|
||||
// m.energy -= heal * 0.8
|
||||
m.addHealth(heal); //heal from last hit
|
||||
m.lastHit = 0
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: m.pos.x,
|
||||
y: m.pos.y,
|
||||
radius: Math.sqrt(heal) * 200,
|
||||
color: "rgba(0,255,200,0.6)",
|
||||
time: 16
|
||||
});
|
||||
// }
|
||||
}
|
||||
if (tech.isIntangible) {
|
||||
for (let i = 0; i < bullet.length; i++) {
|
||||
@@ -4133,9 +4113,16 @@ const m = {
|
||||
m.fieldRange = m.fieldRange * 0.85 + 130
|
||||
m.fieldDrawRadius = m.fieldRange * 1.1 //* 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
|
||||
m.drawCloak()
|
||||
ctx.globalCompositeOperation = "lighter";
|
||||
m.drawCloakedM()
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
// ctx.globalCompositeOperation = "lighter";
|
||||
// m.drawCloakedM()
|
||||
// ctx.globalCompositeOperation = "source-over";
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.pos.x, m.pos.y, 35, 0, 2 * Math.PI);
|
||||
ctx.strokeStyle = "rgba(255,255,255,0.25)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
|
||||
ctx.lineWidth = 10
|
||||
ctx.stroke();
|
||||
|
||||
} else if (m.fieldRange < 4000) {
|
||||
m.fieldRange += 90
|
||||
m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
|
||||
@@ -4148,8 +4135,8 @@ const m = {
|
||||
if (inPlayer.length > 0) {
|
||||
for (let i = 0; i < inPlayer.length; i++) {
|
||||
if (m.energy > 0) {
|
||||
if (!inPlayer[i].isUnblockable) m.energy -= 0.007;
|
||||
if (inPlayer[i].shield) m.energy -= 0.025;
|
||||
if (!inPlayer[i].isUnblockable) m.energy -= 0.003;
|
||||
if (inPlayer[i].shield) m.energy -= 0.011;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4158,10 +4145,17 @@ const m = {
|
||||
}
|
||||
}
|
||||
this.drawRegenEnergyCloaking()
|
||||
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
|
||||
ctx.globalCompositeOperation = "multiply";
|
||||
m.drawCloakedM()
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
|
||||
const timeLeft = (m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) - m.cycle) * 0.5
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.pos.x, m.pos.y, 32, 0, 2 * Math.PI);
|
||||
ctx.strokeStyle = "rgba(180,30,70,0.5)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
|
||||
ctx.lineWidth = Math.max(Math.min(10, timeLeft), 3);
|
||||
ctx.stroke();
|
||||
|
||||
// ctx.globalCompositeOperation = "multiply";
|
||||
// m.drawCloakedM()
|
||||
// ctx.globalCompositeOperation = "source-over";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,26 +534,24 @@ const powerUps = {
|
||||
if (!tech.isEnergyHealth && m.alive) {
|
||||
powerUps.animatePowerUpGrab('rgba(0, 238, 187,0.25)')
|
||||
let heal = (this.size / 40 / (simulation.healScale ** 0.25)) ** 2 //simulation.healScale is undone here because heal scale is already properly affected on m.addHealth()
|
||||
// console.log("size = " + this.size, "heal = " + heal)
|
||||
if (heal > 0) {
|
||||
const overHeal = m.health + heal * simulation.healScale - m.maxHealth //used with tech.isOverHeal
|
||||
const healOutput = Math.min(m.maxHealth - m.health, heal) * simulation.healScale
|
||||
m.addHealth(heal);
|
||||
if (healOutput > 0) simulation.makeTextLog(`<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
|
||||
const scaledOverHeal = overHeal // * 0.9
|
||||
m.damage(scaledOverHeal);
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>-=</span> ${(scaledOverHeal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
|
||||
m.damage(overHeal);
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>-=</span> ${(overHeal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: m.pos.x,
|
||||
y: m.pos.y,
|
||||
radius: scaledOverHeal * 500 * simulation.healScale,
|
||||
radius: overHeal * 500 * simulation.healScale,
|
||||
color: simulation.mobDmgColor,
|
||||
time: simulation.drawTime
|
||||
});
|
||||
tech.extraMaxHealth += scaledOverHeal * simulation.healScale //increase max health
|
||||
tech.extraMaxHealth += overHeal * Math.sqrt(simulation.healScale) //increase max health
|
||||
m.setMaxHealth();
|
||||
} else if (overHeal > 0.1) {
|
||||
} else if (overHeal > 0.13) { //if leftover heals spawn a new spammer heal power up
|
||||
requestAnimationFrame(() => {
|
||||
powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
|
||||
});
|
||||
|
||||
@@ -1272,7 +1272,7 @@ const simulation = {
|
||||
for (let i = 0, len = mob.length; i < len; i++) {
|
||||
if (mob[i].isDropPowerUp && mob[i].alive) count++
|
||||
}
|
||||
count *= 0.17 //to fake the chance, this makes it not random, and maybe less confusing
|
||||
count *= 0.22 //to fake the 20% chance, this makes it not random, and more predictable
|
||||
let cycle = () => { //run after waiting a cycle for the map to be cleared
|
||||
const types = ["heal", "ammo", "heal", "ammo", "research", "coupling", "boost", "tech", "gun", "field"]
|
||||
for (let i = 0; i < count; i++) powerUps.spawnDelay(types[Math.floor(Math.random() * types.length)], 1)
|
||||
|
||||
200
js/spawn.js
200
js/spawn.js
@@ -200,7 +200,7 @@ const spawn = {
|
||||
for (let i = 0, len = mob.length; i < len; ++i) {
|
||||
if (mob[i].alive && !mob[i].isShielded) {
|
||||
if (Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius < this.radius) {
|
||||
mob[i].damage(0.02 * m.dmgScale);
|
||||
mob[i].damage(0.025 * m.dmgScale);
|
||||
// mob[i].locatePlayer();//
|
||||
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
@@ -366,7 +366,7 @@ const spawn = {
|
||||
me.maxMobs = 400
|
||||
me.mode = [{
|
||||
name: "boulders",
|
||||
spawnRate: 170 - 6 * simulation.difficultyMode,
|
||||
spawnRate: Math.max(30, 170 - 5 * simulation.difficultyMode),
|
||||
do() {
|
||||
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
|
||||
me.boulder(me.position.x, me.position.y + 250)
|
||||
@@ -374,10 +374,11 @@ const spawn = {
|
||||
},
|
||||
enter() { },
|
||||
exit() { },
|
||||
}, {
|
||||
},
|
||||
{
|
||||
name: "mobs",
|
||||
// whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
|
||||
spawnRate: 280 - 20 * simulation.difficultyMode,
|
||||
spawnRate: Math.max(60, 240 - 20 * simulation.difficultyMode),
|
||||
do() {
|
||||
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
|
||||
me.torque += 0.000015 * me.inertia; //spin
|
||||
@@ -397,7 +398,7 @@ const spawn = {
|
||||
},
|
||||
{
|
||||
name: "hoppers",
|
||||
spawnRate: 480 - 16 * simulation.difficultyMode,
|
||||
spawnRate: Math.max(90, 480 - 16 * simulation.difficultyMode),
|
||||
do() {
|
||||
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
|
||||
me.torque += 0.00002 * me.inertia; //spin
|
||||
@@ -422,7 +423,7 @@ const spawn = {
|
||||
},
|
||||
{
|
||||
name: "seekers",
|
||||
spawnRate: 100 - 3 * simulation.difficultyMode,
|
||||
spawnRate: Math.max(15, 100 - 3 * simulation.difficultyMode),
|
||||
do() {
|
||||
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
|
||||
const index = Math.floor((me.cycle % 360) / 60)
|
||||
@@ -440,7 +441,7 @@ const spawn = {
|
||||
{
|
||||
name: "mines",
|
||||
bombCycle: 0,
|
||||
bombInterval: 10 - simulation.difficultyMode,
|
||||
bombInterval: Math.max(2, 10 - simulation.difficultyMode),
|
||||
do() {
|
||||
const yOff = 120
|
||||
this.bombCycle++
|
||||
@@ -498,7 +499,7 @@ const spawn = {
|
||||
},
|
||||
{
|
||||
name: "orbiters",
|
||||
spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode),
|
||||
spawnRate: Math.ceil(Math.max(2, 5 - 0.2 * simulation.difficultyMode)),
|
||||
orbitersCycle: 0,
|
||||
do() {
|
||||
this.orbitersCycle++
|
||||
@@ -522,7 +523,7 @@ const spawn = {
|
||||
this.fadeCycle++
|
||||
if (this.fadeCycle > 0) {
|
||||
me.torque += this.spinForce * me.inertia; //spin //0.00000015
|
||||
if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
|
||||
if (this.fadeCycle > 360) this.fadeCycle = -200 + simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
|
||||
ctx.strokeStyle = "#50f";
|
||||
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
|
||||
ctx.lineWidth = 1.5;
|
||||
@@ -561,7 +562,7 @@ const spawn = {
|
||||
{
|
||||
name: "black hole",
|
||||
eventHorizon: 0,
|
||||
eventHorizonRadius: 1900,
|
||||
eventHorizonRadius: 1700,
|
||||
eventHorizonCycle: 0,
|
||||
do() {
|
||||
this.eventHorizonCycle++
|
||||
@@ -629,15 +630,121 @@ const spawn = {
|
||||
spawn.shield(me, me.position.x, me.position.y, 1);
|
||||
},
|
||||
exit() { this.waveCycle = 0 },
|
||||
},
|
||||
{
|
||||
name: "slow zone",
|
||||
waveCycle: 0,
|
||||
whereX: simulation.isHorizontalFlipped ? -3000 : 3000,
|
||||
width: 1200,
|
||||
// isActive: false,
|
||||
cycle: 0,
|
||||
cycleDuration: 150,
|
||||
zone: 0,
|
||||
isMovingRight: true,
|
||||
playerSlowTime: 0,
|
||||
do() {
|
||||
// console.log(zone)
|
||||
this.cycle++
|
||||
if (this.cycle % this.cycleDuration === 0) { //next zone
|
||||
this.zone += this.isMovingRight ? 1 : -1
|
||||
if (this.zone > 0) this.isMovingRight = false
|
||||
if (this.zone < -1) this.isMovingRight = true
|
||||
this.whereX = (simulation.isHorizontalFlipped ? -3000 : 3000) + this.width * this.zone
|
||||
}
|
||||
//draw slow zone
|
||||
if (this.cycle % this.cycleDuration > 0.45 * this.cycleDuration) {
|
||||
ctx.fillStyle = `rgba(0, 100, 255, ${0.19 + 0.015 * Math.sin(simulation.cycle * 0.36)})`;
|
||||
ctx.fillRect(this.whereX, -1500, this.width, 1500);
|
||||
//check for player in range and apply slow debuff
|
||||
if (player.position.x > this.whereX && player.position.x < this.whereX + this.width) {
|
||||
this.playerSlowTime = 180
|
||||
//damage player
|
||||
const dmg = 0.0001 * simulation.dmgScale
|
||||
m.damage(dmg);
|
||||
}
|
||||
} else { //show where slow zone is about to show up
|
||||
ctx.fillStyle = `rgba(0, 100, 255, ${0.2 + 0.25 * Math.random()})`;
|
||||
ctx.fillRect(this.whereX, -1500, this.width, 12);
|
||||
ctx.fillRect(this.whereX, -12, this.width, 12);
|
||||
}
|
||||
if (this.playerSlowTime > 0) {
|
||||
this.playerSlowTime-- //warm up player when outside of slow zone
|
||||
//slow player
|
||||
// Matter.Body.setVelocity(player, Vector.mult(player.velocity, (1 - 0.01 * this.playerSlowTime)));
|
||||
// Matter.Body.setVelocity(player, { x: (1 - 0.01 * this.playerSlowTime) * player.velocity.x, y: (1 - 0.0025 * this.playerSlowTime) * player.velocity.y }); //makes the player get stuck slow when walking horizontally
|
||||
Matter.Body.setVelocity(player, { x: Math.max(0.05, 1 - 0.01 * Math.max(10, this.playerSlowTime)) * player.velocity.x, y: Math.max(0.2, 1 - 0.0025 * this.playerSlowTime) * player.velocity.y });
|
||||
//draw effect on player
|
||||
ctx.beginPath();
|
||||
ctx.arc(m.pos.x, m.pos.y, 45, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = `rgba(0,100,255,${(0.003 * Math.max(10, this.playerSlowTime))})`;
|
||||
ctx.fill();
|
||||
}
|
||||
},
|
||||
enter() {
|
||||
},
|
||||
exit() { },
|
||||
},
|
||||
{
|
||||
name: "antigravity",
|
||||
cycle: 0,
|
||||
startCycle: 420,
|
||||
totalCycles: 600,
|
||||
rectX: simulation.isHorizontalFlipped ? -5400 : -150, //for positioning graphics
|
||||
do() {
|
||||
this.cycle++
|
||||
if (this.cycle > this.totalCycles) this.cycle = 0
|
||||
if (this.cycle === this.startCycle) {
|
||||
//initial push up
|
||||
for (let i = 0, len = body.length; i < len; ++i) {
|
||||
body[i].force.y -= 0.05 * body[i].mass
|
||||
}
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
powerUp[i].force.y -= 0.07 * powerUp[i].mass
|
||||
}
|
||||
for (let i = 0, len = bullet.length; i < len; ++i) {
|
||||
bullet[i].force.y -= 0.05 * bullet[i].mass
|
||||
}
|
||||
for (let i = 0, len = mob.length; i < len; ++i) {
|
||||
mob[i].force.y -= 0.15 * mob[i].mass
|
||||
}
|
||||
player.force.y -= 0.04 * player.mass
|
||||
} else if (this.cycle > this.startCycle) { //antigravity
|
||||
for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
|
||||
body[i].force.y -= simulation.g * body[i].mass
|
||||
Matter.Body.setVelocity(body[i], Vector.mult(body[i].velocity, 0.98)); //friction
|
||||
}
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
powerUp[i].force.y -= simulation.g * powerUp[i].mass
|
||||
}
|
||||
// for (let i = 0, len = bullet.length; i < len; ++i) {
|
||||
// bullet[i].force.y -= simulation.g * bullet[i].mass
|
||||
// Matter.Body.setVelocity(bullet[i], Vector.mult(bullet[i].velocity, 0.98)); //friction
|
||||
// }
|
||||
// for (let i = 0, len = mob.length; i < len; ++i) {
|
||||
// mob[i].force.y -= 0.7 * simulation.g * mob[i].mass
|
||||
// }
|
||||
player.force.y -= simulation.g * player.mass //g = 0.0024
|
||||
Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.985)); //friction
|
||||
//graphics
|
||||
ctx.fillStyle = `rgba(0, 0, 0, ${0.03 + 0.03 * Math.random()})`;
|
||||
ctx.fillRect(this.rectX, -1500, 5650, 1500); //cover everything
|
||||
} else if (this.cycle > this.startCycle - 60) {
|
||||
//graphical warning of antigravity
|
||||
ctx.fillStyle = `rgba(0, 0, 0, ${0.2 + 0.25 * Math.random()})`;
|
||||
ctx.fillRect(this.rectX, -25, 5650, 25); //cover floor
|
||||
}
|
||||
},
|
||||
enter() { spawn.shield(me, me.position.x, me.position.y, 1); },
|
||||
exit() { this.cycle = 0 },
|
||||
},
|
||||
// {
|
||||
// name: "__",
|
||||
// do() {},
|
||||
// enter() {},
|
||||
// exit() {},
|
||||
// do() { },
|
||||
// enter() { },
|
||||
// exit() { },
|
||||
// },
|
||||
]
|
||||
shuffle(me.mode); //THIS SHOULDN'T BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
shuffle(me.mode); //THIS SHOULD NOT BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
me.do = function () {
|
||||
this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
|
||||
if (this.health < 1) {
|
||||
@@ -648,7 +755,8 @@ const spawn = {
|
||||
this.damageReductionDecay();
|
||||
for (let i = 0; i < this.totalModes; i++) this.mode[i].do()
|
||||
}
|
||||
// this.mode[5].do() //deelete this
|
||||
// this.mode[10].do() //comment out this
|
||||
// console.log(this.mode[9].name)
|
||||
// this.cycle++;
|
||||
// this.mode[4].do()
|
||||
// this.mode[7].do()
|
||||
@@ -719,7 +827,7 @@ const spawn = {
|
||||
}
|
||||
}
|
||||
Matter.Body.setDensity(me, 0.003); //normal is 0.001
|
||||
me.timeLeft = 360;
|
||||
me.timeLeft = 300;
|
||||
me.g = 0.0005; //required if using this.gravity
|
||||
me.frictionAir = 0.005;
|
||||
me.friction = 1;
|
||||
@@ -740,6 +848,12 @@ const spawn = {
|
||||
this.torque += this.spin;
|
||||
this.gravity();
|
||||
this.timeLimit();
|
||||
if (this.timeLeft < 60) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.position.x, this.position.y, this.explodeRange, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = `rgba(255,255,255,0.15)`;
|
||||
ctx.fill();
|
||||
}
|
||||
};
|
||||
}
|
||||
me.orbitalNoVelocity = function (who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
|
||||
@@ -2502,7 +2616,7 @@ const spawn = {
|
||||
spawn.hopBullet(this.position.x, this.position.y)
|
||||
this.death();
|
||||
}
|
||||
if (Matter.Query.collides(this, [player]).length > 0) this.isExploding = true
|
||||
if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) this.isExploding = true
|
||||
if (this.isExploding) {
|
||||
if (this.countDown-- < 0) { //explode
|
||||
this.death();
|
||||
@@ -2538,7 +2652,7 @@ const spawn = {
|
||||
// me.isBadTarget = true;
|
||||
me.isMobBullet = true;
|
||||
me.showHealthBar = false;
|
||||
me.timeLeft = 1140 + Math.floor(480 * Math.random());
|
||||
me.timeLeft = 1020 + Math.floor(480 * Math.random());
|
||||
|
||||
me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
|
||||
me.accelMag = 0.01; //jump height
|
||||
@@ -2547,7 +2661,7 @@ const spawn = {
|
||||
me.friction = 1
|
||||
me.frictionStatic = 1
|
||||
me.restitution = 0;
|
||||
me.delay = 130 + 60 * simulation.CDScale;
|
||||
me.delay = 120 + 60 * simulation.CDScale;
|
||||
// Matter.Body.rotate(me, Math.random() * Math.PI);
|
||||
me.collisionFilter.category = cat.mobBullet;
|
||||
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
|
||||
@@ -3673,12 +3787,54 @@ const spawn = {
|
||||
} else if (c < -threshold) {
|
||||
this.torque -= turn;
|
||||
}
|
||||
const flapArc = 0.7 //don't go past 1.57 for normal flaps
|
||||
|
||||
const flapArc = 0.7 //don't go past 1.57 for normal flaps
|
||||
ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
|
||||
this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
}
|
||||
// else { //flocking behavior (not working yet)
|
||||
// this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
|
||||
// this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
|
||||
// //set direction to turn to fire
|
||||
// if (!(simulation.cycle % this.seePlayerFreq)) {
|
||||
// //find nearest mob and maintain a distance
|
||||
// let nearestMob = null
|
||||
// let nearestMobDistance = Infinity
|
||||
// for (let i = 0; i < mob.length; i++) {
|
||||
// const newMobDistance = Vector.magnitude(Vector.sub(this.position, mob[i].position))
|
||||
// if (mob[i].isDropPowerUp && mob[i].alive && newMobDistance < nearestMobDistance) { //&& !mob[i].isBoss
|
||||
// nearestMobDistance = newMobDistance
|
||||
// nearestMob = mob[i]
|
||||
// }
|
||||
// }
|
||||
// if (nearestMob) {
|
||||
// // console.log(nearestMob)
|
||||
// this.fireDir = Vector.normalise(Vector.sub(nearestMob.position, this.position));
|
||||
// //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
|
||||
// const mod = (a, n) => {
|
||||
// return a - Math.floor(a / n) * n
|
||||
// }
|
||||
// const sub = Vector.sub(nearestMob.position, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
|
||||
// const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
|
||||
// if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
|
||||
// }
|
||||
// }
|
||||
// //rotate towards fireDir
|
||||
// const angle = this.angle + Math.PI / 2;
|
||||
// c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
|
||||
// const threshold = 0.4;
|
||||
// const turn = 0.000025 * this.inertia
|
||||
// if (c > threshold) {
|
||||
// this.torque += turn;
|
||||
// } else if (c < -threshold) {
|
||||
// this.torque -= turn;
|
||||
// }
|
||||
// const flapArc = 0.7 //don't go past 1.57 for normal flaps
|
||||
// ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
|
||||
// this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
// this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
// }
|
||||
};
|
||||
},
|
||||
beetleBoss(x, y, radius = 50) {
|
||||
@@ -5237,9 +5393,7 @@ const spawn = {
|
||||
me.do = function () {
|
||||
this.checkStatus();
|
||||
|
||||
if (Matter.Query.collides(this, [player]).length > 0) {
|
||||
this.isExploding = true
|
||||
}
|
||||
if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) this.isExploding = true
|
||||
|
||||
if (this.isExploding) {
|
||||
if (this.countDown-- < 0) { //explode
|
||||
|
||||
273
js/tech.js
273
js/tech.js
@@ -237,7 +237,7 @@ const tech = {
|
||||
if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
|
||||
if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage
|
||||
if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.015 * m.coupling
|
||||
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling)
|
||||
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling)
|
||||
if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime
|
||||
if (tech.isTechDebt) dmg *= tech.totalCount > 20 ? Math.pow(0.85, tech.totalCount - 20) : 4 - 0.15 * tech.totalCount // if (tech.isTechDebt) dmg *= Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount)
|
||||
if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555
|
||||
@@ -365,6 +365,57 @@ const tech = {
|
||||
if (this.count) m.resetSkin();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Higgs mechanism",
|
||||
description: "<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",
|
||||
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,
|
||||
frequencyDefault: 4,
|
||||
allowed() {
|
||||
return tech.isEnergyHealth
|
||||
return tech.isEnergyHealth && !tech.isOverHeal
|
||||
},
|
||||
requires: "mass-energy equivalence",
|
||||
requires: "mass-energy equivalence, not quenching",
|
||||
effect() {
|
||||
powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
|
||||
powerUps.heal.color = "#ff0" //"#0ae"
|
||||
@@ -947,30 +998,6 @@ const tech = {
|
||||
tech.isFarAwayDmg = false;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Higgs mechanism",
|
||||
description: "<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",
|
||||
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Weapon' class="link">integrated armament</a>`,
|
||||
@@ -1278,21 +1305,21 @@ const tech = {
|
||||
{
|
||||
name: "collider",
|
||||
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`
|
||||
},
|
||||
|
||||
maxCount: 2,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
frequencyDefault: 1,
|
||||
allowed: () => true,
|
||||
requires: "",
|
||||
effect() {
|
||||
tech.collidePowerUps += 0.5
|
||||
tech.collidePowerUps = true
|
||||
},
|
||||
remove() {
|
||||
tech.collidePowerUps = 0
|
||||
tech.collidePowerUps = false
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1316,17 +1343,53 @@ const tech = {
|
||||
tech.isShieldAmmo = false;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "yield stress",
|
||||
description: "<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",
|
||||
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,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
frequencyDefault: 1,
|
||||
allowed() {
|
||||
return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath
|
||||
return !tech.isMobFullHealth
|
||||
},
|
||||
requires: "", //"any mob death tech",
|
||||
requires: "not topological defect",
|
||||
effect() {
|
||||
tech.mobSpawnWithHealth++
|
||||
mobs.setMobSpawnHealth()
|
||||
@@ -1343,7 +1406,7 @@ const tech = {
|
||||
{
|
||||
name: "scrap bots",
|
||||
link: `<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,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -1363,7 +1426,7 @@ const tech = {
|
||||
{
|
||||
name: "scrap refit",
|
||||
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,
|
||||
count: 0,
|
||||
frequency: 3,
|
||||
@@ -3108,9 +3171,9 @@ const tech = {
|
||||
frequencyDefault: 1,
|
||||
isHealTech: true,
|
||||
allowed() {
|
||||
return true
|
||||
return !tech.isEnergyHealth
|
||||
},
|
||||
requires: "",
|
||||
requires: "not mass-energy",
|
||||
effect() {
|
||||
tech.isOverHeal = true;
|
||||
},
|
||||
@@ -3121,7 +3184,7 @@ const tech = {
|
||||
{
|
||||
name: "accretion",
|
||||
descriptionFunction() {
|
||||
return `${powerUps.orb.heal(1)} follow you, even between levels<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)}`,
|
||||
maxCount: 1,
|
||||
@@ -3136,7 +3199,7 @@ const tech = {
|
||||
effect() {
|
||||
tech.isHealAttract = true
|
||||
powerUps.setPowerUpMode();
|
||||
for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal");
|
||||
for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal");
|
||||
},
|
||||
remove() {
|
||||
tech.isHealAttract = false
|
||||
@@ -3295,28 +3358,6 @@ const tech = {
|
||||
tech.isImmortal = false;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Hilbert space",
|
||||
description: "<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",
|
||||
// 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",
|
||||
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,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -3426,7 +3470,7 @@ const tech = {
|
||||
requires: "no research",
|
||||
effect() {
|
||||
tech.isRerollHaste = true;
|
||||
tech.researchHaste = 0.3;
|
||||
tech.researchHaste = 0.4; //+60% fire rate
|
||||
b.setFireCD();
|
||||
},
|
||||
remove() {
|
||||
@@ -3482,7 +3526,7 @@ const tech = {
|
||||
{
|
||||
name: "mass production",
|
||||
descriptionFunction() {
|
||||
return `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} 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)} 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)} or ${powerUps.orb.research(5)}`,
|
||||
maxCount: 1,
|
||||
@@ -3500,7 +3544,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "research",
|
||||
description: `spawn ${powerUps.orb.research(5)}`,
|
||||
description: `spawn ${powerUps.orb.research(7)}`,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
@@ -3510,13 +3554,13 @@ const tech = {
|
||||
allowed() { return true },
|
||||
requires: "",
|
||||
effect() {
|
||||
powerUps.spawnDelay("research", 5);
|
||||
powerUps.spawnDelay("research", 7);
|
||||
},
|
||||
remove() { }
|
||||
},
|
||||
{
|
||||
name: "ammo",
|
||||
description: `spawn ${powerUps.orb.ammo(8)}`,
|
||||
description: `spawn ${powerUps.orb.ammo(10)}`,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
@@ -3526,14 +3570,14 @@ const tech = {
|
||||
allowed() { return true },
|
||||
requires: "",
|
||||
effect() {
|
||||
powerUps.spawnDelay("ammo", 8);
|
||||
powerUps.spawnDelay("ammo", 10);
|
||||
},
|
||||
remove() { }
|
||||
},
|
||||
{
|
||||
name: "heals",
|
||||
descriptionFunction() {
|
||||
return `spawn ${powerUps.orb.heal(8)}`
|
||||
return `spawn ${powerUps.orb.heal(10)}`
|
||||
},
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -3544,7 +3588,7 @@ const tech = {
|
||||
allowed() { return true },
|
||||
requires: "mass production",
|
||||
effect() {
|
||||
powerUps.spawnDelay("heal", 8);
|
||||
powerUps.spawnDelay("heal", 10);
|
||||
},
|
||||
remove() { }
|
||||
},
|
||||
@@ -5339,7 +5383,7 @@ const tech = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "phonon", //longitudinal //gravitational wave?
|
||||
name: "phonon",
|
||||
description: "waves are low <strong>frequency</strong>, high <strong class='color-d'>damage</strong><br><strong>expanding arcs</strong> that propagate through <strong>solids</strong>",
|
||||
isGunTech: true,
|
||||
maxCount: 1,
|
||||
@@ -6818,7 +6862,7 @@ const tech = {
|
||||
},
|
||||
remove() {
|
||||
tech.railChargeRate = 0.97;
|
||||
tech.harpoonDensity = 0.007
|
||||
tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -6837,6 +6881,7 @@ const tech = {
|
||||
ammoBonus: 9,
|
||||
effect() {
|
||||
tech.isRailGun = true;
|
||||
tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
|
||||
b.guns[9].chooseFireMethod()
|
||||
b.guns[9].ammoPack = 5;
|
||||
b.guns[9].ammo = b.guns[9].ammo * 6;
|
||||
@@ -6845,6 +6890,7 @@ const tech = {
|
||||
remove() {
|
||||
if (tech.isRailGun) {
|
||||
tech.isRailGun = false;
|
||||
tech.harpoonDensity = tech.isRailGun ? 0.007 : 0.004
|
||||
b.guns[9].chooseFireMethod()
|
||||
b.guns[9].ammoPack = 1.7;
|
||||
b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6);
|
||||
@@ -7025,21 +7071,41 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "induction furnace",
|
||||
description: "after using <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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun
|
||||
return ((tech.haveGunCheck("harpoon") && !tech.isRailGun) || m.fieldMode === 10) && !tech.isHarpoonFullHealth
|
||||
},
|
||||
requires: "harpoon, not railgun",
|
||||
requires: "harpoon, grappling hook, not railgun, brittle",
|
||||
effect() {
|
||||
tech.isHarpoonPowerUp = true
|
||||
},
|
||||
remove() {
|
||||
tech.isHarpoonPowerUp = false
|
||||
tech.harpoonPowerUpCycle = 0
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "brittle",
|
||||
description: "<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",
|
||||
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,
|
||||
maxCount: 9,
|
||||
count: 0,
|
||||
@@ -8133,7 +8199,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -8400,7 +8466,7 @@ const tech = {
|
||||
{
|
||||
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>` },
|
||||
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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -8411,7 +8477,7 @@ const tech = {
|
||||
},
|
||||
requires: "cloaking, time dilation",
|
||||
effect() {
|
||||
tech.cloakDuplication = 0.45
|
||||
tech.cloakDuplication = 0.4
|
||||
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
|
||||
if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
|
||||
},
|
||||
@@ -8423,7 +8489,7 @@ const tech = {
|
||||
{
|
||||
name: "metamaterial absorber", //quantum eraser
|
||||
descriptionFunction() {
|
||||
return `for each mob left <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() {
|
||||
// return `for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br>`
|
||||
@@ -8447,7 +8513,7 @@ const tech = {
|
||||
{
|
||||
name: "symbiosis",
|
||||
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,
|
||||
maxCount: 1,
|
||||
@@ -8491,7 +8557,7 @@ const tech = {
|
||||
{
|
||||
name: "patch",
|
||||
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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -8528,6 +8594,25 @@ const tech = {
|
||||
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",
|
||||
// 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() { }
|
||||
},
|
||||
{
|
||||
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",
|
||||
// descriptionFunction() {
|
||||
@@ -11921,4 +12023,9 @@ const tech = {
|
||||
isHookExplosion: null,
|
||||
isHarpoonDefense: null,
|
||||
isReel: null,
|
||||
harpoonPowerUpCycle: null,
|
||||
isHarpoonFullHealth: null,
|
||||
isMobFullHealth: null,
|
||||
isMobFullHealthCloak: null,
|
||||
isMobLowHealth: null
|
||||
}
|
||||
Reference in New Issue
Block a user