laser delay

laser energy drain and damage now scale with fire delay effects
  no change for pulse since it already has a fire delay

explosion harm to player no longer scales with explosion radius
  explosion damage will treat all explosions the same as a basic grenade explosion
  large radius explosions are much safer
acetone peroxide 80->70% increased radius, 100->50% increase in harm from explosions

CPT only triggers from damage above 1% per game cycle
  so no trigger from slime hazards or black holes or mob auras
level: reactor has a horizontal flipped mode
regression gives finalBoss(1.0005), Boss(1.0025), mob(1.05) increased damage taken

JUNK tech: return - go back to the intro level, but keep your tech

bug fixes
This commit is contained in:
landgreen
2022-06-05 13:37:38 -07:00
parent 9bc927d7ad
commit 227e4491a6
11 changed files with 330 additions and 242 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -185,7 +185,7 @@
</a>
Chat about n-gon in the <a href="https://discord.gg/JyfrKbXTfw">discord</a>.<br> Let me know about ideas, or bugs.
<br><br><br>
<a href="https://github.com/landgreen/n-gon">
<a id="github" href="https://github.com/landgreen/n-gon">
<svg viewBox="0 0 100 16" xmlns="http://www.w3.org/2000/svg" fill="#1B1F23">
<path d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z" />
<g stroke='none' font-size="8px" font-family="Arial Black, sans-serif">

View File

@@ -347,14 +347,14 @@ const b = {
}
},
explosionRange() {
return tech.explosiveRadius * (tech.isExplosionHarm ? 1.8 : 1) * (tech.isSmallExplosion ? 0.66 : 1) * (tech.isExplodeRadio ? 1.25 : 1)
return tech.explosiveRadius * (tech.isExplosionHarm ? 1.7 : 1) * (tech.isSmallExplosion ? 0.66 : 1) * (tech.isExplodeRadio ? 1.25 : 1)
},
explosion(where, radius, color = "rgba(255,25,0,0.6)") { // typically explode is used for some bullets with .onEnd
radius *= tech.explosiveRadius
let dist, sub, knock;
let dmg = radius * 0.019 * (tech.isExplosionStun ? 0.7 : 1); //* 0.013 * (tech.isExplosionStun ? 0.7 : 1);
if (tech.isExplosionHarm) radius *= 1.8 // 1/sqrt(2) radius -> area
if (tech.isExplosionHarm) radius *= 1.7 // 1/sqrt(2) radius -> area
if (tech.isSmallExplosion) {
// color = "rgba(255,0,30,0.7)"
radius *= 0.66
@@ -375,7 +375,7 @@ const b = {
//player damage
if (Vector.magnitude(Vector.sub(where, player.position)) < radius) {
const DRAIN = (tech.isExplosionHarm ? 0.9 : 0.45) * (tech.isRadioactiveResistance ? 0.25 : 1)
const DRAIN = (tech.isExplosionHarm ? 0.67 : 0.45) * (tech.isRadioactiveResistance ? 0.25 : 1)
if (m.immuneCycle < m.cycle) m.energy -= DRAIN
if (m.energy < 0) {
m.energy = 0
@@ -424,7 +424,7 @@ const b = {
if (dist < radius) {
if (simulation.dmgScale) {
const harm = radius * (tech.isExplosionHarm ? 0.00036 : 0.00018)
const harm = tech.isExplosionHarm ? 0.075 : 0.05
if (tech.isImmuneExplosion && m.energy > 0.15) {
// const mitigate = Math.min(1, Math.max(1 - m.energy * 0.5, 0))
m.energy -= 0.15
@@ -458,14 +458,14 @@ const b = {
body[i].force.y += knock.y;
if (tech.isBlockExplode) {
if (body[i] === m.holdingTarget) m.drop()
const size = 20 + 350 * Math.pow(body[i].mass, 0.25)
const size = 20 + 300 * Math.pow(body[i].mass, 0.25)
const where = body[i].position
const onLevel = level.onLevel //prevent explosions in the next level
Matter.Composite.remove(engine.world, body[i]);
body.splice(i, 1);
setTimeout(() => {
if (onLevel === level.onLevel) b.explosion(where, size); //makes bullet do explosive damage at end
}, 150 + 300 * Math.random());
}, 250 + 300 * Math.random());
}
} else if (dist < alertRange) {
knock = Vector.mult(Vector.normalise(sub), -Math.sqrt(dmg) * body[i].mass * 0.011);
@@ -2389,14 +2389,14 @@ const b = {
}
if (tech.isLaserPush) { //push mobs away
const index = path.length - 1
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.95, y: best.who.velocity.y * 0.95 });
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.005 * push * Math.min(6, best.who.mass))
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
Matter.Body.applyForce(best.who, path[index], force)
}
} else if (tech.isLaserPush && best.who.classType === "body") {
const index = path.length - 1
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.95, y: best.who.velocity.y * 0.95 });
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.005 * push * Math.min(6, best.who.mass))
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
Matter.Body.applyForce(best.who, path[index], force)
}
};
@@ -4203,7 +4203,7 @@ const b = {
}
}
if (!m.isCloak) { //if time dilation isn't active
if (!m.isCloak) { //if cloaking field isn't active
const size = 33
q = Matter.Query.region(mob, {
min: {
@@ -6957,8 +6957,15 @@ const b = {
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
} else {
m.fireCDcycle = m.cycle
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
b.laser();
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
const where = {
x: m.pos.x + 20 * Math.cos(m.angle),
y: m.pos.y + 20 * Math.sin(m.angle)
}
b.laser(where, {
x: where.x + 3000 * Math.cos(m.angle),
y: where.y + 3000 * Math.sin(m.angle)
}, tech.laserDamage / b.fireCDscale);
}
},
firePulse() {
@@ -6969,11 +6976,11 @@ const b = {
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
} else {
m.fireCDcycle = m.cycle
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
// const divergence = input.down ? 0.15 : 0.2
// const scale = Math.pow(0.9, tech.beamSplitter)
// const pushScale = scale * scale
let dmg = tech.laserDamage // * scale //Math.pow(0.9, tech.laserDamage)
let dmg = tech.laserDamage / b.fireCDscale // * scale //Math.pow(0.9, tech.laserDamage)
const where = {
x: m.pos.x + 20 * Math.cos(m.angle),
y: m.pos.y + 20 * Math.sin(m.angle)
@@ -6993,7 +7000,7 @@ const b = {
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
} else {
m.fireCDcycle = m.cycle
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
const range = {
x: 5000 * Math.cos(m.angle),
y: 5000 * Math.sin(m.angle)
@@ -7006,7 +7013,7 @@ const b = {
x: 7.5 * Math.cos(m.angle - Math.PI / 2),
y: 7.5 * Math.sin(m.angle - Math.PI / 2)
}
const dmg = 0.70 * tech.laserDamage // 3.5 * 0.55 = 200% more damage
const dmg = 0.70 * tech.laserDamage / b.fireCDscale // 3.5 * 0.55 = 200% more damage
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
const eye = {
x: m.pos.x + 15 * Math.cos(m.angle),
@@ -7057,8 +7064,8 @@ const b = {
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
} else {
m.fireCDcycle = m.cycle
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
const dmg = 0.4 * tech.laserDamage // 3.5 * 0.55 = 200% more damage
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
const dmg = 0.4 * tech.laserDamage / b.fireCDscale // 3.5 * 0.55 = 200% more damage
const spacing = Math.ceil(4 - 0.3 * tech.historyLaser)
ctx.beginPath();
b.laser({
@@ -7084,27 +7091,6 @@ const b = {
ctx.stroke();
}
},
// firePulse() {
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down
// let energy = 0.3 * Math.min(m.energy, 1.5)
// m.energy -= energy * tech.isLaserDiode
// if (tech.beamSplitter) {
// // energy *= Math.pow(0.9, tech.beamSplitter)
// // b.pulse(energy, m.angle)
// // for (let i = 1; i < 1 + tech.beamSplitter; i++) {
// // b.pulse(energy, m.angle - i * 0.27)
// // b.pulse(energy, m.angle + i * 0.27)
// // }
// const divergence = input.down ? 0.2 : 0.5
// const angle = m.angle - tech.beamSplitter * divergence / 2
// for (let i = 0; i < 1 + tech.beamSplitter; i++) {
// b.pulse(energy, angle + i * divergence)
// }
// } else {
// b.pulse(energy, m.angle)
// }
// },
},
],
};

View File

@@ -109,7 +109,7 @@ function collisionChecks(event) {
let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * simulation.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0
if (m.isCloak) dmg *= 0.5
mob[k].foundPlayer();
if (tech.isRewindAvoidDeath && m.energy > 0.66) { //CPT reversal runs in m.damage, but it stops the rest of the collision code here too
if (tech.isRewindAvoidDeath && m.energy > 0.66 && dmg > 0.01) { //CPT reversal runs in m.damage, but it stops the rest of the collision code here too
m.damage(dmg);
return
}
@@ -190,7 +190,7 @@ function collisionChecks(event) {
time: simulation.drawTime
});
}
if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? 1.0025 : 1.05
if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? (mob[k].isFinalBoss ? 1.0005 : 1.0025) : 1.05
return;
}
//mob + body collisions
@@ -229,7 +229,7 @@ function collisionChecks(event) {
}
const stunTime = dmg / Math.sqrt(obj.mass)
if (stunTime > 0.5) mobs.statusStun(mob[k], 60 + 60 * Math.sqrt(stunTime))
if (stunTime > 0.5 && mob[k].memory !== Infinity) mobs.statusStun(mob[k], 60 + 60 * Math.sqrt(stunTime))
if (mob[k].alive && mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer();
if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) {
obj.hasFragmented = true;

View File

@@ -15,10 +15,10 @@ const level = {
levels: [],
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// // simulation.isHorizontalFlipped = true
// simulation.isHorizontalFlipped = true
// m.addHealth(Infinity)
// m.setField("time dilation")
// b.giveGuns("spores")
// b.giveGuns("laser")
// tech.giveTech("closed timelike curve")
// tech.giveTech("retrocausality")
// tech.giveTech("clock gating")
@@ -38,11 +38,7 @@ const level = {
// level.difficultyIncrease(20) //30 is near max on hard //60 is near max on why
// simulation.enableConstructMode() //used to build maps in testing mode
// level.testing();
// simulation.fpsCap = 30 //new fps
// simulation.fpsInterval = 1000 / simulation.fpsCap;
//how long to wait to return to normal fps
// m.defaultFPSCycle = m.cycle + 20 + Math.min(90, Math.floor(200 * dmg))
// spawn.timeSkipBoss(1900, -500)
// spawn.starter(1900, -500, 200)
// level.reactor(); //not in rotation, used for testing
if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************
@@ -2697,8 +2693,6 @@ const level = {
// spawn.randomMob(1600, -500)
},
reactor() {
level.setPosToSpawn(-550, -800); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 3500;
level.exit.y = -42;
spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
@@ -2708,8 +2702,7 @@ const level = {
color.map = "#303639";
// powerUps.spawnStartingPowerUps(1475, -1175);
// spawn.debris(750, -2200, 3700, 16); //16 debris per level
const button = level.button(1400, 0)
button.isUp = true
spawn.bodyRect(250, -70, 100, 70, 1);
spawn.mapRect(-425, 0, 4500, 2100);
spawn.mapRect(-475, -2825, 4500, 1025);
@@ -2735,90 +2728,169 @@ const level = {
let isFightOver = false
let isSpawnedBoss = false
level.custom = () => {
if (isDoorsLocked) {
if (player.position.x < -300) { //if player gets trapped inside starting room open up again
isDoorsLocked = false
doorIn.isClosing = false
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
level.setPosToSpawn(550, -800); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
const button = level.button(-1500, 0)
button.isUp = true
level.custom = () => {
if (isDoorsLocked) {
if (player.position.x > 300) { //if player gets trapped inside starting room open up again
isDoorsLocked = false
doorIn.isClosing = false
}
}
}
// else if (!isFightOver && player.position.x > 225) {
// isDoorsLocked = true
// doorIn.isClosing = true
// doorOut.isClosing = true
// }
doorIn.openClose();
doorOut.openClose();
ctx.fillStyle = "#d5ebef"
ctx.fillRect(2750, -375, 1050, 375)
level.enter.draw();
level.exit.drawAndCheck();
button.draw();
if (button.isUp) {
button.query();
} else if (!isSpawnedBoss) {
if (player.position.x > 0) {
if (!doorOut.isClosed() || !doorIn.isClosed()) {
doorIn.isClosing = true
doorOut.isClosing = true
doorIn.openClose();
doorOut.openClose();
ctx.fillStyle = "#d5ebef"
ctx.fillRect(-3800, -375, 1050, 375)
level.enter.draw();
level.exit.drawAndCheck();
button.draw();
if (button.isUp) {
button.query();
} else if (!isSpawnedBoss) {
if (player.position.x < 0) {
if (!doorOut.isClosed() || !doorIn.isClosed()) {
doorIn.isClosing = true
doorOut.isClosing = true
} else {
isSpawnedBoss = true
isDoorsLocked = true
for (let i = 0; i < 9; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "ammo")
for (let i = 0; i < 3; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "heal");
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
if (Math.random() < 0.07 && simulation.difficulty > 24) {
for (let i = 0, len = scale * 0.25 / 4; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
for (let i = 0, len = scale * 0.1 / 4; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false);
for (let i = 0, len = scale * 0.16 / 4; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false)
for (let i = 0, len = scale * 0.23 / 4; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false);
} else {
if (Math.random() < 0.25) {
for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.33) {
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.5) {
for (let i = 0, len = scale * 0.16; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
} else {
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
}
}
spawn.secondaryBossChance(-2300, -800)
}
} else {
isSpawnedBoss = true
isDoorsLocked = true
for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
// if (Math.random() < 0.07 && simulation.difficulty > 24) {
// for (let i = 0, len = scale * 0.25 / 4; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
// for (let i = 0, len = scale * 0.1 / 4; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
// for (let i = 0, len = scale * 0.16 / 4; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
// for (let i = 0, len = scale * 0.23 / 4; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
// } else {
// if (Math.random() < 0.25) {
// for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
// } else if (Math.random() < 0.33) {
// for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
// } else if (Math.random() < 0.5) {
// for (let i = 0, len = scale * 0.16; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
// } else {
// for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
// }
// }
spawn.secondaryBossChance(2200, -800)
doorIn.isClosing = false
}
} else {
doorIn.isClosing = false
}
} else if (!isFightOver && !(simulation.cycle % 180)) {
let isFoundBoss = false
for (let i = 0; i < mob.length; i++) {
if (mob[i].isBoss) {
isFoundBoss = true
break
} else if (!isFightOver && !(simulation.cycle % 180)) {
let isFoundBoss = false
for (let i = 0; i < mob.length; i++) {
if (mob[i].isBoss) {
isFoundBoss = true
break
}
}
if (!isFoundBoss) {
isFightOver = true
doorIn.isClosing = false
doorOut.isClosing = false
powerUps.spawnBossPowerUp(-3600, -100)
powerUps.spawn(-3650, -200, "tech")
// if (player.position.x < 2760 && player.position.x > 210) {}
}
}
if (!isFoundBoss) {
isFightOver = true
doorIn.isClosing = false
doorOut.isClosing = false
powerUps.spawnBossPowerUp(3600, -100)
powerUps.spawn(3650, -200, "tech")
// if (player.position.x < 2760 && player.position.x > 210) {}
};
level.customTopLayer = () => {
doorIn.draw();
doorOut.draw();
ctx.fillStyle = "rgba(0,0,0,0.1)"
ctx.fillRect(-225, -1100, 1000, 350);
};
} else {
level.setPosToSpawn(-550, -800); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
const button = level.button(1400, 0)
button.isUp = true
level.custom = () => {
if (isDoorsLocked) {
if (player.position.x < -300) { //if player gets trapped inside starting room open up again
isDoorsLocked = false
doorIn.isClosing = false
}
}
}
};
level.customTopLayer = () => {
// if (isDoorsLocked) {
// ctx.fillStyle = "#333"
// ctx.fillRect(2800, -375, 500, 375);
// }
doorIn.draw();
doorOut.draw();
ctx.fillStyle = "rgba(0,0,0,0.1)"
ctx.fillRect(-775, -1100, 1000, 350);
// ctx.fillStyle = "rgba(0,255,255,0.1)"
// ctx.fillRect(2750, -375, 550, 375)
};
doorIn.openClose();
doorOut.openClose();
ctx.fillStyle = "#d5ebef"
ctx.fillRect(2750, -375, 1050, 375)
level.enter.draw();
level.exit.drawAndCheck();
button.draw();
if (button.isUp) {
button.query();
} else if (!isSpawnedBoss) {
if (player.position.x > 0) {
if (!doorOut.isClosed() || !doorIn.isClosed()) {
doorIn.isClosing = true
doorOut.isClosing = true
} else {
isSpawnedBoss = true
isDoorsLocked = true
for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
if (Math.random() < 0.07 && simulation.difficulty > 24) {
for (let i = 0, len = scale * 0.25 / 4; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
for (let i = 0, len = scale * 0.1 / 4; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
for (let i = 0, len = scale * 0.16 / 4; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
for (let i = 0, len = scale * 0.23 / 4; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
} else {
if (Math.random() < 0.25) {
for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.33) {
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.5) {
for (let i = 0, len = scale * 0.16; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
} else {
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
}
}
spawn.secondaryBossChance(2200, -800)
}
} else {
doorIn.isClosing = false
}
} else if (!isFightOver && !(simulation.cycle % 180)) {
let isFoundBoss = false
for (let i = 0; i < mob.length; i++) {
if (mob[i].isBoss) {
isFoundBoss = true
break
}
}
if (!isFoundBoss) {
isFightOver = true
doorIn.isClosing = false
doorOut.isClosing = false
powerUps.spawnBossPowerUp(3600, -100)
powerUps.spawn(3650, -200, "tech")
// if (player.position.x < 2760 && player.position.x > 210) {}
}
}
};
level.customTopLayer = () => {
doorIn.draw();
doorOut.draw();
ctx.fillStyle = "rgba(0,0,0,0.1)"
ctx.fillRect(-775, -1100, 1000, 350);
};
}
// if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
@@ -3024,7 +3096,9 @@ const level = {
spawn.mapRect(2025, 0, 150, 50); //lid to floor hole
} else {
for (let i = 0; i < 60; i++) {
setTimeout(() => { spawn.sneaker(2100, -1500 - 50 * i); }, 2000 + 500 * i);
setTimeout(() => {
if (level.levels[level.onLevel] === "intro") spawn.sneaker(2100, -1500 - 50 * i);
}, 2000 + 500 * i);
}
}
const wires = new Path2D() //pre-draw the complex lighting path to save processing

View File

@@ -115,13 +115,19 @@ const mobs = {
who.isStunned = true;
who.status.push({
effect() {
who.seePlayer.yes = false;
who.seePlayer.recall = 0;
who.seePlayer.position = {
x: who.position.x + 100 * (Math.random() - 0.5),
y: who.position.y + 100 * (Math.random() - 0.5)
if (who.memory !== Infinity) {
who.seePlayer.yes = false;
who.seePlayer.recall = 0;
who.seePlayer.position = {
x: who.position.x + 100 * (Math.random() - 0.5),
y: who.position.y + 100 * (Math.random() - 0.5)
}
} else {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.6,
y: who.velocity.y * 0.6
});
}
// && !who.isBoss
if (who.velocity.y < 2) who.force.y += who.mass * 0.0004 //extra gravity
//draw health bar

View File

@@ -646,7 +646,7 @@ const m = {
}
},
damage(dmg) {
if (tech.isRewindAvoidDeath && m.energy > 0.6) {
if (tech.isRewindAvoidDeath && m.energy > 0.6 && dmg > 0.01) {
const steps = Math.floor(Math.min(299, 150 * m.energy))
simulation.makeTextLog(`<span class='color-var'>m</span>.rewind(${steps})`)
m.rewind(steps)
@@ -981,6 +981,7 @@ const m = {
},
setMaxEnergy() {
m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 0.6 * (m.fieldUpgrades[m.fieldMode].name === "standing wave")
// if (tech.isEnergyHealth) m.maxEnergy *= Math.sqrt(m.harmReduction())
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-f'>maxEnergy</span> <span class='color-symbol'>=</span> ${(m.maxEnergy.toFixed(2))}`)
},
fieldMeterColor: "#0cf",

View File

@@ -848,7 +848,6 @@ const simulation = {
m.fireCDcycle = 0
m.drop();
m.hole.isOn = false;
level.zones = [];
simulation.drawList = [];
if (tech.isDronesTravel && m.alive) {

View File

@@ -289,6 +289,7 @@ const spawn = {
Composite.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
me.isFinalBoss = true;
me.frictionAir = 0.01;
me.memory = Infinity;
me.hasRunDeathScript = false
@@ -956,7 +957,7 @@ const spawn = {
me.isCell = true;
me.cellID = cellID
me.accelMag = 0.000165 * simulation.accelScale;
me.memory = 40;
me.memory = Infinity;
me.isVerticesChange = true
me.frictionAir = 0.012
me.seePlayerFreq = Math.floor(11 + 7 * Math.random())

View File

@@ -93,6 +93,8 @@ const tech = {
// console.log(count)
// }
// count total non junk tech
id = "github"
let count = 0
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk) count += tech.tech[i].frequency
@@ -2223,6 +2225,7 @@ const tech = {
},
{
name: "mass-energy equivalence",
// description: "<strong class='color-f'>energy</strong> protects you instead of <strong class='color-h'>health</strong><br>√ of <strong class='color-harm'>harm</strong> <strong>reduction</strong> reduces max <strong class='color-f'>energy</strong>",
description: "<strong class='color-f'>energy</strong> protects you instead of <strong class='color-h'>health</strong><br><strong class='color-harm'>harm</strong> <strong>reduction</strong> effects provide <strong>no</strong> benefit",
maxCount: 1,
count: 0,
@@ -3675,11 +3678,13 @@ const tech = {
},
{
name: "strange attractor",
description: `use ${powerUps.orb.research(2)} to spawn <strong>1</strong> <strong class='color-m'>tech</strong><br>with <strong>double</strong> your <strong class='color-dup'>duplication</strong> chance`,
descriptionFunction() { return `use ${powerUps.orb.research(2)} to spawn <strong>1</strong> <strong class='color-m'>tech</strong> with <strong>double</strong><br>your <strong class='color-dup'>duplication</strong> chance <em>(${(2*tech.duplicationChance()*100).toFixed(0)}%)</em>` },
// description: `use ${powerUps.orb.research(2)} to spawn <strong>1</strong> <strong class='color-m'>tech</strong> with <strong>double</strong><br>your <strong class='color-dup'>duplication</strong> chance <em>(${(2*tech.duplicationChance()*100).toFixed(0)}%)</em>`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
frequency: 1000,
frequencyDefault: 1000,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
@@ -4613,7 +4618,7 @@ const tech = {
allowed() {
return tech.haveGunCheck("missiles") && tech.isMissileBig //&& !tech.isSmartRadius && !tech.isImmuneExplosion
},
requires: "missiles, cruse missile", //, not electric reactive armor, controlled explosions",
requires: "missiles, cruse missile",
effect() {
tech.isMissileBiggest = true
},
@@ -4767,7 +4772,7 @@ const tech = {
},
{
name: "acetone peroxide",
description: "increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>80%</strong>, but<br>you take <strong>200%</strong> more <strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong>",
description: "increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>70%</strong>, but<br>you take <strong>50%</strong> more <strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -4857,9 +4862,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isEnergyHealth
},
requires: "an explosive damage source, not iridium-192",
requires: "an explosive damage source, not iridium-192, mass-energy",
effect: () => {
tech.isImmuneExplosion = true;
},
@@ -4916,9 +4921,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades") && !tech.isNeutronBomb
return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode
},
requires: "grenades, not neutron bomb",
requires: "grenades, not neutron bomb, chain reaction",
effect() {
tech.isVacuumBomb = true;
b.setGrenadeMode()
@@ -4937,9 +4942,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb //tech.isVacuumBomb
return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb && !tech.isVacuumBomb
},
requires: "grenades, not iridium-192, neutron bomb",
requires: "grenades, not iridium-192, neutron bomb, vacuum bomb",
effect() {
tech.isBlockExplode = true; //chain reaction
},
@@ -5013,9 +5018,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && !tech.isPetalsExplode && !tech.isCircleExplode
},
requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics",
requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test",
effect() {
tech.isNeutronBomb = true;
b.setGrenadeMode()
@@ -6147,7 +6152,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.18
return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.16
},
requires: "laser, not free-electron",
effect() {
@@ -6174,14 +6179,14 @@ const tech = {
},
requires: "laser, not pulse, diodes",
effect() {
tech.laserFieldDrain = 0.007 //base is 0.002
tech.laserDamage = 0.54; //base is 0.18
tech.laserFieldDrain = 0.0063 //base is 0.002
tech.laserDamage = 0.48; //base is 0.16
tech.laserColor = "#83f"
tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
},
remove() {
tech.laserFieldDrain = 0.002;
tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.16
tech.laserFieldDrain = 0.0018;
tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
tech.laserColor = "#f00"
tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
}
@@ -6348,7 +6353,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.18 && !tech.isStuckOn
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.16 && !tech.isStuckOn
},
requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
effect() {
@@ -7837,6 +7842,26 @@ const tech = {
// },
// remove() {}
// },
{
name: "return",
description: "return to the introduction level<br>reduce combat <strong>difficulty</strong> by <strong>2 levels</strong>",
maxCount: 1,
count: 0,
frequency: 0,
isJunk: true,
isNonRefundable: true,
allowed() {
return true
},
requires: "",
effect() {
// level.levelsCleared = 0 //increases chance of power ups spawns, so shouldn't reset
level.difficultyDecrease(simulation.difficultyMode * 2)
level.onLevel = 0
simulation.clearNow = true //end current level
},
remove() {}
},
{
name: "panpsychism",
description: "awaken all <strong class='color-block'>blocks</strong><br><strong class='color-block'>blocks</strong> have a chance to spawn power ups",
@@ -7907,7 +7932,7 @@ const tech = {
},
{
name: "closed timelike curve",
description: "spawn 5 <strong class='color-f'>field</strong> power ups, but every 12 seconds<br>teleport a second into your future<br>",
description: "spawn 5 <strong class='color-f'>field</strong> power ups, but every 12 seconds<br>teleport a second into your future or past",
maxCount: 1,
count: 0,
frequency: 0,
@@ -7923,7 +7948,14 @@ const tech = {
function loop() {
if (!simulation.paused && m.alive) {
if (!(simulation.cycle % 720)) {
requestAnimationFrame(() => { simulation.timePlayerSkip(60) }); //wrapping in animation frame prevents errors, probably
requestAnimationFrame(() => {
if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option
m.rewind(60)
m.energy += 0.4 //to make up for lost energy
} else {
simulation.timePlayerSkip(60)
}
}); //wrapping in animation frame prevents errors, probably
}
}
requestAnimationFrame(loop);
@@ -9065,7 +9097,10 @@ const tech = {
allowed() { return true },
requires: "",
effect() {
setInterval(() => { m.rewind(120) }, 10000);
setInterval(() => {
m.rewind(120)
m.energy += 0.4
}, 10000);
// for (let i = 0; i < 24; i++) {
// setTimeout(() => { m.rewind(120) }, i * 5000);
// }
@@ -9083,7 +9118,10 @@ const tech = {
allowed() { return true },
requires: "",
effect() {
setInterval(() => { m.rewind(30) }, 4000);
setInterval(() => {
m.rewind(30)
m.energy += 0.2
}, 4000);
},
remove() {}
},
@@ -9674,6 +9712,28 @@ const tech = {
},
remove() {}
},
// {
// name: "JUNKie", //just crashes the game
// description: "all junk",
// maxCount: 1,
// count: 0,
// frequency: 1,
// frequencyDefault: 1,
// isNonRefundable: true,
// isJunk: true,
// allowed() { return true },
// requires: "",
// effect() {
// for (let i = 0, len = tech.tech.length; i < len; i++) {
// if (tech.tech[i].isJunk && tech.tech[i].count < tech.tech[i].maxCount) tech.tech[i].effect()
// }
// },
// remove() {
// tech.tooManyTechChoices = 0
// }
// },
{
name: "path integral",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Path_integral_formulation' class="link">path integral</a>`,

113
todo.txt
View File

@@ -1,45 +1,32 @@
******************************************************** NEXT PATCH **************************************************
boss orbitals and mineBoss mines are destroyed when you deflect them with your field
drones, spores and other bullets that target mobs, will not target invulnerable mobs
timeSKipBoss is a bit slower with a bit less time skipping
fixed color to better match level background colors
laser energy drain and damage now scale with fire delay effects
no change for pulse since it already has a fire delay
JUNK tech: path integral - your next tech choice has almost all possible choices
explosion harm to player no longer scales with explosion radius
explosion damage will treat all explosions the same as a basic grenade explosion
large radius explosions are much safer
acetone peroxide 80->70% increased radius, 100->50% increase in harm from explosions
CPT only triggers from damage above 1% per game cycle
so no trigger from slime hazards or black holes or mob auras
level: reactor has a horizontal flipped mode
regression gives finalBoss(1.0005), Boss(1.0025), mob(1.05) increased damage taken
JUNK tech: return - go back to the intro level, but keep your tech
bug fixes
*********************************************************** TODO *****************************************************
timeskip flickers with tech: clock gating, and game pause after large hit
probably not related to timeskip, related to graphics effect
not a big problem, actually it's kinda neat effect
only fix if there is a clear solution
JUNK tech show 20+ options in tech selection
block manufacturing - molecular assembler tech
Holding r-click will create a slowly increasing in size block, which will be thrown on release
bullets that can target the player
occurs if no mobs targets around
worms? drones? missiles? spores?
all of the above?
BUG time skip probably led to player being able to move, and game not being paused for a few seconds while the death screen faded in
also small chance it happened with rewind instead, but unlikely
block manufacturing - molecular assembler tech
Holding r-click will create a slowly increasing in size block, which will be thrown on release
if a mob dies in skiptime it doesn't register?
is this only for the ondeath event?
so far, but needs more tests
is this only for timeskip > 1
yes I think
make MEE work with harm reduction
how to nerf MEE
maybe harm reduction could also reduce energy regen
Currently, the mob just deals higher damage on impact, which is annoying although not hard to compete with nor unique
By "redesign" I mean replacing instances of the regular mob, since the same code is used for the tiny red projectiles (I think) just add a new mob and remove the old one from the rotation
The new mob should be as such, a "real" exploding mob:
@@ -53,11 +40,6 @@ Regular state: red
About to explode: animation to dark red
Exploding: several shockwaves from the explosion points and tiny trails given to the shrapnel for a second or two until they deaccelerate
make laser gain damage and energy drain from fire delay tech
wording? put it in the gun description
reactor: add horizontal flip mode
pause time like invariant for other things...
throwing blocks
charging railgun
@@ -139,32 +121,7 @@ tech: harpoons stick into enemies
attaches mob to wall if possible
firing while harpoon is stuck into an enemy rips it out of them, inflicting damage and stun and pulling them towards you
bug: often game puts player position at NaN
try:
cloaking/harpoon grapple on normal, continue past beating the final boss
clues:
maybe with vanish or other special blocks and grapple hook
very high level for tech, duplication
happened once with only 13 tech
?&seed=7269&gun0=drones&gun1=matter%20wave&gun2=shotgun&tech0=arsenal&tech1=dead%20reckoning&tech2=regression&tech3=unified%20field%20theory&tech4=rivet%20gun&tech5=phonon&tech6=affine%20connection&field=wormhole&difficulty=2
maybe not about JUNK though
maybe on tons of bullets
maybe grappling hook, Bulk modulus
solution: just kill the player if they go NaN
vanish elements shouldn't collide with mobs
maybe they don't return if mobs are in the way?
maybe they kill mobs in the way
maybe they should go non-collide with mobs
bug: harpoon attack gave a mob really high levels of health
recent events:
had 3 harpoons at a time
tech: immune with grappling hook, Bulk modulus
cancel true colors with pure science
attack with harpoon at slasher mobs
they didn't die, but they should in one hit instead they got a huge health bar, then I just died for no reason after touching one
bug: maybe I can put in an event listener to reset inputs to false when you tab out to prevent key sticking
enemies stuck with foam receive upward force over time
only form aerogel tech?
@@ -195,19 +152,6 @@ setting to remove UI, except health bar
except active gun? to see ammo
checkbox in pause and in settings
bug - url sharing still broken sometimes
tech upgrade to anthropic principle to make it trigger at 50% life and 0% once per map
bug? cloaking field doesn't show energy over max
run more profiles of n-gon to fix performance issues
bug: possibly clearing away all bullets causes a problem
bullet.js 255 (.do() is missing)
I died and quantum immortality triggered (I had needles and ice-IX)
game crashed but recovered
go non-collide with mobs when immune to damage?
mobs that are invulnerable from the front
@@ -325,9 +269,6 @@ electric motors: increases movement speed and jump height, but jumping and movin
mob that fires bullets in 4,5,6,7 different directions at once, no aiming
grow a bit before it fires to indicate state
bug once: switching from shotgun to harpoon somehow set b.activeGun to not defined
https://discord.com/channels/645222059647172618/646505973610971165/919116288008290324
quasarBoss: inverted pulsar boss that hits everything except where its aiming
intro map: diegeticly draw a mouse with field highlighted
@@ -349,8 +290,6 @@ mob/boss that fires a laser at player, but give player time to avoid
they target where player was 1 second ago
they turn to face player?
bug - death while paused crashes game?
tech rocket jump - jumping produces an explosion at your feet that lets you jump extra high, but does some damage
require electric reactive armor?
@@ -547,6 +486,28 @@ n-gon outreach ideas
******************************************************** BUGS ********************************************************
timeskip flickers with tech: clock gating, and game pause after large hit
probably not related to timeskip, related to graphics effect
not a big problem, actually it's kinda neat effect
only fix if there is a clear solution
bug: maybe I can put in an event listener to reset inputs to false when you tab out to prevent key sticking
bug - url sharing still broken sometimes
tech upgrade to anthropic principle to make it trigger at 50% life and 0% once per map
bug? cloaking field doesn't show energy over max
run more profiles of n-gon to fix performance issues
bug - death while paused crashes game?
bug: possibly clearing away all bullets causes a problem
bullet.js 255 (.do() is missing)
I died and quantum immortality triggered (I had needles and ice-IX)
game crashed but recovered
vanish element bug, crashes on touching element, happens for 1 person maybe with junk tech?
safari issues