grappling hook field
grappling hook is now a field (work in progress) reworked physics to allow faster speeds, but more control improved rate of power up grabbing more player control to hook retraction rate changed hook shape and field image graphics grappling hook field coupling, more tech, bug fixes, and general polish to be added soon aerostat - 88->100% damage in air 22-> 25% damage on ground foam damage reduced 10%, ammo increased about 10% after hitting an invulnerable mob (drones,spores,worms,iceIX,fleas) don't die or lose cycles added JUNK tech: mobs! - summon 20 random mobs added announcement of mob names in console at start of new level bug fixes
This commit is contained in:
869
js/bullet.js
869
js/bullet.js
@@ -1460,324 +1460,369 @@ const b = {
|
||||
// Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
|
||||
// },
|
||||
grapple(where, angle = m.angle, harpoonSize = 1) {
|
||||
grapple(where, angle = m.angle) {
|
||||
const me = bullet.length;
|
||||
const returnRadius = 100 * Math.sqrt(harpoonSize)
|
||||
const returnRadius = 100
|
||||
bullet[me] = Bodies.fromVertices(where.x, where.y, [{
|
||||
x: -50 * harpoonSize,
|
||||
y: 2 * harpoonSize,
|
||||
x: -40,
|
||||
y: 2,
|
||||
index: 0,
|
||||
isInternal: false
|
||||
}, {
|
||||
x: -50 * harpoonSize,
|
||||
y: -2 * harpoonSize,
|
||||
x: -40,
|
||||
y: -2,
|
||||
index: 1,
|
||||
isInternal: false
|
||||
}, {
|
||||
x: 45 * harpoonSize,
|
||||
y: -3 * harpoonSize,
|
||||
x: 37,
|
||||
y: -2,
|
||||
index: 2,
|
||||
isInternal: false
|
||||
}, {
|
||||
x: 50 * harpoonSize,
|
||||
y: 0,
|
||||
x: 40,
|
||||
y: -1,
|
||||
index: 3,
|
||||
isInternal: false
|
||||
}, {
|
||||
x: 45 * harpoonSize,
|
||||
y: 3 * harpoonSize,
|
||||
x: 34,
|
||||
y: 5,
|
||||
index: 4,
|
||||
isInternal: false
|
||||
}], {
|
||||
angle: angle,
|
||||
friction: 1,
|
||||
frictionAir: 0.4,
|
||||
thrustMag: 0.1,
|
||||
dmg: 6, //damage done in addition to the damage from momentum
|
||||
classType: "bullet",
|
||||
endCycle: simulation.cycle + 70,
|
||||
collisionFilter: {
|
||||
category: cat.bullet,
|
||||
mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
|
||||
},
|
||||
minDmgSpeed: 4,
|
||||
lookFrequency: Math.floor(7 + Math.random() * 3),
|
||||
density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
drain: tech.isRailEnergy ? 0.0006 : 0.006,
|
||||
beforeDmg(who) {
|
||||
if (tech.isShieldPierce && who.isShielded) { //disable shields
|
||||
who.isShielded = false
|
||||
requestAnimationFrame(() => {
|
||||
who.isShielded = true
|
||||
});
|
||||
}
|
||||
if (tech.fragments) {
|
||||
b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random()))
|
||||
}
|
||||
if (tech.isFoamBall) {
|
||||
for (let i = 0, len = 3 * this.mass; i < len; i++) {
|
||||
const radius = 5 + 8 * Math.random()
|
||||
const velocity = {
|
||||
x: Math.max(0.5, 2 - radius * 0.1),
|
||||
y: 0
|
||||
}],
|
||||
|
||||
// [{
|
||||
// x: -10,
|
||||
// y: 2,
|
||||
// index: 0,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: -10,
|
||||
// y: -2,
|
||||
// index: 1,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 35,
|
||||
// y: -3,
|
||||
// index: 2,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 37,
|
||||
// y: -2,
|
||||
// index: 3,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 40,
|
||||
// y: 0,
|
||||
// index: 4,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 37,
|
||||
// y: 2,
|
||||
// index: 5,
|
||||
// isInternal: false
|
||||
// }, {
|
||||
// x: 35,
|
||||
// y: 3,
|
||||
// index: 6,
|
||||
// isInternal: false
|
||||
// }],
|
||||
{
|
||||
angle: angle,
|
||||
friction: 1,
|
||||
frictionAir: 0.4,
|
||||
thrustMag: 0.13,
|
||||
dmg: 6, //damage done in addition to the damage from momentum
|
||||
classType: "bullet",
|
||||
endCycle: simulation.cycle + 70,
|
||||
isSlowPull: false,
|
||||
collisionFilter: {
|
||||
category: cat.bullet,
|
||||
mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
|
||||
},
|
||||
minDmgSpeed: 4,
|
||||
// lookFrequency: Math.floor(7 + Math.random() * 3),
|
||||
density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
|
||||
drain: 0.001,
|
||||
beforeDmg(who) {
|
||||
if (tech.isShieldPierce && who.isShielded) { //disable shields
|
||||
who.isShielded = false
|
||||
requestAnimationFrame(() => {
|
||||
who.isShielded = true
|
||||
});
|
||||
}
|
||||
// if (tech.fragments) {
|
||||
// b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random()))
|
||||
// }
|
||||
// if (tech.isFoamBall) {
|
||||
// for (let i = 0, len = 3 * this.mass; i < len; i++) {
|
||||
// const radius = 5 + 8 * Math.random()
|
||||
// const velocity = {
|
||||
// x: Math.max(0.5, 2 - radius * 0.1),
|
||||
// y: 0
|
||||
// }
|
||||
// b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
|
||||
// }
|
||||
// // this.endCycle = 0;
|
||||
// }
|
||||
if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
|
||||
this.retract()
|
||||
},
|
||||
caughtPowerUp: null,
|
||||
dropCaughtPowerUp() {
|
||||
if (this.caughtPowerUp) {
|
||||
this.caughtPowerUp.collisionFilter.category = cat.powerUp
|
||||
this.caughtPowerUp.collisionFilter.mask = cat.map | cat.powerUp
|
||||
this.caughtPowerUp = null
|
||||
}
|
||||
},
|
||||
onEnd() {
|
||||
if (this.caughtPowerUp && !simulation.isChoosing && (this.caughtPowerUp.name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)) {
|
||||
let index = null //find index
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
if (powerUp[i] === this.caughtPowerUp) index = i
|
||||
}
|
||||
if (index !== null) {
|
||||
powerUps.onPickUp(this.caughtPowerUp);
|
||||
this.caughtPowerUp.effect();
|
||||
Matter.Composite.remove(engine.world, this.caughtPowerUp);
|
||||
powerUp.splice(index, 1);
|
||||
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
|
||||
} else {
|
||||
this.dropCaughtPowerUp()
|
||||
}
|
||||
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
|
||||
}
|
||||
// this.endCycle = 0;
|
||||
}
|
||||
},
|
||||
caughtPowerUp: null,
|
||||
dropCaughtPowerUp() {
|
||||
if (this.caughtPowerUp) {
|
||||
this.caughtPowerUp.collisionFilter.category = cat.powerUp
|
||||
this.caughtPowerUp.collisionFilter.mask = cat.map | cat.powerUp
|
||||
this.caughtPowerUp = null
|
||||
}
|
||||
},
|
||||
onEnd() {
|
||||
if (this.caughtPowerUp && !simulation.isChoosing && (this.caughtPowerUp.name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)) {
|
||||
let index = null //find index
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
if (powerUp[i] === this.caughtPowerUp) index = i
|
||||
}
|
||||
if (index !== null) {
|
||||
powerUps.onPickUp(this.caughtPowerUp);
|
||||
this.caughtPowerUp.effect();
|
||||
Matter.Composite.remove(engine.world, this.caughtPowerUp);
|
||||
powerUp.splice(index, 1);
|
||||
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.004 * 6 //0.005 is normal
|
||||
} else {
|
||||
this.dropCaughtPowerUp()
|
||||
}
|
||||
} else {
|
||||
this.dropCaughtPowerUp()
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
const where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
}
|
||||
const sub = Vector.sub(where, this.vertices[0])
|
||||
const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
|
||||
ctx.strokeStyle = "#000" // "#0ce"
|
||||
ctx.lineWidth = 0.5
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(where.x, where.y);
|
||||
ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
|
||||
// ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
ctx.stroke();
|
||||
//draw harpoon spikes
|
||||
const spikeLength = 2
|
||||
ctx.beginPath();
|
||||
const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
|
||||
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
|
||||
ctx.lineTo(spike1.x, spike1.y);
|
||||
ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
|
||||
|
||||
const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
|
||||
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
|
||||
ctx.lineTo(spike2.x, spike2.y);
|
||||
ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
|
||||
ctx.fillStyle = '#000'
|
||||
ctx.fill();
|
||||
},
|
||||
returnToPlayer() {
|
||||
if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
|
||||
this.endCycle = 0;
|
||||
// if (m.energy < 0.05) {
|
||||
// m.fireCDcycle = m.cycle + 120; //fire cooldown
|
||||
// } else if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) {
|
||||
// m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 25 if it is above 25
|
||||
// }
|
||||
|
||||
if (m.energy < 0.05) this.dropCaughtPowerUp()
|
||||
|
||||
//recoil on catching
|
||||
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
player.force.x += momentum.x
|
||||
player.force.y += momentum.y
|
||||
// refund ammo
|
||||
b.guns[9].ammo++;
|
||||
simulation.updateGunHUD();
|
||||
|
||||
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
// if (b.guns[i].name === "harpoon") {
|
||||
// b.guns[i].ammo++;
|
||||
// simulation.updateGunHUD();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
if (m.energy > this.drain) m.energy -= this.drain
|
||||
const sub = Vector.sub(this.position, m.pos)
|
||||
const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
|
||||
const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
|
||||
this.force.x -= returnForce.x
|
||||
this.force.y -= returnForce.y
|
||||
this.grabPowerUp()
|
||||
}
|
||||
this.draw();
|
||||
},
|
||||
grabPowerUp() { //grab power ups near the tip of the harpoon
|
||||
if (this.caughtPowerUp) {
|
||||
Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
|
||||
Matter.Body.setVelocity(this.caughtPowerUp, {
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
} else { //&& simulation.cycle % 2
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
const radius = powerUp[i].circleRadius + 50
|
||||
if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) {
|
||||
if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
|
||||
this.caughtPowerUp = powerUp[i]
|
||||
Matter.Body.setVelocity(powerUp[i], {
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
Matter.Body.setPosition(powerUp[i], this.vertices[2])
|
||||
powerUp[i].collisionFilter.category = 0
|
||||
powerUp[i].collisionFilter.mask = 0
|
||||
this.thrustMag *= 0.6
|
||||
this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
|
||||
break //just pull 1 power up if possible
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
const where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
}
|
||||
}
|
||||
},
|
||||
do() {
|
||||
if (input.fire) { //&& !Matter.Query.collides(this, body).length
|
||||
this.grabPowerUp()
|
||||
if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction
|
||||
this.endCycle = simulation.cycle + 60
|
||||
// m.fireCDcycle = m.cycle + 120 // cool down
|
||||
this.do = this.returnToPlayer
|
||||
Matter.Body.setDensity(this, 0.0005); //reduce density on return
|
||||
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
|
||||
this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
|
||||
}
|
||||
} else {
|
||||
//if not enough energy
|
||||
if (m.energy < 0.05) this.dropCaughtPowerUp()
|
||||
// const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
|
||||
// this.force.x -= returnForce.x
|
||||
// this.force.y -= returnForce.y
|
||||
// this.frictionAir = 0.002
|
||||
// this.do = () => {
|
||||
// if (this.speed < 20) this.force.y += 0.0005 * this.mass;
|
||||
// }
|
||||
const sub = Vector.sub(where, this.vertices[0])
|
||||
const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
|
||||
ctx.strokeStyle = "#000" // "#0ce"
|
||||
ctx.lineWidth = 0.5
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(where.x, where.y);
|
||||
ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
|
||||
// ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
|
||||
ctx.stroke();
|
||||
//draw harpoon spikes
|
||||
const spikeLength = 2
|
||||
ctx.beginPath();
|
||||
const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
|
||||
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
|
||||
ctx.lineTo(spike1.x, spike1.y);
|
||||
ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
|
||||
|
||||
// } else {
|
||||
//return to player
|
||||
const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
|
||||
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
|
||||
ctx.lineTo(spike2.x, spike2.y);
|
||||
ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
|
||||
ctx.fillStyle = '#000'
|
||||
ctx.fill();
|
||||
},
|
||||
retract() {
|
||||
this.do = this.returnToPlayer
|
||||
this.endCycle = simulation.cycle + 60
|
||||
Matter.Body.setDensity(this, 0.0005); //reduce density on return
|
||||
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
|
||||
this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
|
||||
//recoil on catching
|
||||
this.collisionFilter.mask = 0//cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
|
||||
//recoil on pulling grapple back
|
||||
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
player.force.x += momentum.x
|
||||
player.force.y += momentum.y
|
||||
// }
|
||||
}
|
||||
//grappling hook
|
||||
if (input.fire && Matter.Query.collides(this, map).length) {
|
||||
Matter.Body.setPosition(this, Vector.add(this.position, {
|
||||
x: 20 * Math.cos(this.angle),
|
||||
y: 20 * Math.sin(this.angle)
|
||||
}))
|
||||
if (Matter.Query.collides(this, map).length) {
|
||||
Matter.Body.setVelocity(this, {
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
Matter.Sleeping.set(this, true)
|
||||
this.endCycle = simulation.cycle + 5
|
||||
this.dropCaughtPowerUp()
|
||||
this.do = () => {
|
||||
//between player nose and the grapple
|
||||
const sub = Vector.sub(this.vertices[0], {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
})
|
||||
let dist = Vector.magnitude(sub)
|
||||
if (input.fire) {
|
||||
// m.fireCDcycle = m.cycle + 30; // cool down if out of energy
|
||||
m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
|
||||
this.endCycle = simulation.cycle + 10
|
||||
if (input.down) { //down
|
||||
dist = 0
|
||||
player.force.y += 5 * player.mass * simulation.g;
|
||||
}
|
||||
if (m.energy > this.drain) {
|
||||
Matter.Body.setVelocity(player, {
|
||||
x: player.velocity.x * 0.8,
|
||||
y: player.velocity.y * 0.8
|
||||
});
|
||||
},
|
||||
returnToPlayer() {
|
||||
if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
|
||||
if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
|
||||
this.endCycle = 0;
|
||||
//recoil on catching grapple
|
||||
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
player.force.x += momentum.x
|
||||
player.force.y += momentum.y
|
||||
|
||||
|
||||
//need to scale the friction differently based on distance?
|
||||
// if (dist > 500) {
|
||||
const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), 200))
|
||||
player.force.x += pull.x
|
||||
player.force.y += pull.y
|
||||
// }
|
||||
|
||||
if (dist > 500) {
|
||||
m.energy -= this.drain
|
||||
if (m.energy < 0) {
|
||||
this.endCycle = 0;
|
||||
if (m.cycle + 50 < m.fireCDcycle) m.fireCDcycle = m.cycle + 50
|
||||
// refund ammo
|
||||
b.guns[9].ammo++;
|
||||
simulation.updateGunHUD();
|
||||
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
// if (b.guns[i].name === "harpoon") {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m.energy > this.drain) m.energy -= this.drain
|
||||
const sub = Vector.sub(this.position, m.pos)
|
||||
const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
|
||||
const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
|
||||
this.force.x -= returnForce.x
|
||||
this.force.y -= returnForce.y
|
||||
this.grabPowerUp()
|
||||
}
|
||||
this.draw();
|
||||
},
|
||||
destroyBlocks() {
|
||||
const blocks = Matter.Query.collides(this, body)
|
||||
if (blocks.length && !blocks[0].bodyA.isNotHoldable) {
|
||||
if (blocks[0].bodyA.mass > 2.5) this.retract()
|
||||
const block = blocks[0].bodyA.vertices
|
||||
Composite.remove(engine.world, blocks[0].bodyA)
|
||||
body.splice(body.indexOf(blocks[0].bodyA), 1)
|
||||
//animate the block fading away
|
||||
simulation.ephemera.push({
|
||||
name: "blockFadeOut",
|
||||
count: 25, //cycles before it self removes
|
||||
do() {
|
||||
this.count--
|
||||
if (this.count < 0) simulation.removeEphemera(this.name)
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(block[0].x, block[0].y);
|
||||
for (let j = 1; j < block.length; j++) ctx.lineTo(block[j].x, block[j].y);
|
||||
ctx.lineTo(block[0].x, block[0].y);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeStyle = `rgba(0,0,0,${this.count / 25})`
|
||||
ctx.stroke();
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
grabPowerUp() { //grab power ups near the tip of the harpoon
|
||||
if (this.caughtPowerUp) {
|
||||
Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
|
||||
Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
|
||||
} else {
|
||||
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
||||
const radius = powerUp[i].circleRadius + 50
|
||||
if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) {
|
||||
if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
|
||||
this.caughtPowerUp = powerUp[i]
|
||||
Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
|
||||
Matter.Body.setPosition(powerUp[i], this.vertices[2])
|
||||
powerUp[i].collisionFilter.category = 0
|
||||
powerUp[i].collisionFilter.mask = 0
|
||||
this.thrustMag *= 0.6
|
||||
this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
|
||||
this.retract()
|
||||
break //just pull 1 power up if possible
|
||||
}
|
||||
if (tech.isImmuneGrapple && m.immuneCycle < m.cycle + 10) {
|
||||
m.immuneCycle = m.cycle + 10;
|
||||
if (m.energy > 0.001) {
|
||||
m.energy -= 0.001
|
||||
} else { //out of energy
|
||||
Matter.Sleeping.set(this, false)
|
||||
this.collisionFilter.category = 0
|
||||
this.collisionFilter.mask = 0
|
||||
this.do = this.returnToPlayer
|
||||
this.endCycle = simulation.cycle + 60
|
||||
m.fireCDcycle = m.cycle + 120; //fire cooldown
|
||||
//recoil on catching
|
||||
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
player.force.x += momentum.x
|
||||
player.force.y += momentum.y
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Matter.Sleeping.set(this, false)
|
||||
this.collisionFilter.category = 0
|
||||
this.collisionFilter.mask = 0
|
||||
this.do = this.returnToPlayer
|
||||
this.endCycle = simulation.cycle + 60
|
||||
//recoil on catching
|
||||
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
player.force.x += momentum.x
|
||||
player.force.y += momentum.y
|
||||
}
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
|
||||
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
|
||||
this.draw()
|
||||
},
|
||||
});
|
||||
m.grabPowerUp();
|
||||
},
|
||||
do() {
|
||||
if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
|
||||
if (input.field) { //&& !Matter.Query.collides(this, body).length
|
||||
this.destroyBlocks()
|
||||
this.grabPowerUp()
|
||||
// if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down field, force retraction
|
||||
// this.endCycle = simulation.cycle + 30
|
||||
// // m.fireCDcycle = m.cycle + 120 // cool down
|
||||
// this.do = this.returnToPlayer
|
||||
// Matter.Body.setDensity(this, 0.0005); //reduce density on return
|
||||
// if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
|
||||
// this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
|
||||
// }
|
||||
} else {
|
||||
//if not enough energy
|
||||
// if (m.energy < 0.01) this.dropCaughtPowerUp()
|
||||
// const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
|
||||
// this.force.x -= returnForce.x
|
||||
// this.force.y -= returnForce.y
|
||||
// this.frictionAir = 0.002
|
||||
// this.do = () => {
|
||||
// if (this.speed < 20) this.force.y += 0.0005 * this.mass;
|
||||
// }
|
||||
|
||||
// } else {
|
||||
//return to player
|
||||
this.retract()
|
||||
// }
|
||||
}
|
||||
//grappling hook
|
||||
if (input.field && Matter.Query.collides(this, map).length) {
|
||||
Matter.Body.setPosition(this, Vector.add(this.position, { x: -20 * Math.cos(this.angle), y: -20 * Math.sin(this.angle) }))
|
||||
if (Matter.Query.collides(this, map).length) {
|
||||
Matter.Body.setVelocity(this, { x: 0, y: 0 });
|
||||
Matter.Sleeping.set(this, true)
|
||||
this.endCycle = simulation.cycle + 5
|
||||
// this.dropCaughtPowerUp()
|
||||
this.do = () => {
|
||||
if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
|
||||
// if (this.caughtPowerUp) {
|
||||
// Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
|
||||
// Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
|
||||
// }
|
||||
this.grabPowerUp()
|
||||
|
||||
//between player nose and the grapple
|
||||
const sub = Vector.sub(this.vertices[0], { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) })
|
||||
let dist = Vector.magnitude(sub)
|
||||
if (input.field) {
|
||||
// m.fireCDcycle = m.cycle + 30; // cool down if out of energy
|
||||
// m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
|
||||
// if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
|
||||
this.endCycle = simulation.cycle + 10
|
||||
if (input.down) { //down
|
||||
this.isSlowPull = true
|
||||
dist = 0
|
||||
player.force.y += 2.5 * player.mass * simulation.g; //adjust this to control fall rate while hooked and pressing down
|
||||
} else if (input.up) {
|
||||
this.isSlowPull = false
|
||||
}
|
||||
if (m.energy < this.drain) this.isSlowPull = true
|
||||
|
||||
// pulling friction that allowed a slight swinging, but has high linear pull at short dist
|
||||
const drag = 1 - 30 / Math.min(Math.max(100, dist), 700) - 0.1 * (player.speed > 70)
|
||||
// console.log(player.speed)
|
||||
Matter.Body.setVelocity(player, { x: player.velocity.x * drag, y: player.velocity.y * drag });
|
||||
const pullScale = 0.0004
|
||||
const pull = Vector.mult(Vector.normalise(sub), pullScale * Math.min(Math.max(15, dist), this.isSlowPull ? 70 : 200))
|
||||
//original pulling force with high friction and very linear pull
|
||||
// Matter.Body.setVelocity(player, { x: player.velocity.x * 0.85, y: player.velocity.y * 0.85 });
|
||||
// const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), this.isSlowPull ? 100 : 200))
|
||||
|
||||
player.force.x += pull.x
|
||||
player.force.y += pull.y
|
||||
if (dist > 500) {
|
||||
m.energy -= this.drain
|
||||
// if (m.energy < 0) this.endCycle = 0;
|
||||
}
|
||||
|
||||
// if (tech.isImmuneGrapple && m.immuneCycle < m.cycle + 10) {
|
||||
// m.immuneCycle = m.cycle + 10;
|
||||
// if (m.energy > 0.001) {
|
||||
// m.energy -= 0.001
|
||||
// } else { //out of energy
|
||||
// Matter.Sleeping.set(this, false)
|
||||
// this.collisionFilter.category = 0
|
||||
// this.collisionFilter.mask = 0
|
||||
// this.do = this.returnToPlayer
|
||||
// this.endCycle = simulation.cycle + 60
|
||||
// // m.fireCDcycle = m.cycle + 120; //fire cooldown
|
||||
// if (m.fieldCDcycle < m.cycle + 120) m.fieldCDcycle = m.cycle + 120
|
||||
|
||||
// //recoil on catching
|
||||
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
// player.force.x += momentum.x
|
||||
// player.force.y += momentum.y
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
Matter.Sleeping.set(this, false)
|
||||
this.retract()
|
||||
// Matter.Sleeping.set(this, false)
|
||||
// this.collisionFilter.category = 0
|
||||
// this.collisionFilter.mask = 0
|
||||
// this.do = this.returnToPlayer
|
||||
// this.endCycle = simulation.cycle + 60
|
||||
// //recoil on catching
|
||||
// const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
|
||||
// player.force.x += momentum.x
|
||||
// player.force.y += momentum.y
|
||||
}
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
|
||||
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
|
||||
this.draw()
|
||||
},
|
||||
});
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
},
|
||||
// grapple(where, angle = m.angle, harpoonSize = 1) {
|
||||
@@ -3178,20 +3223,24 @@ const b = {
|
||||
y: 100 * (Math.random() - 0.5)
|
||||
},
|
||||
beforeDmg(who) {
|
||||
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
|
||||
setTimeout(() => {
|
||||
if (!who.alive) {
|
||||
for (let i = 0; i < 3; i++) { //spawn 3 more
|
||||
b.worm(this.position)
|
||||
bullet[bullet.length - 1].endCycle = Math.min(simulation.cycle + Math.floor(420 * tech.bulletsLastLonger), this.endCycle + 180 + Math.floor(60 * Math.random())) //simulation.cycle + Math.floor(420 * tech.bulletsLastLonger)
|
||||
}
|
||||
}
|
||||
this.endCycle = 0; //bullet ends cycle after doing damage
|
||||
}, 1);
|
||||
if (who.isInvulnerable) {
|
||||
Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.1));
|
||||
} else {
|
||||
this.endCycle = 0; //bullet ends cycle after doing damage
|
||||
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
|
||||
setTimeout(() => {
|
||||
if (!who.alive) {
|
||||
for (let i = 0; i < 3; i++) { //spawn 3 more
|
||||
b.worm(this.position)
|
||||
bullet[bullet.length - 1].endCycle = Math.min(simulation.cycle + Math.floor(420 * tech.bulletsLastLonger), this.endCycle + 180 + Math.floor(60 * Math.random())) //simulation.cycle + Math.floor(420 * tech.bulletsLastLonger)
|
||||
}
|
||||
}
|
||||
this.endCycle = 0; //bullet ends cycle after doing damage
|
||||
}, 1);
|
||||
} else {
|
||||
this.endCycle = 0; //bullet ends cycle after doing damage
|
||||
}
|
||||
if (this.isFreeze) mobs.statusSlow(who, 90)
|
||||
}
|
||||
if (this.isFreeze) mobs.statusSlow(who, 90)
|
||||
},
|
||||
onEnd() {
|
||||
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
|
||||
@@ -3295,8 +3344,10 @@ const b = {
|
||||
y: 100 * (Math.random() - 0.5)
|
||||
},
|
||||
beforeDmg(who) {
|
||||
this.endCycle = 0; //bullet ends cycle after doing damage
|
||||
if (this.isFreeze) mobs.statusSlow(who, 90)
|
||||
if (!who.isInvulnerable) {
|
||||
this.endCycle = 0; //bullet ends cycle after doing damage
|
||||
if (this.isFreeze) mobs.statusSlow(who, 90)
|
||||
}
|
||||
},
|
||||
onEnd() {
|
||||
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
|
||||
@@ -3304,7 +3355,7 @@ const b = {
|
||||
if (m.health > m.maxHealth) m.health = m.maxHealth;
|
||||
m.displayHealth();
|
||||
}
|
||||
console.log(this.dmg)
|
||||
// console.log(this.dmg)
|
||||
},
|
||||
do() {
|
||||
if (this.lockedOn && this.lockedOn.alive) {
|
||||
@@ -3425,13 +3476,15 @@ const b = {
|
||||
minDmgSpeed: 0,
|
||||
lockedOn: null,
|
||||
beforeDmg(who) {
|
||||
if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
|
||||
setTimeout(() => {
|
||||
if (!who.alive) m.energy += tech.iceEnergy * 0.8
|
||||
}, 10);
|
||||
if (!who.isInvulnerable) {
|
||||
if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
|
||||
setTimeout(() => {
|
||||
if (!who.alive) m.energy += tech.iceEnergy * 0.8
|
||||
}, 10);
|
||||
}
|
||||
mobs.statusSlow(who, tech.iceIXFreezeTime)
|
||||
this.endCycle = simulation.cycle
|
||||
}
|
||||
mobs.statusSlow(who, tech.iceIXFreezeTime)
|
||||
this.endCycle = simulation.cycle
|
||||
// if (tech.isHeavyWater) mobs.statusDoT(who, 0.15, 300)
|
||||
},
|
||||
onEnd() { },
|
||||
@@ -3507,27 +3560,29 @@ const b = {
|
||||
},
|
||||
beforeDmg(who) {
|
||||
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target
|
||||
this.endCycle -= 130
|
||||
this.cd = simulation.cycle + this.delay;
|
||||
if (tech.isSporeFreeze) mobs.statusSlow(who, 90)
|
||||
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
|
||||
setTimeout(() => {
|
||||
if (!who.alive) {
|
||||
for (let i = 0; i < 2; i++) { //spawn 2 more
|
||||
const speed = 10 + 5 * Math.random()
|
||||
const angle = 2 * Math.PI * Math.random()
|
||||
b.flea(this.position, {
|
||||
x: speed * Math.cos(angle),
|
||||
y: speed * Math.sin(angle)
|
||||
})
|
||||
if (!who.isInvulnerable) {
|
||||
this.endCycle -= 130
|
||||
if (tech.isSporeFreeze) mobs.statusSlow(who, 90)
|
||||
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
|
||||
setTimeout(() => {
|
||||
if (!who.alive) {
|
||||
for (let i = 0; i < 2; i++) { //spawn 2 more
|
||||
const speed = 10 + 5 * Math.random()
|
||||
const angle = 2 * Math.PI * Math.random()
|
||||
b.flea(this.position, {
|
||||
x: speed * Math.cos(angle),
|
||||
y: speed * Math.sin(angle)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.endCycle = 0;
|
||||
}, 1);
|
||||
this.endCycle = 0;
|
||||
}, 1);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.dmg = 0
|
||||
})
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.dmg = 0
|
||||
})
|
||||
},
|
||||
onEnd() {
|
||||
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
|
||||
@@ -3659,27 +3714,31 @@ const b = {
|
||||
deathCycles: 110 + RADIUS * 5,
|
||||
isImproved: false,
|
||||
beforeDmg(who) {
|
||||
if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) {
|
||||
const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0)
|
||||
b.explosion(this.position, max * 0.1 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end
|
||||
if (tech.isForeverDrones) {
|
||||
this.endCycle = 0
|
||||
b.drone({
|
||||
x: m.pos.x + 30 * (Math.random() - 0.5),
|
||||
y: m.pos.y + 30 * (Math.random() - 0.5)
|
||||
}, 5)
|
||||
bullet[bullet.length - 1].endCycle = Infinity
|
||||
} else {
|
||||
this.endCycle -= max
|
||||
}
|
||||
} else {
|
||||
if (who.isInvulnerable) {
|
||||
//move away from target after hitting
|
||||
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20)
|
||||
Matter.Body.setVelocity(this, { x: unit.x, y: unit.y });
|
||||
this.lockedOn = null
|
||||
if (this.endCycle > simulation.cycle + this.deathCycles) {
|
||||
this.endCycle -= 60
|
||||
if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles
|
||||
} else {
|
||||
if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) {
|
||||
const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0)
|
||||
b.explosion(this.position, max * 0.1 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end
|
||||
if (tech.isForeverDrones) {
|
||||
this.endCycle = 0
|
||||
b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
|
||||
bullet[bullet.length - 1].endCycle = Infinity
|
||||
} else {
|
||||
this.endCycle -= max
|
||||
}
|
||||
} else {
|
||||
//move away from target after hitting
|
||||
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20)
|
||||
Matter.Body.setVelocity(this, { x: unit.x, y: unit.y });
|
||||
this.lockedOn = null
|
||||
if (this.endCycle > simulation.cycle + this.deathCycles) {
|
||||
this.endCycle -= 60
|
||||
if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4193,28 +4252,39 @@ const b = {
|
||||
};
|
||||
}
|
||||
bullet[me].beforeDmg = function (who) {
|
||||
if (tech.oneSuperBall) mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds)
|
||||
if (tech.isFoamBall) {
|
||||
for (let i = 0, len = 5 * this.mass; i < len; i++) {
|
||||
const radius = 5 + 8 * Math.random()
|
||||
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
|
||||
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
|
||||
if (!who.isInvulnerable) {
|
||||
if (tech.oneSuperBall) mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds)
|
||||
if (tech.isFoamBall) {
|
||||
for (let i = 0, len = 5 * this.mass; i < len; i++) {
|
||||
const radius = 5 + 8 * Math.random()
|
||||
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
|
||||
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
|
||||
}
|
||||
this.endCycle = 0
|
||||
}
|
||||
this.endCycle = 0
|
||||
}
|
||||
if (tech.isIncendiary) {
|
||||
b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end
|
||||
this.endCycle = 0
|
||||
} else if (tech.isSuperBounce) {
|
||||
const cycle = () => {
|
||||
Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage
|
||||
this.endCycle = simulation.cycle + Math.floor(300 + 90 * Math.random()); //reset to full duration of time
|
||||
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(this.velocity), 60)); //reset to high velocity
|
||||
if (tech.isIncendiary) {
|
||||
b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end
|
||||
this.endCycle = 0
|
||||
} else if (tech.isSuperBounce) {
|
||||
const cycle = () => {
|
||||
Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage
|
||||
this.endCycle = simulation.cycle + Math.floor(300 + 90 * Math.random()); //reset to full duration of time
|
||||
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(this.velocity), 60)); //reset to high velocity
|
||||
|
||||
let count = 5
|
||||
const wait = () => {
|
||||
count--
|
||||
if (count > 0) requestAnimationFrame(wait);
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: this.position.x,
|
||||
y: this.position.y,
|
||||
radius: radius,
|
||||
color: 'rgba(255, 0, 0, 0.33)',
|
||||
time: 8
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(wait);
|
||||
|
||||
let count = 5
|
||||
const wait = () => {
|
||||
count--
|
||||
if (count > 0) requestAnimationFrame(wait);
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: this.position.x,
|
||||
y: this.position.y,
|
||||
@@ -4223,17 +4293,8 @@ const b = {
|
||||
time: 8
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(wait);
|
||||
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: this.position.x,
|
||||
y: this.position.y,
|
||||
radius: radius,
|
||||
color: 'rgba(255, 0, 0, 0.33)',
|
||||
time: 8
|
||||
});
|
||||
requestAnimationFrame(cycle);
|
||||
}
|
||||
requestAnimationFrame(cycle);
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -5394,7 +5455,7 @@ const b = {
|
||||
cd: 0,
|
||||
fireCount: 0,
|
||||
fireLimit: 5 + 2 * tech.isFoamBotUpgrade,
|
||||
delay: Math.floor((150 + (tech.isFoamBotUpgrade ? 0 : 250)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
|
||||
delay: Math.floor((145 + (tech.isFoamBotUpgrade ? 0 : 230)) * b.fireCDscale),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade,
|
||||
acceleration: 0.005 * (1 + 0.5 * Math.random()),
|
||||
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move
|
||||
endCycle: Infinity,
|
||||
@@ -7717,7 +7778,7 @@ const b = {
|
||||
return `spray bubbly <strong>foam</strong> that <strong>sticks</strong> to mobs<br><strong class='color-s'>slows</strong> mobs and does <strong class='color-d'>damage</strong> over time<br><strong>${this.ammoPack.toFixed(0)}</strong> bubbles per ${powerUps.orb.ammo()}`
|
||||
},
|
||||
ammo: 0,
|
||||
ammoPack: 24,
|
||||
ammoPack: 28,
|
||||
have: false,
|
||||
charge: 0,
|
||||
isDischarge: false,
|
||||
@@ -7842,9 +7903,9 @@ const b = {
|
||||
if (tech.isRailGun) {
|
||||
this.do = this.railDo
|
||||
this.fire = this.railFire
|
||||
} else if (tech.isGrapple) {
|
||||
this.do = () => { }
|
||||
this.fire = this.grappleFire
|
||||
// } else if (tech.isGrapple) {
|
||||
// this.do = () => { }
|
||||
// this.fire = this.grappleFire
|
||||
} else {
|
||||
this.do = () => { }
|
||||
this.fire = this.harpoonFire
|
||||
@@ -8054,36 +8115,36 @@ const b = {
|
||||
m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
|
||||
this.charge += 0.00001
|
||||
},
|
||||
grappleFire() {
|
||||
const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (m.crouch ? 0.7 : 1)
|
||||
const where = {
|
||||
x: m.pos.x + harpoonSize * 40 * Math.cos(m.angle),
|
||||
y: m.pos.y + harpoonSize * 40 * Math.sin(m.angle)
|
||||
}
|
||||
const num = Math.min(this.ammo, tech.extraHarpoons + 1)
|
||||
if (!m.crouch && num > 1) { //multiple harpoons
|
||||
const SPREAD = 0.06
|
||||
let angle = m.angle - SPREAD * num / 2;
|
||||
for (let i = 0; i < num; i++) {
|
||||
if (this.ammo > 0) {
|
||||
this.ammo--
|
||||
b.grapple(where, angle, true, harpoonSize)
|
||||
angle += SPREAD
|
||||
}
|
||||
}
|
||||
this.ammo++ //make up for the ammo used up in fire()
|
||||
simulation.updateGunHUD();
|
||||
m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
|
||||
// } else if (m.crouch) {
|
||||
// b.harpoon(where, null, m.angle, harpoonSize, false, 70)
|
||||
} else {
|
||||
if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1
|
||||
b.grapple(where, m.angle, harpoonSize)
|
||||
}
|
||||
// m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
|
||||
m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
|
||||
// grappleFire() {
|
||||
// const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (m.crouch ? 0.7 : 1)
|
||||
// const where = {
|
||||
// x: m.pos.x + harpoonSize * 40 * Math.cos(m.angle),
|
||||
// y: m.pos.y + harpoonSize * 40 * Math.sin(m.angle)
|
||||
// }
|
||||
// const num = Math.min(this.ammo, tech.extraHarpoons + 1)
|
||||
// if (!m.crouch && num > 1) { //multiple harpoons
|
||||
// const SPREAD = 0.06
|
||||
// let angle = m.angle - SPREAD * num / 2;
|
||||
// for (let i = 0; i < num; i++) {
|
||||
// if (this.ammo > 0) {
|
||||
// this.ammo--
|
||||
// b.grapple(where, angle, true, harpoonSize)
|
||||
// angle += SPREAD
|
||||
// }
|
||||
// }
|
||||
// this.ammo++ //make up for the ammo used up in fire()
|
||||
// simulation.updateGunHUD();
|
||||
// m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
|
||||
// // } else if (m.crouch) {
|
||||
// // b.harpoon(where, null, m.angle, harpoonSize, false, 70)
|
||||
// } else {
|
||||
// if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1
|
||||
// b.grapple(where, m.angle, harpoonSize)
|
||||
// }
|
||||
// // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
|
||||
// m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
|
||||
|
||||
},
|
||||
// },
|
||||
harpoonFire() {
|
||||
const where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
|
||||
34
js/level.js
34
js/level.js
@@ -28,17 +28,17 @@ const level = {
|
||||
// m.immuneCycle = Infinity //you can't take damage
|
||||
// tech.tech[297].frequency = 100
|
||||
// m.couplingChange(10)
|
||||
// m.setField("wormhole") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole
|
||||
// m.setField("grappling hook") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
|
||||
// m.energy = 0
|
||||
// simulation.molecularMode = 2
|
||||
// m.damage(0.1);
|
||||
// b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
|
||||
// b.giveGuns("foam") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
|
||||
// b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
|
||||
// b.guns[8].ammo = 100000000
|
||||
// requestAnimationFrame(() => { tech.giveTech("MACHO") });
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("electrostatic induction")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("enthalpy")
|
||||
// for (let i = 0; i < 10; ++i) tech.giveTech("quasiparticles")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("grappling hook")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("superdeterminism")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("fine-structure constant")
|
||||
// for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade")
|
||||
// requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") });
|
||||
@@ -49,11 +49,11 @@ const level = {
|
||||
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
|
||||
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
|
||||
|
||||
// level.biohazard();
|
||||
// level.testing();
|
||||
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
|
||||
// for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500)
|
||||
// for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500)
|
||||
// spawn.suckerBoss(1900, -500, 25)
|
||||
// spawn.beetleBoss(1900, -500, 25)
|
||||
// spawn.slasher2(2000, -1150)
|
||||
// spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color)
|
||||
// for (let i = 0; i < 20; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random())
|
||||
@@ -239,6 +239,10 @@ const level = {
|
||||
// <br><span class='color-var'>m</span>.field.description = "<span class='color-text'>${m.fieldUpgrades[m.fieldMode].description}</span>"
|
||||
// `, 1200);
|
||||
},
|
||||
announceMobTypes() {
|
||||
simulation.makeTextLog(`spawn<span class='color-symbol'>.</span>${spawn.pickList[0]}<span class='color-symbol'>(</span>x<span class='color-symbol'>,</span>y<span class='color-symbol'>)</span>`)
|
||||
simulation.makeTextLog(`spawn<span class='color-symbol'>.</span>${spawn.pickList[1]}<span class='color-symbol'>(</span>x<span class='color-symbol'>,</span>y<span class='color-symbol'>)</span>`)
|
||||
},
|
||||
disableExit: false,
|
||||
nextLevel() {
|
||||
if (!level.disableExit) {
|
||||
@@ -1874,6 +1878,7 @@ const level = {
|
||||
//******************************************************************************************************************
|
||||
//******************************************************************************************************************
|
||||
template() {
|
||||
// level.announceMobTypes()
|
||||
simulation.enableConstructMode()
|
||||
level.setPosToSpawn(0, -50); //normal spawn
|
||||
level.exit.x = 1500;
|
||||
@@ -2375,9 +2380,6 @@ const level = {
|
||||
ctx.fillStyle = "rgba(68, 68, 68,0.95)"
|
||||
ctx.fillRect(2030, 0, 150, 1800);
|
||||
};
|
||||
|
||||
|
||||
|
||||
level.setPosToSpawn(460, -100); //normal spawn
|
||||
// level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left
|
||||
level.exit.x = 2800;
|
||||
@@ -3451,6 +3453,7 @@ const level = {
|
||||
simulation.draw.drawMapPath = simulation.draw.drawMapSight
|
||||
},
|
||||
reservoir() {
|
||||
level.announceMobTypes()
|
||||
level.exit.x = 1700;
|
||||
level.exit.y = -4510;
|
||||
spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
|
||||
@@ -3966,6 +3969,7 @@ const level = {
|
||||
powerUps.addResearchToLevel() //needs to run after mobs are spawned
|
||||
},
|
||||
factory() {
|
||||
level.announceMobTypes()
|
||||
// simulation.enableConstructMode() //remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// level.difficultyIncrease(10 * 4) //30 is near max on hard //60 is near max on why
|
||||
|
||||
@@ -4249,6 +4253,7 @@ const level = {
|
||||
powerUps.spawn(5200, -1300, "ammo");
|
||||
},
|
||||
labs() {
|
||||
level.announceMobTypes()
|
||||
level.isProcedural = true //used in generating text for the level builder
|
||||
level.defaultZoom = 1700
|
||||
simulation.zoomTransition(level.defaultZoom)
|
||||
@@ -5347,6 +5352,7 @@ const level = {
|
||||
powerUps.addResearchToLevel() //needs to run after mobs are spawned
|
||||
},
|
||||
pavilion() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
const vanish = []
|
||||
level.exit.x = -850;
|
||||
@@ -5499,6 +5505,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
testChamber() {
|
||||
level.announceMobTypes()
|
||||
level.setPosToSpawn(0, -50); //lower start
|
||||
level.exit.y = level.enter.y - 550;
|
||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
||||
@@ -5757,6 +5764,7 @@ const level = {
|
||||
|
||||
},
|
||||
lock() {
|
||||
level.announceMobTypes()
|
||||
level.setPosToSpawn(0, -65); //lower start
|
||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
||||
level.exit.y = 2010;
|
||||
@@ -6006,6 +6014,7 @@ const level = {
|
||||
powerUps.addResearchToLevel() //needs to run after mobs are spawned
|
||||
},
|
||||
sewers() {
|
||||
level.announceMobTypes()
|
||||
const button1 = level.button(6600, 2675)
|
||||
// const hazard = level.hazard(4550, 2750, 4550, 150)
|
||||
const hazard = level.hazard(simulation.isHorizontalFlipped ? -4550 - 4550 : 4550, 2750, 4550, 150)
|
||||
@@ -6196,6 +6205,7 @@ const level = {
|
||||
|
||||
},
|
||||
satellite() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
const boost1 = level.boost(5825, 235, 1400)
|
||||
const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 }
|
||||
@@ -6372,6 +6382,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
rooftops() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
// level.fallPosition = { x: 5000, y:-4000}
|
||||
const elevator = level.elevator(1450, -990, 235, 45, -2000)
|
||||
@@ -6560,6 +6571,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
aerie() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
const boost1 = level.boost(-425, 100, 1400)
|
||||
const boost2 = level.boost(5350, 275, 2850);
|
||||
@@ -6789,6 +6801,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
skyscrapers() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
const boost1 = level.boost(475, 0, 1300)
|
||||
const boost2 = level.boost(4450, 0, 1300);
|
||||
@@ -6927,6 +6940,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
highrise() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, {
|
||||
up: 0.01,
|
||||
@@ -7212,6 +7226,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
warehouse() {
|
||||
level.announceMobTypes()
|
||||
level.isEndlessFall = true;
|
||||
level.custom = () => {
|
||||
ctx.fillStyle = "#444" //light fixtures
|
||||
@@ -7531,6 +7546,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
office() {
|
||||
level.announceMobTypes()
|
||||
let button, door
|
||||
let isReverse = false
|
||||
if (Math.random() < 0.75) { //normal direction start in top left
|
||||
|
||||
132
js/player.js
132
js/player.js
@@ -568,7 +568,7 @@ const m = {
|
||||
if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
|
||||
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
|
||||
if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0165, 0.66)
|
||||
if (tech.isHarmReduce && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.25
|
||||
if (tech.isHarmReduce && input.field) dmg *= 0.25
|
||||
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.1
|
||||
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
|
||||
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
|
||||
@@ -2779,14 +2779,10 @@ const m = {
|
||||
effect: () => {
|
||||
m.fieldMeterColor = "#48f" //"#0c5"
|
||||
m.eyeFillColor = m.fieldMeterColor
|
||||
|
||||
m.fieldShieldingScale = 0;
|
||||
m.fieldBlockCD = 3;
|
||||
m.grabPowerUpRange2 = 10000000
|
||||
m.fieldPosition = {
|
||||
x: m.pos.x,
|
||||
y: m.pos.y
|
||||
}
|
||||
m.fieldPosition = { x: m.pos.x, y: m.pos.y }
|
||||
m.fieldAngle = m.angle
|
||||
m.perfectPush = (isFree = false) => {
|
||||
if (m.fieldCDcycle < m.cycle) {
|
||||
@@ -2794,10 +2790,7 @@ const m = {
|
||||
if (
|
||||
Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) - mob[i].radius < m.fieldRange &&
|
||||
!mob[i].isUnblockable &&
|
||||
Vector.dot({
|
||||
x: Math.cos(m.fieldAngle),
|
||||
y: Math.sin(m.fieldAngle)
|
||||
}, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold &&
|
||||
Vector.dot({ x: Math.cos(m.fieldAngle), y: Math.sin(m.fieldAngle) }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold &&
|
||||
Matter.Query.ray(map, mob[i].position, m.fieldPosition).length === 0
|
||||
) {
|
||||
mob[i].locatePlayer();
|
||||
@@ -2816,11 +2809,7 @@ const m = {
|
||||
}
|
||||
}
|
||||
if (tech.blockDmg) { //electricity
|
||||
Matter.Body.setVelocity(mob[i], {
|
||||
x: 0.5 * mob[i].velocity.x,
|
||||
y: 0.5 * mob[i].velocity.y
|
||||
});
|
||||
|
||||
Matter.Body.setVelocity(mob[i], { x: 0.5 * mob[i].velocity.x, y: 0.5 * mob[i].velocity.y });
|
||||
if (mob[i].isShielded) {
|
||||
for (let j = 0, len = mob.length; j < len; j++) {
|
||||
if (mob[j].id === mob[i].shieldID) mob[j].damage(tech.blockDmg * m.dmgScale * (tech.isBlockRadiation ? 6 : 2), true)
|
||||
@@ -3684,6 +3673,94 @@ const m = {
|
||||
ctx.strokeStyle = "rgba(255,0,110,0.06)"
|
||||
ctx.stroke();
|
||||
}
|
||||
// } else if (true) { //plasma sword slash
|
||||
// const plasmaSweepCycles = 30
|
||||
// m.plasmaSweep = 0
|
||||
// m.plasmaSlashDirection = m.flipLegs//Math.random() > 0.5 ? 1 : -1;
|
||||
// m.hold = function () {
|
||||
// if (m.isHolding) {
|
||||
// m.drawHold(m.holdingTarget);
|
||||
// m.holding();
|
||||
// m.throwBlock();
|
||||
// m.plasmaSweep = 0
|
||||
// // } else if (true) { //not hold but field button is pressed
|
||||
// } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
|
||||
// if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
|
||||
// m.grabPowerUp();
|
||||
// m.lookForPickUp();
|
||||
|
||||
// //graphics
|
||||
// if (m.plasmaSweep === 0) m.plasmaSlashDirection = m.flipLegs //Math.random() > 0.5 ? 1 : -1;
|
||||
// const angle = m.angle //+ 1 * (m.plasmaSweep - plasmaSweepCycles / 2) / plasmaSweepCycles * m.plasmaSlashDirection
|
||||
// const plasmaSweepCapped = Math.min(m.plasmaSweep, plasmaSweepCycles - 8) / plasmaSweepCycles
|
||||
// const range = 100 * plasmaSweepCapped
|
||||
// const arc = 1.3
|
||||
// const A = { x: m.pos.x + range * Math.cos(angle - arc), y: m.pos.y + range * Math.sin(angle - arc) }
|
||||
// const B = { x: m.pos.x + range * Math.cos(angle + arc), y: m.pos.y + range * Math.sin(angle + arc) }
|
||||
// const controlRange = 500 * plasmaSweepCapped
|
||||
// const AC = { x: m.pos.x + controlRange * Math.cos(angle - arc / 2), y: m.pos.y + controlRange * Math.sin(angle - arc / 2) }
|
||||
// const BC = { x: m.pos.x + controlRange * Math.cos(angle + arc / 2), y: m.pos.y + controlRange * Math.sin(angle + arc / 2) }
|
||||
// const innerControlRange = 300 * plasmaSweepCapped
|
||||
// const ACinner = { x: m.pos.x + innerControlRange * Math.cos(angle - arc / 2), y: m.pos.y + innerControlRange * Math.sin(angle - arc / 2) }
|
||||
// const BCinner = { x: m.pos.x + innerControlRange * Math.cos(angle + arc / 2), y: m.pos.y + innerControlRange * Math.sin(angle + arc / 2) }
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(A.x, A.y)
|
||||
// ctx.bezierCurveTo(AC.x, AC.y, BC.x, BC.y, B.x, B.y); //outer curve
|
||||
// ctx.bezierCurveTo(BCinner.x, BCinner.y, ACinner.x, ACinner.y, A.x, A.y); //inner curve
|
||||
// // ctx.strokeStyle = "#000"
|
||||
// // ctx.stroke();
|
||||
// ctx.fillStyle = "rgba(255,0,255,0.5)"
|
||||
// ctx.fill();
|
||||
|
||||
// //draw control points for graphics reference
|
||||
// ctx.lineWidth = '0.5'
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(A.x, A.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(B.x, B.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(AC.x, AC.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(BC.x, BC.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(ACinner.x, ACinner.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(BCinner.x, BCinner.y, 5, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
|
||||
// //mob collision detection
|
||||
// collideRange = 160
|
||||
// const collideCenter = {
|
||||
// x: m.pos.x + collideRange * Math.cos(angle),
|
||||
// y: m.pos.y + collideRange * Math.sin(angle)
|
||||
// }
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(collideCenter.x, collideCenter.y, 140, 0, 2 * Math.PI);
|
||||
// ctx.stroke();
|
||||
|
||||
// //push mob away and slow them?
|
||||
|
||||
|
||||
// //sweeping motion and cooldown
|
||||
// m.plasmaSweep++
|
||||
// if (m.plasmaSweep > plasmaSweepCycles) {
|
||||
// m.plasmaSweep = 0
|
||||
// if (m.fireCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 30
|
||||
// }
|
||||
// } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
|
||||
// m.pickUp();
|
||||
// m.plasmaSweep = 0
|
||||
// } else {
|
||||
// m.plasmaSweep = 0
|
||||
// m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
|
||||
// }
|
||||
// m.drawRegenEnergy("rgba(0, 0, 0, 0.2)")
|
||||
// }
|
||||
} else {
|
||||
m.hold = function () {
|
||||
if (m.isHolding) {
|
||||
@@ -4864,6 +4941,31 @@ const m = {
|
||||
// m.drawRegenEnergy()
|
||||
// },
|
||||
},
|
||||
{
|
||||
name: "grappling hook",
|
||||
// description: `use <strong class='color-f'>energy</strong> to pull yourself towards the <strong>map</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
|
||||
description: `use <strong class='color-f'>energy</strong> to fire a hook that attaches to <strong>map</strong>,<br>pulls player, <strong class='color-d'>damages</strong> mobs, and destroys <strong class='color-block'>blocks</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
|
||||
effect: () => {
|
||||
m.fieldFire = true;
|
||||
// m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping
|
||||
m.fieldMeterColor = "#333"
|
||||
m.eyeFillColor = m.fieldMeterColor
|
||||
m.fieldHarmReduction = 0.45; //55% reduction
|
||||
|
||||
m.hold = function () {
|
||||
if (input.field) {
|
||||
if (m.fieldCDcycle < m.cycle) {
|
||||
if (m.energy > 0.02) m.energy -= 0.02
|
||||
const where = { x: m.pos.x + 40 * Math.cos(m.angle), y: m.pos.y + 40 * Math.sin(m.angle) }
|
||||
b.grapple(where, m.angle)
|
||||
if (m.fieldCDcycle < m.cycle + 20) m.fieldCDcycle = m.cycle + 20
|
||||
}
|
||||
m.grabPowerUp();
|
||||
}
|
||||
m.drawRegenEnergy()
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
//************************************************************************************
|
||||
//************************************************************************************
|
||||
|
||||
@@ -914,54 +914,57 @@ const powerUps = {
|
||||
for (let i = 0; i < b.guns.length; i++) {
|
||||
if (!b.guns[i].have) options.push(i);
|
||||
}
|
||||
let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
|
||||
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
|
||||
function removeOption(index) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i] === index) {
|
||||
options.splice(i, 1) //remove a previous choice from option pool
|
||||
return
|
||||
// console.log(options.length)
|
||||
if (options.length > 0 || !tech.isSuperDeterminism) {
|
||||
let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
|
||||
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
|
||||
function removeOption(index) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i] === index) {
|
||||
options.splice(i, 1) //remove a previous choice from option pool
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//check for guns that were a choice last time and remove them
|
||||
for (let i = 0; i < b.guns.length; i++) {
|
||||
if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
|
||||
if (b.guns[i].isRecentlyShown) removeOption(i)
|
||||
}
|
||||
for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
|
||||
// if (options.length > 0) {
|
||||
let text = powerUps.buildColumns(totalChoices, "gun")
|
||||
for (let i = 0; i < totalChoices; i++) {
|
||||
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
||||
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choose})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[choose].name}</div> ${b.guns[choose].description}</div>`
|
||||
text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
|
||||
|
||||
b.guns[choose].isRecentlyShown = true
|
||||
removeOption(choose)
|
||||
if (options.length < 1) break
|
||||
}
|
||||
if (tech.isExtraBotOption) {
|
||||
const botTech = [] //make an array of bot options
|
||||
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
||||
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
|
||||
//check for guns that were a choice last time and remove them
|
||||
for (let i = 0; i < b.guns.length; i++) {
|
||||
if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
|
||||
if (b.guns[i].isRecentlyShown) removeOption(i)
|
||||
}
|
||||
if (botTech.length > 0) { //pick random bot tech
|
||||
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
||||
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
||||
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
||||
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
||||
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
||||
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
||||
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
||||
for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
|
||||
// if (options.length > 0) {
|
||||
let text = powerUps.buildColumns(totalChoices, "gun")
|
||||
for (let i = 0; i < totalChoices; i++) {
|
||||
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
||||
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choose})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[choose].name}</div> ${b.guns[choose].description}</div>`
|
||||
text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
|
||||
|
||||
b.guns[choose].isRecentlyShown = true
|
||||
removeOption(choose)
|
||||
if (options.length < 1) break
|
||||
}
|
||||
if (tech.isExtraBotOption) {
|
||||
const botTech = [] //make an array of bot options
|
||||
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
||||
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
|
||||
}
|
||||
if (botTech.length > 0) { //pick random bot tech
|
||||
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
||||
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
||||
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
||||
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
||||
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
||||
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
||||
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
||||
<div class="card-text">
|
||||
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${techCountText}</div>
|
||||
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
||||
}
|
||||
}
|
||||
if (tech.isOneGun && b.inventory.length > 0) text += `<div style = "color: #f24">replaces your current gun</div>`
|
||||
document.getElementById("choose-grid").innerHTML = text
|
||||
powerUps.showDraft();
|
||||
}
|
||||
if (tech.isOneGun && b.inventory.length > 0) text += `<div style = "color: #f24">replaces your current gun</div>`
|
||||
document.getElementById("choose-grid").innerHTML = text
|
||||
powerUps.showDraft();
|
||||
// }
|
||||
}
|
||||
},
|
||||
|
||||
180
js/tech.js
180
js/tech.js
@@ -232,7 +232,7 @@ const tech = {
|
||||
// }
|
||||
// }
|
||||
if (tech.isDivisor && b.activeGun && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77
|
||||
if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.78 : 1.88
|
||||
if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.75 : 2
|
||||
if (tech.isDilate) dmg *= 1.5 + 0.6 * Math.sin(m.cycle * 0.0075)
|
||||
if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
|
||||
if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage
|
||||
@@ -955,9 +955,9 @@ const tech = {
|
||||
frequency: 1,
|
||||
frequencyDefault: 1,
|
||||
allowed() {
|
||||
return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple
|
||||
return !m.isShipMode && !tech.isAlwaysFire
|
||||
},
|
||||
requires: "not ship mode, automatic, grappling hook",
|
||||
requires: "not ship mode, automatic",
|
||||
effect() {
|
||||
tech.isFireMoveLock = true;
|
||||
b.setFireCD();
|
||||
@@ -6682,10 +6682,10 @@ const tech = {
|
||||
},
|
||||
requires: "foam",
|
||||
effect() {
|
||||
tech.foamDamage += 0.011 * 0.43
|
||||
tech.foamDamage += 0.01 * 0.43
|
||||
},
|
||||
remove() {
|
||||
tech.foamDamage = 0.011;
|
||||
tech.foamDamage = 0.01;
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -6831,9 +6831,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple && !tech.isBoostReplaceAmmo
|
||||
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isBoostReplaceAmmo
|
||||
},
|
||||
requires: "harpoon, not UHMWPE, induction furnace, grappling hook, quasiparticles",
|
||||
requires: "harpoon, not UHMWPE, induction furnace, quasiparticles",
|
||||
ammoBonus: 9,
|
||||
effect() {
|
||||
tech.isRailGun = true;
|
||||
@@ -6852,52 +6852,52 @@ const tech = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "grappling hook",
|
||||
description: `<strong>harpoons</strong> attach to the <strong>map</strong> and pull you<br>your <strong>rope</strong> extends while holding <strong>fire</strong>`,
|
||||
isGunTech: true,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
|
||||
},
|
||||
requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism",
|
||||
effect() {
|
||||
tech.isGrapple = true;
|
||||
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
|
||||
}
|
||||
},
|
||||
remove() {
|
||||
if (tech.isGrapple) {
|
||||
tech.isGrapple = false;
|
||||
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "bulk modulus",
|
||||
description: `while <strong>grappling</strong> become <strong>invulnerable</strong><br>drain <strong class='color-f'>energy</strong>`,
|
||||
isGunTech: true,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy
|
||||
},
|
||||
requires: "grappling hook, not alternator",
|
||||
effect() {
|
||||
tech.isImmuneGrapple = true;
|
||||
},
|
||||
remove() {
|
||||
tech.isImmuneGrapple = false
|
||||
}
|
||||
},
|
||||
// {
|
||||
// name: "grappling hook",
|
||||
// description: `<strong>harpoons</strong> attach to the <strong>map</strong> and pull you<br>your <strong>rope</strong> extends while holding <strong>fire</strong>`,
|
||||
// isGunTech: true,
|
||||
// maxCount: 1,
|
||||
// count: 0,
|
||||
// frequency: 2,
|
||||
// frequencyDefault: 2,
|
||||
// allowed() {
|
||||
// return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
|
||||
// },
|
||||
// requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism",
|
||||
// effect() {
|
||||
// tech.isGrapple = true;
|
||||
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
// if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
|
||||
// }
|
||||
// },
|
||||
// remove() {
|
||||
// if (tech.isGrapple) {
|
||||
// tech.isGrapple = false;
|
||||
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
// if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// name: "bulk modulus",
|
||||
// description: `while <strong>grappling</strong> become <strong>invulnerable</strong><br>drain <strong class='color-f'>energy</strong>`,
|
||||
// isGunTech: true,
|
||||
// maxCount: 1,
|
||||
// count: 0,
|
||||
// frequency: 2,
|
||||
// frequencyDefault: 2,
|
||||
// allowed() {
|
||||
// return tech.haveGunCheck("harpoon") && !tech.isRailEnergy
|
||||
// },
|
||||
// requires: "not alternator",
|
||||
// effect() {
|
||||
// tech.isImmuneGrapple = true;
|
||||
// },
|
||||
// remove() {
|
||||
// tech.isImmuneGrapple = false
|
||||
// }
|
||||
// },
|
||||
{
|
||||
name: "alternator",
|
||||
description: "<strong>+90%</strong> <strong>harpoon</strong> <strong class='color-f'>energy</strong> efficiency",
|
||||
@@ -6907,9 +6907,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isImmuneGrapple
|
||||
return tech.haveGunCheck("harpoon")
|
||||
},
|
||||
requires: "harpoon, not bulk modulus",
|
||||
requires: "harpoon",
|
||||
effect() {
|
||||
tech.isRailEnergy = true;
|
||||
},
|
||||
@@ -6994,9 +6994,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun
|
||||
},
|
||||
requires: "harpoon, not grappling hook, railgun",
|
||||
requires: "harpoon, not railgun",
|
||||
effect() {
|
||||
tech.isFilament = true;
|
||||
},
|
||||
@@ -7013,9 +7013,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun
|
||||
},
|
||||
requires: "harpoon, not grappling hook, railgun",
|
||||
requires: "harpoon, not railgun",
|
||||
effect() {
|
||||
tech.isHarpoonPowerUp = true
|
||||
},
|
||||
@@ -7657,9 +7657,9 @@ const tech = {
|
||||
frequency: 3,
|
||||
frequencyDefault: 3,
|
||||
allowed() {
|
||||
return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3) && (build.isExperimentSelection || powerUps.research.count > 3)
|
||||
return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 3)
|
||||
},
|
||||
requires: "perfect diamagnetism, negative mass, pilot wave",
|
||||
requires: "perfect diamagnetism, negative mass, grappling hook, pilot wave",
|
||||
effect() {
|
||||
tech.isFieldHarmReduction = true
|
||||
for (let i = 0; i < 2; i++) {
|
||||
@@ -7706,9 +7706,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return (m.fieldMode === 8 || m.fieldMode === 3) && !tech.isCloakHealLastHit
|
||||
return m.fieldMode === 8 || m.fieldMode === 3
|
||||
},
|
||||
requires: "negative mass, pilot wave, not patch",
|
||||
requires: "negative mass, pilot wave",
|
||||
effect() {
|
||||
tech.lastHitDamage += 4;
|
||||
},
|
||||
@@ -7746,16 +7746,16 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "aerostat",
|
||||
description: `<strong>+88%</strong> <strong class='color-d'>damage</strong> while <strong>off</strong> the <strong>ground</strong><br><strong>-22%</strong> <strong class='color-d'>damage</strong> while <strong>on</strong> the <strong>ground</strong>`,
|
||||
description: `<strong>+100%</strong> <strong class='color-d'>damage</strong> while <strong>off</strong> the <strong>ground</strong><br><strong>-25%</strong> <strong class='color-d'>damage</strong> while <strong>on</strong> the <strong>ground</strong>`,
|
||||
isFieldTech: true,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return m.fieldMode === 3
|
||||
return m.fieldMode === 3 || m.fieldMode === 10
|
||||
},
|
||||
requires: "negative mass",
|
||||
requires: "negative mass, grappling hook",
|
||||
effect() {
|
||||
tech.isNoGroundDamage = true
|
||||
},
|
||||
@@ -7831,9 +7831,9 @@ const tech = {
|
||||
isBotTech: true,
|
||||
isNonRefundable: true,
|
||||
allowed() {
|
||||
return powerUps.research.count > 1 && (m.fieldMode === 4 || m.fieldMode === 8)
|
||||
return powerUps.research.count > 1 && (m.fieldMode === 4 || m.fieldMode === 10 || m.fieldMode === 8)
|
||||
},
|
||||
requires: "molecular assembler, pilot wave",
|
||||
requires: "molecular assembler, grappling hook, pilot wave",
|
||||
effect() {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
|
||||
@@ -7856,9 +7856,9 @@ const tech = {
|
||||
isBotTech: true,
|
||||
isNonRefundable: true,
|
||||
allowed() {
|
||||
return powerUps.research.count > 2 && (m.fieldMode === 4 || m.fieldMode === 8)
|
||||
return powerUps.research.count > 2 && (m.fieldMode === 4 || m.fieldMode === 10 || m.fieldMode === 8)
|
||||
},
|
||||
requires: "molecular assembler, pilot wave",
|
||||
requires: "molecular assembler, grappling hook, pilot wave",
|
||||
effect() {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
|
||||
@@ -8121,9 +8121,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 2 || m.fieldMode === 8)
|
||||
return (m.fieldMode === 10 || m.fieldMode === 4 || m.fieldMode === 8)
|
||||
},
|
||||
requires: "molecular assembler, plasma torch, perfect diamagnetism, pilot wave",
|
||||
requires: "plasma torch, grappling hook, pilot wave",
|
||||
effect() {
|
||||
tech.isHarmReduce = true
|
||||
},
|
||||
@@ -8479,9 +8479,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return m.fieldMode === 7 && !tech.lastHitDamage && !tech.isEnergyHealth
|
||||
return m.fieldMode === 7 && !tech.isEnergyHealth
|
||||
},
|
||||
requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy",
|
||||
requires: "metamaterial cloaking, not mass-energy",
|
||||
effect() {
|
||||
tech.isCloakHealLastHit = true;
|
||||
},
|
||||
@@ -8586,9 +8586,9 @@ const tech = {
|
||||
frequency: 3,
|
||||
frequencyDefault: 3,
|
||||
allowed() {
|
||||
return (m.fieldMode === 8 || m.fieldMode === 3 || m.fieldMode === 6 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2)
|
||||
return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 2)
|
||||
},
|
||||
requires: "wormhole, time dilation, negative mass, pilot wave",
|
||||
requires: "wormhole, time dilation, negative mass, pilot wave, grappling hook",
|
||||
effect() {
|
||||
tech.fieldDuplicate = 0.11
|
||||
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
|
||||
@@ -10982,6 +10982,30 @@ const tech = {
|
||||
},
|
||||
remove() { }
|
||||
},
|
||||
{
|
||||
name: "mobs!",
|
||||
descriptionFunction() {
|
||||
if (this.mobType === "") this.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]
|
||||
return `spawn 20 <strong>${this.mobType}</strong> mobs`
|
||||
},
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
isNonRefundable: true,
|
||||
isJunk: true,
|
||||
allowed() { return true },
|
||||
requires: "",
|
||||
mobType: "",
|
||||
effect() {
|
||||
if (this.mobType === "") this.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]
|
||||
for (let i = 0; i < 20; i++) {
|
||||
spawn[this.mobType](m.pos.x, m.pos.y - 700)
|
||||
}
|
||||
simulation.makeTextLog(`spawn<span class='color-symbol'>.</span>${this.mobType}<span class='color-symbol'>(</span>x<span class='color-symbol'>,</span>y<span class='color-symbol'>)</span>`)
|
||||
|
||||
},
|
||||
remove() { }
|
||||
},
|
||||
{
|
||||
name: "black hole cluster",
|
||||
description: `spawn <strong>30</strong> nearby <strong>black holes</strong>`,
|
||||
@@ -11718,8 +11742,8 @@ const tech = {
|
||||
isTimeCrystals: null,
|
||||
isGroundState: null,
|
||||
isRailGun: null,
|
||||
isGrapple: null,
|
||||
isImmuneGrapple: null,
|
||||
// isGrapple: null,
|
||||
// isImmuneGrapple: null,
|
||||
isDronesTravel: null,
|
||||
isTechDebt: null,
|
||||
isPlasmaBall: null,
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// https://ncase.me/sight-and-light/
|
||||
// redblobgames.com/articles/visibility
|
||||
// https://github.com/Silverwolf90/2d-visibility/tree/master/src
|
||||
// could apply to explosions, neutron bomb, player LOS
|
||||
|
||||
|
||||
const v = {
|
||||
points: [],
|
||||
populate() {
|
||||
v.points = [{
|
||||
x: -150,
|
||||
y: -950
|
||||
}, {
|
||||
x: 710,
|
||||
y: -950
|
||||
}, {
|
||||
x: 710,
|
||||
y: -940
|
||||
}, {
|
||||
x: 710,
|
||||
y: -710
|
||||
}, {
|
||||
x: 710,
|
||||
y: -700
|
||||
}, {
|
||||
x: -150,
|
||||
y: -700
|
||||
}]
|
||||
},
|
||||
draw() {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(v.points[0].x, v.points[0].y)
|
||||
for (let i = 0, len = v.points.length; i < len; i++) {
|
||||
ctx.lineTo(v.points[i].x, v.points[i].y)
|
||||
}
|
||||
// ctx.fillStyle = "#333"
|
||||
ctx.globalCompositeOperation = "destination-in";
|
||||
ctx.fill();
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
ctx.clip();
|
||||
}
|
||||
}
|
||||
v.populate();
|
||||
// console.log(v.points)
|
||||
Reference in New Issue
Block a user