chain reaction

tech: chain reaction now requires vacuum bomb, but it increases grenade radius and damage 33%
  (and makes blocks explode)

needle gun fires with more regular timing
needles despawn 1.5s faster, for performance reasons
intro level power ups are relocated
tech: decomposers renamed necrophage
if mobs are one shotted before they see you, they no longer alert nearby mobs
clicking on a mob in testing will log that mob in console
This commit is contained in:
landgreen
2021-08-03 06:46:19 -07:00
parent f9dc66797b
commit d8e891a681
11 changed files with 160 additions and 117 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -774,7 +774,7 @@ const b = {
const me = bullet.length; const me = bullet.length;
bullet[me] = Bodies.circle(where.x, where.y, 15, b.fireAttributes(angle, false)); bullet[me] = Bodies.circle(where.x, where.y, 15, b.fireAttributes(angle, false));
Matter.Body.setDensity(bullet[me], 0.0005); Matter.Body.setDensity(bullet[me], 0.0005);
bullet[me].explodeRad = 350 + Math.floor(Math.random() * 50);; bullet[me].explodeRad = 333 + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100
bullet[me].onEnd = function() { bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 4) if (tech.fragments) b.targetedNail(this.position, tech.fragments * 4)
@@ -850,7 +850,7 @@ const b = {
const me = bullet.length; const me = bullet.length;
bullet[me] = Bodies.circle(where.x, where.y, 20, b.fireAttributes(angle, false)); bullet[me] = Bodies.circle(where.x, where.y, 20, b.fireAttributes(angle, false));
Matter.Body.setDensity(bullet[me], 0.0003); Matter.Body.setDensity(bullet[me], 0.0003);
bullet[me].explodeRad = 325 + Math.floor(Math.random() * 50);; bullet[me].explodeRad = 333 + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100
bullet[me].onEnd = function() { bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 6) if (tech.fragments) b.targetedNail(this.position, tech.fragments * 6)
@@ -1260,7 +1260,7 @@ const b = {
Matter.Body.setPosition(this, Vector.add(this.position, q[i].velocity)) //move with the medium Matter.Body.setPosition(this, Vector.add(this.position, q[i].velocity)) //move with the medium
let dmg = this.dmg / Math.min(10, q[i].mass) let dmg = this.dmg / Math.min(10, q[i].mass)
q[i].damage(dmg); q[i].damage(dmg);
q[i].foundPlayer(); if (q[i].alive) q[i].foundPlayer();
//removed to improve performance //removed to improve performance
// simulation.drawList.push({ //add dmg to draw queue // simulation.drawList.push({ //add dmg to draw queue
// x: this.position.x, // x: this.position.x,
@@ -2764,7 +2764,7 @@ const b = {
bullet[me] = Bodies.rectangle(m.pos.x + 40 * Math.cos(m.angle), m.pos.y + 40 * Math.sin(m.angle), 75, 0.75, b.fireAttributes(angle)); bullet[me] = Bodies.rectangle(m.pos.x + 40 * Math.cos(m.angle), m.pos.y + 40 * Math.sin(m.angle), 75, 0.75, b.fireAttributes(angle));
bullet[me].collisionFilter.mask = tech.isNeedleShieldPierce ? cat.body : cat.body | cat.mobShield bullet[me].collisionFilter.mask = tech.isNeedleShieldPierce ? cat.body : cat.body | cat.mobShield
Matter.Body.setDensity(bullet[me], 0.00001); //0.001 is normal Matter.Body.setDensity(bullet[me], 0.00001); //0.001 is normal
bullet[me].endCycle = simulation.cycle + 180; bullet[me].endCycle = simulation.cycle + 100;
bullet[me].immuneList = [] bullet[me].immuneList = []
bullet[me].do = function() { bullet[me].do = function() {
const whom = Matter.Query.collides(this, mob) const whom = Matter.Query.collides(this, mob)
@@ -2784,7 +2784,6 @@ const b = {
b.explosion(this.position, 220 + 50 * Math.random()); //makes bullet do explosive damage at end b.explosion(this.position, 220 + 50 * Math.random()); //makes bullet do explosive damage at end
} }
this.immuneList.push(who.id) //remember that this needle has hit this mob once already this.immuneList.push(who.id) //remember that this needle has hit this mob once already
who.foundPlayer();
let dmg = b.dmgScale * 6 let dmg = b.dmgScale * 6
if (tech.isNailRadiation) { if (tech.isNailRadiation) {
mobs.statusDoT(who, tech.isFastRadiation ? 12 : 3, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles mobs.statusDoT(who, tech.isFastRadiation ? 12 : 3, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles
@@ -2792,6 +2791,7 @@ const b = {
} }
if (tech.isCrit && who.isStunned) dmg *= 4 if (tech.isCrit && who.isStunned) dmg *= 4
who.damage(dmg, tech.isNeedleShieldPierce); who.damage(dmg, tech.isNeedleShieldPierce);
if (who.alive) who.foundPlayer();
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,
@@ -3008,7 +3008,7 @@ const b = {
// const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 2.5 : 1) // const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 2.5 : 1)
const dmg = 0.5 * b.dmgScale const dmg = 0.5 * b.dmgScale
q[i].damage(dmg); q[i].damage(dmg);
q[i].foundPlayer(); if (q[i].alive) q[i].foundPlayer();
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,
@@ -3606,7 +3606,7 @@ const b = {
mobs.statusStun(q[i], 180) mobs.statusStun(q[i], 180)
const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 3.5 : 1) * (tech.isCrit ? 4 : 1) const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 3.5 : 1) * (tech.isCrit ? 4 : 1)
q[i].damage(dmg); q[i].damage(dmg);
q[i].foundPlayer(); if (q[i].alive) q[i].foundPlayer();
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,
@@ -3686,24 +3686,38 @@ const b = {
}, },
fireNeedles() { fireNeedles() {
if (m.crouch) { if (m.crouch) {
m.fireCDcycle = m.cycle + 45 * b.fireCDscale; // cool down m.fireCDcycle = m.cycle + 38 * b.fireCDscale; // cool down
b.needle() b.needle()
for (let i = 1; i < 4; i++) { //4 total needles
setTimeout(() => { if (!simulation.paused) b.needle() }, 60 * i); function cycle() {
if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else {
count++
if (count % 2) b.needle()
if (count < 5 && m.alive) requestAnimationFrame(cycle);
}
} }
let count = -1
requestAnimationFrame(cycle);
} else { } else {
m.fireCDcycle = m.cycle + 25 * b.fireCDscale; // cool down m.fireCDcycle = m.cycle + 28 * b.fireCDscale; // cool down
b.needle() b.needle()
for (let i = 1; i < 3; i++) { //3 total needles
setTimeout(() => { if (!simulation.paused) b.needle() }, 60 * i); function cycle() {
if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else {
count++
if (count % 2) b.needle()
if (count < 3 && m.alive) requestAnimationFrame(cycle);
}
} }
let count = -1
requestAnimationFrame(cycle);
} }
}, },
fireRivets() { fireRivets() {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCDscale); // cool down m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCDscale); // cool down
const me = bullet.length; const me = bullet.length;
const size = tech.rivetSize * 7.5 const size = tech.rivetSize * 8
bullet[me] = Bodies.rectangle(m.pos.x + 35 * Math.cos(m.angle), m.pos.y + 35 * Math.sin(m.angle), 5 * size, size, b.fireAttributes(m.angle)); bullet[me] = Bodies.rectangle(m.pos.x + 35 * Math.cos(m.angle), m.pos.y + 35 * Math.sin(m.angle), 5 * size, size, b.fireAttributes(m.angle));
bullet[me].dmg = tech.isNailRadiation ? 0 : 2.75 bullet[me].dmg = tech.isNailRadiation ? 0 : 2.75
Matter.Body.setDensity(bullet[me], 0.002); Matter.Body.setDensity(bullet[me], 0.002);
@@ -3958,7 +3972,7 @@ const b = {
b.foam(where, { x: SPEED * Math.cos(angle), y: SPEED * Math.sin(angle) }, 5 + 8 * Math.random()) b.foam(where, { x: SPEED * Math.cos(angle), y: SPEED * Math.sin(angle) }, 5 + 8 * Math.random())
} }
} else if (tech.isNeedleShot) { } else if (tech.isNeedleShot) {
const number = 12 * (tech.isShotgunReversed ? 1.6 : 1) const number = 11 * (tech.isShotgunReversed ? 1.6 : 1)
const spread = (m.crouch ? 0.03 : 0.05) const spread = (m.crouch ? 0.03 : 0.05)
let angle = m.angle - (number - 1) * spread * 0.5 let angle = m.angle - (number - 1) * spread * 0.5
for (let i = 0; i < number; i++) { for (let i = 0; i < number; i++) {
@@ -4351,7 +4365,7 @@ const b = {
for (let i = 0; i < q.length; i++) { for (let i = 0; i < q.length; i++) {
let dmg = this.dmg // / Math.min(10, q[i].mass) let dmg = this.dmg // / Math.min(10, q[i].mass)
q[i].damage(dmg); q[i].damage(dmg);
q[i].foundPlayer(); if (q[i].alive) q[i].foundPlayer();
Matter.Body.setVelocity(q[i], Vector.mult(q[i].velocity, 0.9)) Matter.Body.setVelocity(q[i], Vector.mult(q[i].velocity, 0.9))
this.endCycle = 0; //bullet ends cycle after doing damage this.endCycle = 0; //bullet ends cycle after doing damage
@@ -4417,7 +4431,7 @@ const b = {
name: "missiles", name: "missiles",
description: "launch <strong>homing</strong> missiles that <strong class='color-e'>explode</strong><br>crouch to <strong>rapidly</strong> launch smaller missiles", description: "launch <strong>homing</strong> missiles that <strong class='color-e'>explode</strong><br>crouch to <strong>rapidly</strong> launch smaller missiles",
ammo: 0, ammo: 0,
ammoPack: 3.5, ammoPack: 4,
have: false, have: false,
fireCycle: 0, fireCycle: 0,
ammoLoaded: 0, ammoLoaded: 0,

View File

@@ -177,8 +177,8 @@ function collisionChecks(event) {
obj.beforeDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here obj.beforeDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here
let dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity))) let dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)))
if (tech.isCrit && mob[k].isStunned) dmg *= 4 if (tech.isCrit && mob[k].isStunned) dmg *= 4
mob[k].foundPlayer();
mob[k].damage(dmg); mob[k].damage(dmg);
if (mob[k].alive) mob[k].foundPlayer();
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x, x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y, y: pairs[i].activeContacts[0].vertex.y,
@@ -207,7 +207,7 @@ function collisionChecks(event) {
const stunTime = dmg / Math.sqrt(obj.mass) const stunTime = dmg / Math.sqrt(obj.mass)
if (stunTime > 0.5) mobs.statusStun(mob[k], 60 + 60 * Math.sqrt(stunTime)) if (stunTime > 0.5) mobs.statusStun(mob[k], 60 + 60 * Math.sqrt(stunTime))
if (mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer(); if (mob[k].alive && mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer();
if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) { if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) {
obj.hasFragmented = true; obj.hasFragmented = true;
b.targetedNail(obj.position, tech.fragments * 4) b.targetedNail(obj.position, tech.fragments * 4)

View File

@@ -494,8 +494,10 @@ const build = {
count = 0; count = 0;
for (let i = 0; i < tech.tech.length; i++) { for (let i = 0; i < tech.tech.length; i++) {
for (let j = 0; j < tech.tech[i].count; j++) { for (let j = 0; j < tech.tech[i].count; j++) {
url += `&tech${count}=${encodeURIComponent(tech.tech[i].name.trim())}` if (!tech.tech[i].isLore && !tech.tech[i].isJunk && !tech.tech[i].isNonRefundable && !tech.tech[i].isExperimentHide) {
count++ url += `&tech${count}=${encodeURIComponent(tech.tech[i].name.trim())}`
count++
}
} }
} }
url += `&field=${encodeURIComponent(m.fieldUpgrades[m.fieldMode].name.trim())}` url += `&field=${encodeURIComponent(m.fieldUpgrades[m.fieldMode].name.trim())}`

View File

@@ -11,13 +11,14 @@ const level = {
levels: [], levels: [],
start() { start() {
if (level.levelsCleared === 0) { //this code only runs on the first level if (level.levelsCleared === 0) { //this code only runs on the first level
// localSettings.levelsClearedLastGame = 10
// simulation.enableConstructMode() //used to build maps in testing mode // simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// tech.isFieldFree = true // tech.isFieldFree = true
// m.setField("perfect diamagnetism") // m.setField("time dilation")
// b.giveGuns("shotgun") // b.giveGuns("nail gun")
// tech.giveTech("Noether violation") // tech.giveTech("needle gun")
// b.giveGuns("wave beam") // b.giveGuns("wave beam")
// tech.giveTech("Lenz's law") // tech.giveTech("Lenz's law")
// for (let i = 0; i < 3; i++) tech.giveTech("packet length") // for (let i = 0; i < 3; i++) tech.giveTech("packet length")
@@ -2105,6 +2106,7 @@ const level = {
} }
// const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)") // const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)")
level.isHazardRise = false //this is set to true to make the slime rise up
const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004, "hsla(160, 100%, 35%,0.75)") const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004, "hsla(160, 100%, 35%,0.75)")
hazardSlime.height -= 950 hazardSlime.height -= 950
hazardSlime.min.y += 950 hazardSlime.min.y += 950
@@ -2454,6 +2456,39 @@ const level = {
} }
}, },
intro() { intro() {
if (level.levelsCleared === 0) { //if this is the 1st level of the game
// powerUps.spawn(2500, -50, "research", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false);
powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125);
if (localSettings.levelsClearedLastGame < 3) {
if (!simulation.isCheating && !m.isShipMode) {
spawn.wireFoot();
spawn.wireFootLeft();
spawn.wireKnee();
spawn.wireKneeLeft();
spawn.wireHead();
// for (let i = 0; i < 3; i++) powerUps.spawn(2095, -1220 - 50 * i, "tech", false); //unavailable tech spawns
// spawn.mapRect(2000, -1025, 200, 25);
}
} else {
simulation.trails()
//bonus power ups for clearing runs in the last game
if (!simulation.isCheating && localSettings.levelsClearedLastGame > 1) {
for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(2095 + 2 * Math.random(), -1270 - 50 * i, "tech", false); //spawn a tech for levels cleared in last game
simulation.makeTextLog(`for (let i <span class='color-symbol'>=</span> 0; i <span class='color-symbol'><</span> localSettings.levelsClearedLastGame <span class='color-symbol'>/</span> 3; i<span class='color-symbol'>++</span>)`);
simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") <em>//simulation superposition</em>}`);
localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
}
} else {
for (let i = 0; i < 60; i++) {
setTimeout(() => { spawn.sneaker(2100, -1500 - 50 * i); }, 2000 + 500 * i);
}
}
level.custom = () => { level.custom = () => {
//draw binary number //draw binary number
const binary = (localSettings.runCount >>> 0).toString(2) const binary = (localSettings.runCount >>> 0).toString(2)
@@ -2611,6 +2646,11 @@ const level = {
//exit room glow //exit room glow
ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillStyle = "rgba(0,255,255,0.05)"
ctx.fillRect(2600, -600, 400, 300) ctx.fillRect(2600, -600, 400, 300)
//draw shade for ceiling tech
ctx.fillStyle = "rgba(68, 68, 68,0.95)"
ctx.fillRect(2030, -2800, 150, 1800);
ctx.fillStyle = "rgba(68, 68, 68,0.95)"
ctx.fillRect(2030, 0, 150, 1800);
}; };
level.setPosToSpawn(460, -100); //normal spawn level.setPosToSpawn(460, -100); //normal spawn
@@ -2623,10 +2663,26 @@ const level = {
simulation.zoomTransition(level.defaultZoom, 1) simulation.zoomTransition(level.defaultZoom, 1)
document.body.style.backgroundColor = "#e1e1e1"; document.body.style.backgroundColor = "#e1e1e1";
spawn.mapRect(-250, 0, 3600, 1800); //ground
spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
spawn.mapRect(3000, -2800, 2600, 4600); //right wall spawn.mapRect(3000, -2800, 2600, 4600); //right wall
spawn.mapRect(-250, -2800, 3600, 1800); //roof
// spawn.mapRect(-250, 0, 3600, 1800); //ground
spawn.mapRect(-250, 0, 2300, 1800); //split roof
spawn.mapRect(2150, 0, 1200, 1800); //split roof
spawn.mapRect(2025, -3, 25, 15); //lip on power up chamber
spawn.mapRect(2150, -3, 25, 15); //lip on power up chamber
spawn.mapRect(2025, 0, 150, 50);
// spawn.mapRect(-250, -2800, 3600, 1800); //roof
spawn.mapRect(-250, -2800, 2300, 1800); //split roof
map[map.length - 1].friction = 0
map[map.length - 1].frictionStatic = 0
spawn.mapRect(2150, -2800, 1200, 1800); //split roof
map[map.length - 1].friction = 0
map[map.length - 1].frictionStatic = 0
spawn.mapRect(2025, -1010, 25, 13); //lip on power up chamber
spawn.mapRect(2150, -1010, 25, 13); //lip on power up chamber
spawn.mapRect(2600, -300, 500, 500); //exit shelf spawn.mapRect(2600, -300, 500, 500); //exit shelf
spawn.mapRect(2600, -1200, 500, 600); //exit roof spawn.mapRect(2600, -1200, 500, 600); //exit roof
spawn.mapRect(-95, -1100, 80, 110); //wire source spawn.mapRect(-95, -1100, 80, 110); //wire source
@@ -2635,25 +2691,6 @@ const level = {
spawn.bodyRect(2425, -120, 70, 50); spawn.bodyRect(2425, -120, 70, 50);
spawn.bodyRect(2400, -100, 100, 60); spawn.bodyRect(2400, -100, 100, 60);
spawn.bodyRect(2500, -150, 100, 150); //exit step spawn.bodyRect(2500, -150, 100, 150); //exit step
// localSettings.levelsClearedLastGame = 20
if (level.levelsCleared === 0) {
// powerUps.spawn(2500, -50, "research", false);
powerUps.spawn(1900, -50, "heal", false);
powerUps.spawn(2050, -50, "heal", false);
if (localSettings.levelsClearedLastGame < 6) {
if (!simulation.isCheating && !m.isShipMode) {
spawn.wireFoot();
spawn.wireFootLeft();
spawn.wireKnee();
spawn.wireKneeLeft();
spawn.wireHead();
}
} else {
simulation.trails()
}
}
powerUps.spawnStartingPowerUps(2300, -50);
}, },
testChamber() { testChamber() {
level.setPosToSpawn(0, -50); //lower start level.setPosToSpawn(0, -50); //lower start

View File

@@ -1054,7 +1054,9 @@ const mobs = {
this.health -= dmg this.health -= dmg
//this.fill = this.color + this.health + ')'; //this.fill = this.color + this.health + ')';
this.onDamage(dmg); //custom damage effects this.onDamage(dmg); //custom damage effects
if (this.health < 0.05 && this.alive) this.death(); if (this.health < 0.05 && this.alive) {
this.death();
}
} }
}, },
onDamage() { onDamage() {

View File

@@ -3208,8 +3208,8 @@ const m = {
obj.beforeDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here obj.beforeDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here
let dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity))) let dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)))
if (tech.isCrit && mob[k].isStunned) dmg *= 4 if (tech.isCrit && mob[k].isStunned) dmg *= 4
mob[k].foundPlayer();
mob[k].damage(dmg); mob[k].damage(dmg);
if (mob[k].alive) mob[k].foundPlayer();
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x, x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y, y: pairs[i].activeContacts[0].vertex.y,
@@ -3239,7 +3239,7 @@ const m = {
const stunTime = dmg / Math.sqrt(obj.mass) const stunTime = dmg / Math.sqrt(obj.mass)
if (stunTime > 0.5) mobs.statusStun(mob[k], 30 + 60 * Math.sqrt(stunTime)) if (stunTime > 0.5) mobs.statusStun(mob[k], 30 + 60 * Math.sqrt(stunTime))
if (mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer(); if (mob[k].alive && mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer();
if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) { if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) {
obj.hasFragmented = true; obj.hasFragmented = true;
b.targetedNail(obj.position, tech.fragments * 4) b.targetedNail(obj.position, tech.fragments * 4)

View File

@@ -175,7 +175,7 @@ const powerUps = {
tech.maxDuplicationEvent() tech.maxDuplicationEvent()
} }
if (tech.isCancelRerolls) { if (tech.isCancelRerolls) {
for (let i = 0; i < 10; i++) { for (let i = 0; i < 9; i++) {
let spawnType = (m.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo" let spawnType = (m.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo"
if (Math.random() < 0.33) { if (Math.random() < 0.33) {
spawnType = "heal" spawnType = "heal"
@@ -780,15 +780,6 @@ const powerUps = {
spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun
if (level.levelsCleared < 4) { //runs 4 times on all difficulty levels if (level.levelsCleared < 4) { //runs 4 times on all difficulty levels
if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech") if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech")
//bonus power ups for clearing runs in the last game
if (level.levelsCleared === 0 && !simulation.isCheating && localSettings.levelsClearedLastGame > 1) {
for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game
simulation.makeTextLog(`for (let i <span class='color-symbol'>=</span> 0; i <span class='color-symbol'><</span> localSettings.levelsClearedLastGame <span class='color-symbol'>/</span> 3; i<span class='color-symbol'>++</span>)`);
simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") <em>//simulation superposition</em>}`);
localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
if (b.inventory.length === 0) { if (b.inventory.length === 0) {
powerUps.spawn(x, y, "gun", false); //first gun powerUps.spawn(x, y, "gun", false); //first gun
} else if (tech.totalCount === 0) { //first tech } else if (tech.totalCount === 0) { //first tech
@@ -886,9 +877,7 @@ const powerUps = {
name: target.name, name: target.name,
size: size size: size
}); });
if (mode) { if (mode) powerUp[index].mode = mode
powerUp[index].mode = mode
}
if (moving) { if (moving) {
Matter.Body.setVelocity(powerUp[index], { Matter.Body.setVelocity(powerUp[index], {
x: (Math.random() - 0.5) * 15, x: (Math.random() - 0.5) * 15,

View File

@@ -57,6 +57,14 @@ const simulation = {
m.hold(); m.hold();
level.customTopLayer(); level.customTopLayer();
simulation.draw.wireFrame(); simulation.draw.wireFrame();
if (input.fire && m.fireCDcycle < m.cycle) {
m.fireCDcycle = m.cycle + 15; //fire cooldown
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitudeSquared(Vector.sub(mob[i].position, simulation.mouseInGame)) < mob[i].radius * mob[i].radius) {
console.log(mob[i])
}
}
}
simulation.draw.cons(); simulation.draw.cons();
simulation.draw.testing(); simulation.draw.testing();
simulation.drawCircle(); simulation.drawCircle();

View File

@@ -180,7 +180,7 @@
if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage
if (tech.isEnergyDamage) dmg *= 1 + m.energy / 9; if (tech.isEnergyDamage) dmg *= 1 + m.energy / 9;
if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.005 if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.005
if (tech.isRerollDamage) dmg *= 1 + 0.042 * powerUps.research.count if (tech.isRerollDamage) dmg *= 1 + 0.04 * powerUps.research.count
if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.23 if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.23
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2
if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165) if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165)
@@ -188,12 +188,12 @@
return dmg * tech.slowFire * tech.aimDamage return dmg * tech.slowFire * tech.aimDamage
}, },
duplicationChance() { duplicationChance() {
return (tech.isPowerUpsVanish ? 0.2 : 0) + (tech.isStimulatedEmission ? 0.22 : 0) + tech.cancelCount * 0.05 + tech.duplicateChance + m.duplicateChance + tech.wormDuplicate + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) return (tech.isPowerUpsVanish ? 0.2 : 0) + (tech.isStimulatedEmission ? 0.22 : 0) + tech.cancelCount * 0.048 + tech.duplicateChance + m.duplicateChance + tech.wormDuplicate + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0)
}, },
maxDuplicationEvent() { maxDuplicationEvent() {
if (tech.is100Duplicate && tech.duplicationChance() > 0.99) { if (tech.is100Duplicate && tech.duplicationChance() > 0.99) {
tech.is100Duplicate = false tech.is100Duplicate = false
const range = 600 const range = 450
spawn.randomLevelBoss(m.pos.x + range, m.pos.y, spawn.nonCollideBossList); spawn.randomLevelBoss(m.pos.x + range, m.pos.y, spawn.nonCollideBossList);
spawn.randomLevelBoss(m.pos.x, m.pos.y + range, spawn.nonCollideBossList); spawn.randomLevelBoss(m.pos.x, m.pos.y + range, spawn.nonCollideBossList);
spawn.randomLevelBoss(m.pos.x - range, m.pos.y, spawn.nonCollideBossList); spawn.randomLevelBoss(m.pos.x - range, m.pos.y, spawn.nonCollideBossList);
@@ -767,7 +767,7 @@
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion) return !tech.isBlockExplode && tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion)
}, },
requires: "an explosive damage source, not ammonium nitrate or nitroglycerin", requires: "an explosive damage source, not ammonium nitrate or nitroglycerin",
effect: () => { effect: () => {
@@ -785,7 +785,7 @@
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion) return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion)
}, },
requires: "an explosive damage source, not iridium-192", requires: "an explosive damage source, not iridium-192",
effect: () => { effect: () => {
@@ -803,7 +803,7 @@
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion) return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion)
}, },
requires: "an explosive damage source, not iridium-192", requires: "an explosive damage source, not iridium-192",
effect: () => { effect: () => {
@@ -821,7 +821,7 @@
frequency: 2, frequency: 2,
isBadRandomOption: true, isBadRandomOption: true,
allowed() { allowed() {
return !tech.isRewindGrenade && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.isBlockExplosion) return !tech.isRewindGrenade && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.isBlockExplosion)
}, },
requires: "an explosive damage source, not causality bombs", requires: "an explosive damage source, not causality bombs",
effect: () => { effect: () => {
@@ -831,25 +831,6 @@
tech.isExplosionHarm = false; tech.isExplosionHarm = false;
} }
}, },
{
name: "chain reaction",
description: "<strong class='color-block'>blocks</strong> caught in <strong class='color-e'>explosions</strong> also <strong class='color-e'>explode</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion)
},
requires: "an explosive damage source, not iridium-192",
effect() {
tech.isBlockExplode = true;
},
remove() {
tech.isBlockExplode = false;
}
},
{ {
name: "shock wave", name: "shock wave",
description: "<strong class='color-e'>explosions</strong> <strong>stun</strong> mobs for <strong>1-2</strong> seconds<br>decrease <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>30%</strong>", description: "<strong class='color-e'>explosions</strong> <strong>stun</strong> mobs for <strong>1-2</strong> seconds<br>decrease <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>30%</strong>",
@@ -859,7 +840,7 @@
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed() { allowed() {
return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion) return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isBlockExplosion)
}, },
requires: "an explosive damage source, not iridium-192", requires: "an explosive damage source, not iridium-192",
effect() { effect() {
@@ -878,7 +859,7 @@
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isMissileField || tech.isExplodeMob || tech.isPulseLaser || tech.isBlockExplosion) return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isMissileField || tech.isExplodeMob || tech.isPulseLaser || tech.isBlockExplosion)
}, },
requires: "an explosive damage source, not iridium-192", requires: "an explosive damage source, not iridium-192",
effect: () => { effect: () => {
@@ -2915,7 +2896,7 @@
}, },
{ {
name: "Bayesian statistics", name: "Bayesian statistics",
description: "increase <strong class='color-d'>damage</strong> by <strong>4.2%</strong><br>for each <strong class='color-r'>research</strong> in your inventory", description: "increase <strong class='color-d'>damage</strong> by <strong>4%</strong><br>for each <strong class='color-r'>research</strong> in your inventory",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 2,
@@ -3038,7 +3019,7 @@
}, },
{ {
name: "replication", name: "replication",
description: "<strong>10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+18</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool", description: "<strong>10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+30</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3055,7 +3036,7 @@
remove() { remove() {
tech.duplicateChance = 0 tech.duplicateChance = 0
powerUps.setDo(); //needed after adjusting duplication chance powerUps.setDo(); //needed after adjusting duplication chance
if (this.count > 1) tech.removeJunkTechFromPool(18) if (this.count > 1) tech.removeJunkTechFromPool(30)
} }
}, },
{ {
@@ -3100,7 +3081,7 @@
}, },
{ {
name: "futures exchange", name: "futures exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to <strong>cancel</strong> a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>5%</strong> power up <strong class='color-dup'>duplication</strong> chance", description: "clicking <strong style = 'font-size:150%;'>×</strong> to <strong>cancel</strong> a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>4.8%</strong> power up <strong class='color-dup'>duplication</strong> chance",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3122,7 +3103,7 @@
}, },
{ {
name: "commodities exchange", name: "commodities exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns <strong>10</strong> <strong class='color-h'>heals</strong>, <strong class='color-g'>ammo</strong>, and <strong class='color-r'>research</strong>", description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns <strong>9</strong> <strong class='color-h'>heals</strong>, <strong class='color-g'>ammo</strong>, and <strong class='color-r'>research</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3651,7 +3632,7 @@
allowed() { allowed() {
return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles // && !tech.isNailRadiation && !tech.isNailCrit return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles // && !tech.isNailRadiation && !tech.isNailCrit
}, },
requires: "nail gun, not powder-actuated, rivets, needles, irradiated, or fission", requires: "nail gun, not rivets, needles",
effect() { effect() {
tech.isIceCrystals = true; tech.isIceCrystals = 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
@@ -3762,7 +3743,7 @@
allowed() { allowed() {
return tech.isMineDrop + tech.nailBotCount + tech.fragments + tech.nailsDeathMob / 2 + ((tech.haveGunCheck("mine") && !tech.isLaserMine) + (tech.haveGunCheck("nail gun") && !tech.isNeedleShieldPierce) + tech.isNeedleShot + tech.isNailShot) * 2 > 1 return tech.isMineDrop + tech.nailBotCount + tech.fragments + tech.nailsDeathMob / 2 + ((tech.haveGunCheck("mine") && !tech.isLaserMine) + (tech.haveGunCheck("nail gun") && !tech.isNeedleShieldPierce) + tech.isNeedleShot + tech.isNailShot) * 2 > 1
}, },
requires: "nails, rivets, not ceramic needles, not ice crystals", requires: "nails, rivets, not ceramic needles",
effect() { effect() {
tech.isNailRadiation = true; tech.isNailRadiation = true;
}, },
@@ -3924,7 +3905,7 @@
}, },
{ {
name: "needle-shot", name: "needle-shot",
description: "<strong>shotgun</strong> propels <strong>12</strong> mob piercing <strong>needles</strong>", description: "<strong>shotgun</strong> propels <strong>11</strong> mob piercing <strong>needles</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -4345,6 +4326,25 @@
b.setGrenadeMode() b.setGrenadeMode()
} }
}, },
{
name: "chain reaction",
description: "increase <strong>grenade</strong> radius and <strong class='color-d'>damage</strong> <strong>33%</strong><br><strong class='color-block'>blocks</strong> caught in <strong class='color-e'>explosions</strong> also <strong class='color-e'>explode</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.isVacuumBomb && !tech.isExplodeRadio
},
requires: "vacuum bomb && not iridium-192",
effect() {
tech.isBlockExplode = true; //chain reaction
},
remove() {
tech.isBlockExplode = false;
}
},
{ {
name: "neutron bomb", name: "neutron bomb",
description: "<strong>grenades</strong> are <strong class='color-p'>irradiated</strong> with <strong class='color-p'>Cf-252</strong><br>does <strong class='color-d'>damage</strong>, <strong class='color-harm'>harm</strong>, and drains <strong class='color-f'>energy</strong>", description: "<strong>grenades</strong> are <strong class='color-p'>irradiated</strong> with <strong class='color-p'>Cf-252</strong><br>does <strong class='color-d'>damage</strong>, <strong class='color-harm'>harm</strong>, and drains <strong class='color-f'>energy</strong>",
@@ -4579,7 +4579,7 @@
} }
}, },
{ {
name: "decomposer", name: "necrophage",
description: "if <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> <strong>kill</strong> their target<br>they reset their <strong>lifespan</strong>", description: "if <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> <strong>kill</strong> their target<br>they reset their <strong>lifespan</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,

View File

@@ -1,28 +1,22 @@
******************************************************** NEXT PATCH ******************************************************** ******************************************************** NEXT PATCH ********************************************************
decomposers - worms reset their lifespan if they kill their target tech: chain reaction now requires vacuum bomb, but it increases grenade radius and damage 33%
(and makes blocks explode)
nail tech tree reworked a bit needle gun fires with more regular timing
removed powder actuated, nail gun ramps up to full fire rate with just pneumatic actuator needles despawn 1.5s faster, for performance reasons
needles and ice crystal nucleation can get supercritical fission and irradiated nails now intro level power ups are relocated
supercritical fission crits easier tech: decomposers renamed necrophage
if mobs are one shotted before they see you, they no longer alert nearby mobs
labs exit platforming is a much easier since it's in the general rotation now clicking on a mob in testing will log that mob in console
bug fixes
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************
make
buff nail gun
buff missiles? buff missiles?
maybe they can release grenades after they explode, like CPT grenades? maybe they can release grenades after they explode, like CPT grenades?
move the bonus tech on intro to the right so players don't have to backtrack as much make the player get a buff after using wormhole
maybe draw something in the background to explain where the tech is coming from while energy lasts: drain energy and give damage buff
using wormhole makes you immune to harm and drains energy until you run out using wormhole makes you immune to harm and drains energy until you run out
disable incoming energy, by saving current energy and just setting energy in the next cycle to be lower then the saved value disable incoming energy, by saving current energy and just setting energy in the next cycle to be lower then the saved value
@@ -37,9 +31,6 @@ pause should at least show the last in game console message
in testing mode console log the body you click on in testing mode console log the body you click on
make the player get a buff after using wormhole
while energy lasts: drain energy and give damage buff
tech: quantized shields - harmonic standing wave field can only lose 33 energy per hit tech: quantized shields - harmonic standing wave field can only lose 33 energy per hit
draw 1,2,3 levels of the field based on energy? draw 1,2,3 levels of the field based on energy?
the blocked value only scales up to 2x or 4x (33 energy) blocked the blocked value only scales up to 2x or 4x (33 energy) blocked