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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -1460,324 +1460,369 @@ const b = {
// Composite.add(engine.world, bullet[me]); //add bullet to world // Composite.add(engine.world, bullet[me]); //add bullet to world
// }, // },
grapple(where, angle = m.angle, harpoonSize = 1) { grapple(where, angle = m.angle) {
const me = bullet.length; const me = bullet.length;
const returnRadius = 100 * Math.sqrt(harpoonSize) const returnRadius = 100
bullet[me] = Bodies.fromVertices(where.x, where.y, [{ bullet[me] = Bodies.fromVertices(where.x, where.y, [{
x: -50 * harpoonSize, x: -40,
y: 2 * harpoonSize, y: 2,
index: 0, index: 0,
isInternal: false isInternal: false
}, { }, {
x: -50 * harpoonSize, x: -40,
y: -2 * harpoonSize, y: -2,
index: 1, index: 1,
isInternal: false isInternal: false
}, { }, {
x: 45 * harpoonSize, x: 37,
y: -3 * harpoonSize, y: -2,
index: 2, index: 2,
isInternal: false isInternal: false
}, { }, {
x: 50 * harpoonSize, x: 40,
y: 0, y: -1,
index: 3, index: 3,
isInternal: false isInternal: false
}, { }, {
x: 45 * harpoonSize, x: 34,
y: 3 * harpoonSize, y: 5,
index: 4, index: 4,
isInternal: false isInternal: false
}], { }],
angle: angle,
friction: 1, // [{
frictionAir: 0.4, // x: -10,
thrustMag: 0.1, // y: 2,
dmg: 6, //damage done in addition to the damage from momentum // index: 0,
classType: "bullet", // isInternal: false
endCycle: simulation.cycle + 70, // }, {
collisionFilter: { // x: -10,
category: cat.bullet, // y: -2,
mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield, // index: 1,
}, // isInternal: false
minDmgSpeed: 4, // }, {
lookFrequency: Math.floor(7 + Math.random() * 3), // x: 35,
density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed // y: -3,
drain: tech.isRailEnergy ? 0.0006 : 0.006, // index: 2,
beforeDmg(who) { // isInternal: false
if (tech.isShieldPierce && who.isShielded) { //disable shields // }, {
who.isShielded = false // x: 37,
requestAnimationFrame(() => { // y: -2,
who.isShielded = true // index: 3,
}); // isInternal: false
} // }, {
if (tech.fragments) { // x: 40,
b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random())) // y: 0,
} // index: 4,
if (tech.isFoamBall) { // isInternal: false
for (let i = 0, len = 3 * this.mass; i < len; i++) { // }, {
const radius = 5 + 8 * Math.random() // x: 37,
const velocity = { // y: 2,
x: Math.max(0.5, 2 - radius * 0.1), // index: 5,
y: 0 // 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 { } else {
this.dropCaughtPowerUp() this.dropCaughtPowerUp()
} }
} else { },
this.dropCaughtPowerUp() draw() {
} const where = {
}, x: m.pos.x + 30 * Math.cos(m.angle),
draw() { y: m.pos.y + 30 * Math.sin(m.angle)
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}
const sub = Vector.sub(where, this.vertices[0])
const 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
}
}
} }
} const sub = Vector.sub(where, this.vertices[0])
}, const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
do() { ctx.strokeStyle = "#000" // "#0ce"
if (input.fire) { //&& !Matter.Query.collides(this, body).length ctx.lineWidth = 0.5
this.grabPowerUp() ctx.beginPath();
if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction ctx.moveTo(where.x, where.y);
this.endCycle = simulation.cycle + 60 ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
// m.fireCDcycle = m.cycle + 120 // cool down // ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
this.do = this.returnToPlayer ctx.stroke();
Matter.Body.setDensity(this, 0.0005); //reduce density on return //draw harpoon spikes
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) const spikeLength = 2
this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body ctx.beginPath();
} const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
} else { ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
//if not enough energy ctx.lineTo(spike1.x, spike1.y);
if (m.energy < 0.05) this.dropCaughtPowerUp() ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
// 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 { const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
//return to player 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.do = this.returnToPlayer
this.endCycle = simulation.cycle + 60 this.endCycle = simulation.cycle + 60
Matter.Body.setDensity(this, 0.0005); //reduce density on return 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) 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 this.collisionFilter.mask = 0//cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
//recoil on catching //recoil on pulling grapple back
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002)) const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
player.force.x += momentum.x player.force.x += momentum.x
player.force.y += momentum.y player.force.y += momentum.y
// } },
} returnToPlayer() {
//grappling hook if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
if (input.fire && Matter.Query.collides(this, map).length) { if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
Matter.Body.setPosition(this, Vector.add(this.position, { this.endCycle = 0;
x: 20 * Math.cos(this.angle), //recoil on catching grapple
y: 20 * Math.sin(this.angle) const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
})) player.force.x += momentum.x
if (Matter.Query.collides(this, map).length) { player.force.y += momentum.y
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
});
} else {
//need to scale the friction differently based on distance? if (m.energy > this.drain) m.energy -= this.drain
// if (dist > 500) { const sub = Vector.sub(this.position, m.pos)
const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), 200)) const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
player.force.x += pull.x const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
player.force.y += pull.y this.force.x -= returnForce.x
// } this.force.y -= returnForce.y
this.grabPowerUp()
if (dist > 500) { }
m.energy -= this.drain this.draw();
if (m.energy < 0) { },
this.endCycle = 0; destroyBlocks() {
if (m.cycle + 50 < m.fireCDcycle) m.fireCDcycle = m.cycle + 50 const blocks = Matter.Query.collides(this, body)
// refund ammo if (blocks.length && !blocks[0].bodyA.isNotHoldable) {
b.guns[9].ammo++; if (blocks[0].bodyA.mass > 2.5) this.retract()
simulation.updateGunHUD(); const block = blocks[0].bodyA.vertices
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun Composite.remove(engine.world, blocks[0].bodyA)
// if (b.guns[i].name === "harpoon") { body.splice(body.indexOf(blocks[0].bodyA), 1)
// break; //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();
} }
} }
} m.grabPowerUp();
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle); },
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle); do() {
this.draw() 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 Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
// grapple(where, angle = m.angle, harpoonSize = 1) { // grapple(where, angle = m.angle, harpoonSize = 1) {
@@ -3178,20 +3223,24 @@ const b = {
y: 100 * (Math.random() - 0.5) y: 100 * (Math.random() - 0.5)
}, },
beforeDmg(who) { beforeDmg(who) {
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) { if (who.isInvulnerable) {
setTimeout(() => { Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.1));
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 { } 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() { onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
@@ -3295,8 +3344,10 @@ const b = {
y: 100 * (Math.random() - 0.5) y: 100 * (Math.random() - 0.5)
}, },
beforeDmg(who) { beforeDmg(who) {
this.endCycle = 0; //bullet ends cycle after doing damage if (!who.isInvulnerable) {
if (this.isFreeze) mobs.statusSlow(who, 90) this.endCycle = 0; //bullet ends cycle after doing damage
if (this.isFreeze) mobs.statusSlow(who, 90)
}
}, },
onEnd() { onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
@@ -3304,7 +3355,7 @@ const b = {
if (m.health > m.maxHealth) m.health = m.maxHealth; if (m.health > m.maxHealth) m.health = m.maxHealth;
m.displayHealth(); m.displayHealth();
} }
console.log(this.dmg) // console.log(this.dmg)
}, },
do() { do() {
if (this.lockedOn && this.lockedOn.alive) { if (this.lockedOn && this.lockedOn.alive) {
@@ -3425,13 +3476,15 @@ const b = {
minDmgSpeed: 0, minDmgSpeed: 0,
lockedOn: null, lockedOn: null,
beforeDmg(who) { beforeDmg(who) {
if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) { if (!who.isInvulnerable) {
setTimeout(() => { if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
if (!who.alive) m.energy += tech.iceEnergy * 0.8 setTimeout(() => {
}, 10); 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) // if (tech.isHeavyWater) mobs.statusDoT(who, 0.15, 300)
}, },
onEnd() { }, onEnd() { },
@@ -3507,27 +3560,29 @@ const b = {
}, },
beforeDmg(who) { beforeDmg(who) {
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target 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; this.cd = simulation.cycle + this.delay;
if (tech.isSporeFreeze) mobs.statusSlow(who, 90) if (!who.isInvulnerable) {
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) { this.endCycle -= 130
setTimeout(() => { if (tech.isSporeFreeze) mobs.statusSlow(who, 90)
if (!who.alive) { if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
for (let i = 0; i < 2; i++) { //spawn 2 more setTimeout(() => {
const speed = 10 + 5 * Math.random() if (!who.alive) {
const angle = 2 * Math.PI * Math.random() for (let i = 0; i < 2; i++) { //spawn 2 more
b.flea(this.position, { const speed = 10 + 5 * Math.random()
x: speed * Math.cos(angle), const angle = 2 * Math.PI * Math.random()
y: speed * Math.sin(angle) b.flea(this.position, {
}) x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
})
}
} }
} this.endCycle = 0;
this.endCycle = 0; }, 1);
}, 1); }
setTimeout(() => {
this.dmg = 0
})
} }
setTimeout(() => {
this.dmg = 0
})
}, },
onEnd() { onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
@@ -3659,27 +3714,31 @@ const b = {
deathCycles: 110 + RADIUS * 5, deathCycles: 110 + RADIUS * 5,
isImproved: false, isImproved: false,
beforeDmg(who) { beforeDmg(who) {
if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) { if (who.isInvulnerable) {
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 //move away from target after hitting
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20)
Matter.Body.setVelocity(this, { x: unit.x, y: unit.y }); Matter.Body.setVelocity(this, { x: unit.x, y: unit.y });
this.lockedOn = null this.lockedOn = null
if (this.endCycle > simulation.cycle + this.deathCycles) { } else {
this.endCycle -= 60 if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) {
if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles 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) { bullet[me].beforeDmg = function (who) {
if (tech.oneSuperBall) mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) if (!who.isInvulnerable) {
if (tech.isFoamBall) { if (tech.oneSuperBall) mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds)
for (let i = 0, len = 5 * this.mass; i < len; i++) { if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random() for (let i = 0, len = 5 * this.mass; i < len; i++) {
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } const radius = 5 + 8 * Math.random()
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) 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
if (tech.isIncendiary) { this.endCycle = 0
b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end } else if (tech.isSuperBounce) {
this.endCycle = 0 const cycle = () => {
} else if (tech.isSuperBounce) { Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage
const cycle = () => { this.endCycle = simulation.cycle + Math.floor(300 + 90 * Math.random()); //reset to full duration of time
Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(this.velocity), 60)); //reset to high velocity
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 simulation.drawList.push({ //add dmg to draw queue
x: this.position.x, x: this.position.x,
y: this.position.y, y: this.position.y,
@@ -4223,17 +4293,8 @@ const b = {
time: 8 time: 8
}); });
} }
requestAnimationFrame(wait); requestAnimationFrame(cycle);
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);
} }
}; };
}, },
@@ -5394,7 +5455,7 @@ const b = {
cd: 0, cd: 0,
fireCount: 0, fireCount: 0,
fireLimit: 5 + 2 * tech.isFoamBotUpgrade, 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()), 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 range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), //how far from the player the bot will move
endCycle: Infinity, 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()}` 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, ammo: 0,
ammoPack: 24, ammoPack: 28,
have: false, have: false,
charge: 0, charge: 0,
isDischarge: false, isDischarge: false,
@@ -7842,9 +7903,9 @@ const b = {
if (tech.isRailGun) { if (tech.isRailGun) {
this.do = this.railDo this.do = this.railDo
this.fire = this.railFire this.fire = this.railFire
} else if (tech.isGrapple) { // } else if (tech.isGrapple) {
this.do = () => { } // this.do = () => { }
this.fire = this.grappleFire // this.fire = this.grappleFire
} else { } else {
this.do = () => { } this.do = () => { }
this.fire = this.harpoonFire this.fire = this.harpoonFire
@@ -8054,36 +8115,36 @@ const b = {
m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
this.charge += 0.00001 this.charge += 0.00001
}, },
grappleFire() { // grappleFire() {
const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (m.crouch ? 0.7 : 1) // const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (m.crouch ? 0.7 : 1)
const where = { // const where = {
x: m.pos.x + harpoonSize * 40 * Math.cos(m.angle), // x: m.pos.x + harpoonSize * 40 * Math.cos(m.angle),
y: m.pos.y + harpoonSize * 40 * Math.sin(m.angle) // y: m.pos.y + harpoonSize * 40 * Math.sin(m.angle)
} // }
const num = Math.min(this.ammo, tech.extraHarpoons + 1) // const num = Math.min(this.ammo, tech.extraHarpoons + 1)
if (!m.crouch && num > 1) { //multiple harpoons // if (!m.crouch && num > 1) { //multiple harpoons
const SPREAD = 0.06 // const SPREAD = 0.06
let angle = m.angle - SPREAD * num / 2; // let angle = m.angle - SPREAD * num / 2;
for (let i = 0; i < num; i++) { // for (let i = 0; i < num; i++) {
if (this.ammo > 0) { // if (this.ammo > 0) {
this.ammo-- // this.ammo--
b.grapple(where, angle, true, harpoonSize) // b.grapple(where, angle, true, harpoonSize)
angle += SPREAD // angle += SPREAD
} // }
} // }
this.ammo++ //make up for the ammo used up in fire() // this.ammo++ //make up for the ammo used up in fire()
simulation.updateGunHUD(); // simulation.updateGunHUD();
m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
// } else if (m.crouch) { // // } else if (m.crouch) {
// b.harpoon(where, null, m.angle, harpoonSize, false, 70) // // b.harpoon(where, null, m.angle, harpoonSize, false, 70)
} else { // } else {
if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1 // if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1
b.grapple(where, m.angle, harpoonSize) // b.grapple(where, m.angle, harpoonSize)
} // }
// m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down // // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down
m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05) // m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05)
}, // },
harpoonFire() { harpoonFire() {
const where = { const where = {
x: m.pos.x + 30 * Math.cos(m.angle), 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 // m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100 // tech.tech[297].frequency = 100
// m.couplingChange(10) // m.couplingChange(10)
// m.setField("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 // m.energy = 0
// simulation.molecularMode = 2 // simulation.molecularMode = 2
// m.damage(0.1); // 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("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 // b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("MACHO") }); // requestAnimationFrame(() => { tech.giveTech("MACHO") });
// for (let i = 0; i < 1; ++i) tech.giveTech("electrostatic induction") // 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 < 1; ++i) tech.giveTech("grappling hook")
// for (let i = 0; i < 10; ++i) tech.giveTech("quasiparticles") // 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("fine-structure constant")
// for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade") // for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade")
// requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") }); // 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, "research");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling"); // 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 < 4; ++i) spawn.hopMother(1900, -500)
// for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500) // for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500)
// for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500) // 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.slasher2(2000, -1150)
// spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color) // 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()) // 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>" // <br><span class='color-var'>m</span>.field.description = "<span class='color-text'>${m.fieldUpgrades[m.fieldMode].description}</span>"
// `, 1200); // `, 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, disableExit: false,
nextLevel() { nextLevel() {
if (!level.disableExit) { if (!level.disableExit) {
@@ -1874,6 +1878,7 @@ const level = {
//****************************************************************************************************************** //******************************************************************************************************************
//****************************************************************************************************************** //******************************************************************************************************************
template() { template() {
// level.announceMobTypes()
simulation.enableConstructMode() simulation.enableConstructMode()
level.setPosToSpawn(0, -50); //normal spawn level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 1500; level.exit.x = 1500;
@@ -2375,9 +2380,6 @@ const level = {
ctx.fillStyle = "rgba(68, 68, 68,0.95)" ctx.fillStyle = "rgba(68, 68, 68,0.95)"
ctx.fillRect(2030, 0, 150, 1800); ctx.fillRect(2030, 0, 150, 1800);
}; };
level.setPosToSpawn(460, -100); //normal spawn level.setPosToSpawn(460, -100); //normal spawn
// level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left // level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left
level.exit.x = 2800; level.exit.x = 2800;
@@ -3451,6 +3453,7 @@ const level = {
simulation.draw.drawMapPath = simulation.draw.drawMapSight simulation.draw.drawMapPath = simulation.draw.drawMapSight
}, },
reservoir() { reservoir() {
level.announceMobTypes()
level.exit.x = 1700; level.exit.x = 1700;
level.exit.y = -4510; level.exit.y = -4510;
spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25); 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 powerUps.addResearchToLevel() //needs to run after mobs are spawned
}, },
factory() { factory() {
level.announceMobTypes()
// simulation.enableConstructMode() //remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // simulation.enableConstructMode() //remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// level.difficultyIncrease(10 * 4) //30 is near max on hard //60 is near max on why // 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"); powerUps.spawn(5200, -1300, "ammo");
}, },
labs() { labs() {
level.announceMobTypes()
level.isProcedural = true //used in generating text for the level builder level.isProcedural = true //used in generating text for the level builder
level.defaultZoom = 1700 level.defaultZoom = 1700
simulation.zoomTransition(level.defaultZoom) simulation.zoomTransition(level.defaultZoom)
@@ -5347,6 +5352,7 @@ const level = {
powerUps.addResearchToLevel() //needs to run after mobs are spawned powerUps.addResearchToLevel() //needs to run after mobs are spawned
}, },
pavilion() { pavilion() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
const vanish = [] const vanish = []
level.exit.x = -850; level.exit.x = -850;
@@ -5499,6 +5505,7 @@ const level = {
} }
}, },
testChamber() { testChamber() {
level.announceMobTypes()
level.setPosToSpawn(0, -50); //lower start level.setPosToSpawn(0, -50); //lower start
level.exit.y = level.enter.y - 550; level.exit.y = level.enter.y - 550;
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
@@ -5757,6 +5764,7 @@ const level = {
}, },
lock() { lock() {
level.announceMobTypes()
level.setPosToSpawn(0, -65); //lower start level.setPosToSpawn(0, -65); //lower start
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.y = 2010; level.exit.y = 2010;
@@ -6006,6 +6014,7 @@ const level = {
powerUps.addResearchToLevel() //needs to run after mobs are spawned powerUps.addResearchToLevel() //needs to run after mobs are spawned
}, },
sewers() { sewers() {
level.announceMobTypes()
const button1 = level.button(6600, 2675) const button1 = level.button(6600, 2675)
// const hazard = level.hazard(4550, 2750, 4550, 150) // const hazard = level.hazard(4550, 2750, 4550, 150)
const hazard = level.hazard(simulation.isHorizontalFlipped ? -4550 - 4550 : 4550, 2750, 4550, 150) const hazard = level.hazard(simulation.isHorizontalFlipped ? -4550 - 4550 : 4550, 2750, 4550, 150)
@@ -6196,6 +6205,7 @@ const level = {
}, },
satellite() { satellite() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
const boost1 = level.boost(5825, 235, 1400) const boost1 = level.boost(5825, 235, 1400)
const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 } const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 }
@@ -6372,6 +6382,7 @@ const level = {
} }
}, },
rooftops() { rooftops() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
// level.fallPosition = { x: 5000, y:-4000} // level.fallPosition = { x: 5000, y:-4000}
const elevator = level.elevator(1450, -990, 235, 45, -2000) const elevator = level.elevator(1450, -990, 235, 45, -2000)
@@ -6560,6 +6571,7 @@ const level = {
} }
}, },
aerie() { aerie() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
const boost1 = level.boost(-425, 100, 1400) const boost1 = level.boost(-425, 100, 1400)
const boost2 = level.boost(5350, 275, 2850); const boost2 = level.boost(5350, 275, 2850);
@@ -6789,6 +6801,7 @@ const level = {
} }
}, },
skyscrapers() { skyscrapers() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
const boost1 = level.boost(475, 0, 1300) const boost1 = level.boost(475, 0, 1300)
const boost2 = level.boost(4450, 0, 1300); const boost2 = level.boost(4450, 0, 1300);
@@ -6927,6 +6940,7 @@ const level = {
} }
}, },
highrise() { highrise() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, { const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, {
up: 0.01, up: 0.01,
@@ -7212,6 +7226,7 @@ const level = {
} }
}, },
warehouse() { warehouse() {
level.announceMobTypes()
level.isEndlessFall = true; level.isEndlessFall = true;
level.custom = () => { level.custom = () => {
ctx.fillStyle = "#444" //light fixtures ctx.fillStyle = "#444" //light fixtures
@@ -7531,6 +7546,7 @@ const level = {
} }
}, },
office() { office() {
level.announceMobTypes()
let button, door let button, door
let isReverse = false let isReverse = false
if (Math.random() < 0.75) { //normal direction start in top left 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.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1 if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0165, 0.66) 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.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.1
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots() if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
@@ -2779,14 +2779,10 @@ const m = {
effect: () => { effect: () => {
m.fieldMeterColor = "#48f" //"#0c5" m.fieldMeterColor = "#48f" //"#0c5"
m.eyeFillColor = m.fieldMeterColor m.eyeFillColor = m.fieldMeterColor
m.fieldShieldingScale = 0; m.fieldShieldingScale = 0;
m.fieldBlockCD = 3; m.fieldBlockCD = 3;
m.grabPowerUpRange2 = 10000000 m.grabPowerUpRange2 = 10000000
m.fieldPosition = { m.fieldPosition = { x: m.pos.x, y: m.pos.y }
x: m.pos.x,
y: m.pos.y
}
m.fieldAngle = m.angle m.fieldAngle = m.angle
m.perfectPush = (isFree = false) => { m.perfectPush = (isFree = false) => {
if (m.fieldCDcycle < m.cycle) { if (m.fieldCDcycle < m.cycle) {
@@ -2794,10 +2790,7 @@ const m = {
if ( if (
Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) - mob[i].radius < m.fieldRange && Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) - mob[i].radius < m.fieldRange &&
!mob[i].isUnblockable && !mob[i].isUnblockable &&
Vector.dot({ Vector.dot({ x: Math.cos(m.fieldAngle), y: Math.sin(m.fieldAngle) }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold &&
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 Matter.Query.ray(map, mob[i].position, m.fieldPosition).length === 0
) { ) {
mob[i].locatePlayer(); mob[i].locatePlayer();
@@ -2816,11 +2809,7 @@ const m = {
} }
} }
if (tech.blockDmg) { //electricity if (tech.blockDmg) { //electricity
Matter.Body.setVelocity(mob[i], { Matter.Body.setVelocity(mob[i], { x: 0.5 * mob[i].velocity.x, y: 0.5 * mob[i].velocity.y });
x: 0.5 * mob[i].velocity.x,
y: 0.5 * mob[i].velocity.y
});
if (mob[i].isShielded) { if (mob[i].isShielded) {
for (let j = 0, len = mob.length; j < len; j++) { 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) 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.strokeStyle = "rgba(255,0,110,0.06)"
ctx.stroke(); 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 { } else {
m.hold = function () { m.hold = function () {
if (m.isHolding) { if (m.isHolding) {
@@ -4864,6 +4941,31 @@ const m = {
// m.drawRegenEnergy() // 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++) { for (let i = 0; i < b.guns.length; i++) {
if (!b.guns[i].have) options.push(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))) // console.log(options.length)
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay if (options.length > 0 || !tech.isSuperDeterminism) {
function removeOption(index) { let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
for (let i = 0; i < options.length; i++) { if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
if (options[i] === index) { function removeOption(index) {
options.splice(i, 1) //remove a previous choice from option pool for (let i = 0; i < options.length; i++) {
return 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
//check for guns that were a choice last time and remove them for (let i = 0; i < b.guns.length; i++) {
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 (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 (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)
} }
if (botTech.length > 0) { //pick random bot tech for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
// const choose = botTech[Math.floor(Math.random() * botTech.length)]; // if (options.length > 0) {
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; let text = powerUps.buildColumns(totalChoices, "gun")
// 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>` for (let i = 0; i < totalChoices; i++) {
const choose = botTech[Math.floor(Math.random() * botTech.length)]; const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; // 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>`
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
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="card-text">
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> &nbsp; ${tech.tech[choose].name} ${techCountText}</div> <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>` ${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.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.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 (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage
@@ -955,9 +955,9 @@ const tech = {
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed() { 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() { effect() {
tech.isFireMoveLock = true; tech.isFireMoveLock = true;
b.setFireCD(); b.setFireCD();
@@ -6682,10 +6682,10 @@ const tech = {
}, },
requires: "foam", requires: "foam",
effect() { effect() {
tech.foamDamage += 0.011 * 0.43 tech.foamDamage += 0.01 * 0.43
}, },
remove() { remove() {
tech.foamDamage = 0.011; tech.foamDamage = 0.01;
} }
}, },
{ {
@@ -6831,9 +6831,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { 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, ammoBonus: 9,
effect() { effect() {
tech.isRailGun = true; tech.isRailGun = true;
@@ -6852,52 +6852,52 @@ const tech = {
} }
} }
}, },
{ // {
name: "grappling hook", // 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>`, // 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, // isGunTech: true,
maxCount: 1, // maxCount: 1,
count: 0, // count: 0,
frequency: 2, // frequency: 2,
frequencyDefault: 2, // frequencyDefault: 2,
allowed() { // allowed() {
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock // return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
}, // },
requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism", // requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism",
effect() { // effect() {
tech.isGrapple = true; // tech.isGrapple = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod() // if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
} // }
}, // },
remove() { // remove() {
if (tech.isGrapple) { // if (tech.isGrapple) {
tech.isGrapple = false; // tech.isGrapple = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod() // if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
} // }
} // }
} // }
}, // },
{ // {
name: "bulk modulus", // name: "bulk modulus",
description: `while <strong>grappling</strong> become <strong>invulnerable</strong><br>drain <strong class='color-f'>energy</strong>`, // description: `while <strong>grappling</strong> become <strong>invulnerable</strong><br>drain <strong class='color-f'>energy</strong>`,
isGunTech: true, // isGunTech: true,
maxCount: 1, // maxCount: 1,
count: 0, // count: 0,
frequency: 2, // frequency: 2,
frequencyDefault: 2, // frequencyDefault: 2,
allowed() { // allowed() {
return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy // return tech.haveGunCheck("harpoon") && !tech.isRailEnergy
}, // },
requires: "grappling hook, not alternator", // requires: "not alternator",
effect() { // effect() {
tech.isImmuneGrapple = true; // tech.isImmuneGrapple = true;
}, // },
remove() { // remove() {
tech.isImmuneGrapple = false // tech.isImmuneGrapple = false
} // }
}, // },
{ {
name: "alternator", name: "alternator",
description: "<strong>+90%</strong> <strong>harpoon</strong> <strong class='color-f'>energy</strong> efficiency", description: "<strong>+90%</strong> <strong>harpoon</strong> <strong class='color-f'>energy</strong> efficiency",
@@ -6907,9 +6907,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("harpoon") && !tech.isImmuneGrapple return tech.haveGunCheck("harpoon")
}, },
requires: "harpoon, not bulk modulus", requires: "harpoon",
effect() { effect() {
tech.isRailEnergy = true; tech.isRailEnergy = true;
}, },
@@ -6994,9 +6994,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { 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() { effect() {
tech.isFilament = true; tech.isFilament = true;
}, },
@@ -7013,9 +7013,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { 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() { effect() {
tech.isHarpoonPowerUp = true tech.isHarpoonPowerUp = true
}, },
@@ -7657,9 +7657,9 @@ const tech = {
frequency: 3, frequency: 3,
frequencyDefault: 3, frequencyDefault: 3,
allowed() { 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() { effect() {
tech.isFieldHarmReduction = true tech.isFieldHarmReduction = true
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
@@ -7706,9 +7706,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { 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() { effect() {
tech.lastHitDamage += 4; tech.lastHitDamage += 4;
}, },
@@ -7746,16 +7746,16 @@ const tech = {
}, },
{ {
name: "aerostat", 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, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return m.fieldMode === 3 return m.fieldMode === 3 || m.fieldMode === 10
}, },
requires: "negative mass", requires: "negative mass, grappling hook",
effect() { effect() {
tech.isNoGroundDamage = true tech.isNoGroundDamage = true
}, },
@@ -7831,9 +7831,9 @@ const tech = {
isBotTech: true, isBotTech: true,
isNonRefundable: true, isNonRefundable: true,
allowed() { 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() { effect() {
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
@@ -7856,9 +7856,9 @@ const tech = {
isBotTech: true, isBotTech: true,
isNonRefundable: true, isNonRefundable: true,
allowed() { 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() { effect() {
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
@@ -8121,9 +8121,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { 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() { effect() {
tech.isHarmReduce = true tech.isHarmReduce = true
}, },
@@ -8479,9 +8479,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { 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() { effect() {
tech.isCloakHealLastHit = true; tech.isCloakHealLastHit = true;
}, },
@@ -8586,9 +8586,9 @@ const tech = {
frequency: 3, frequency: 3,
frequencyDefault: 3, frequencyDefault: 3,
allowed() { 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() { effect() {
tech.fieldDuplicate = 0.11 tech.fieldDuplicate = 0.11
powerUps.setPowerUpMode(); //needed after adjusting duplication chance powerUps.setPowerUpMode(); //needed after adjusting duplication chance
@@ -10982,6 +10982,30 @@ const tech = {
}, },
remove() { } 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", name: "black hole cluster",
description: `spawn <strong>30</strong> nearby <strong>black holes</strong>`, description: `spawn <strong>30</strong> nearby <strong>black holes</strong>`,
@@ -11718,8 +11742,8 @@ const tech = {
isTimeCrystals: null, isTimeCrystals: null,
isGroundState: null, isGroundState: null,
isRailGun: null, isRailGun: null,
isGrapple: null, // isGrapple: null,
isImmuneGrapple: null, // isImmuneGrapple: null,
isDronesTravel: null, isDronesTravel: null,
isTechDebt: null, isTechDebt: null,
isPlasmaBall: 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)

View File

@@ -1,20 +1,58 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
new community map - LaunchSite by Des Boot grappling hook is now a field (work in progress)
reworked physics to allow faster speeds, but more control
improved rate of power up grabbing
more player control to hook retraction rate
changed hook shape and field image graphics
grappling hook field coupling, more tech, bug fixes, and general polish to be added soon
added a short color animation after grabbing basic power ups aerostat - 88->100% damage in air 22-> 25% damage on ground
foam damage reduced 10%, ammo increased about 10%
after hitting an invulnerable mob (drones,spores,worms,iceIX,fleas) don't die or lose cycles
added JUNK tech: mobs! - summon 20 random mobs
added announcement of mob names in console at start of new level
reduced overall damage done to player by ~6% bug fixes
commodities exchange spawns 5-10 -> 6-12 power ups on cancel
residual dipolar coupling spawns 5 -> 6 coupling power ups
bots maintain relative position to player after the no camera tracking teleport
for portals and falling off level
the once every 7 seconds stuck check now also check to see if you stay stuck for 3 seconds before resetting you.
*********************************************************** TODO ***************************************************** *********************************************************** TODO *****************************************************
grappling hook is a field
check for places that the player could get into but not out of
maybe grapple could grab more then 1 power up?
grapple slices blocks
cut large blocks into 2,3
use dead mob code for mobs > 5 sides
write code to cut large blocks in half and remove one half
need several field tech
new field tech ideas
increase hook damage
hook damage aura
hook's line does damage
make several auto targeting harpoons after taking damage
how to make them not drain energy
generate ___ after destroying blocks
energy, drones, iceIX, explosion, nails, junk bots?
coupling effect: defense?, bonus from ammo power ups, fire rate
tech - killing a mob heals for the last damage you took
disable cloaking heal? maybe you don't need to disable, just don't heal twice
heal for 50%?
heal from mob damage or from kills?
make phonon the default wave gun type and make a tech to switch to the normal wave beam
nerf phonon, buff wave
sword slash for plasma torch (giving up on this for now, had trouble making graphics look good)
activates when mouse is close to player
gradual activation
sharp cut off
use length of torch as cut off length
make it look like hollow knight slash
what about upgrades to extruder,plasma ball
give them their own version of a slash?
make a tech that buffs the slash, but it disables extruder,plasma ball
more (all) bosses need to be made of parts more (all) bosses need to be made of parts
good examples: spiderBoss, dragonFlyBoss, beetleBoss good examples: spiderBoss, dragonFlyBoss, beetleBoss
methods: methods: