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:
landgreen
2023-11-18 17:49:01 -08:00
parent 3844d00ef6
commit e9d226259e
10 changed files with 800 additions and 600 deletions

View File

@@ -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),

View File

@@ -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

View File

@@ -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()
}
}
},
],
//************************************************************************************
//************************************************************************************

View File

@@ -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> &nbsp; ${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> &nbsp; ${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> &nbsp; ${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> &nbsp; ${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> &nbsp; ${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();
// }
}
},

View File

@@ -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,

View File

@@ -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)