diff --git a/.DS_Store b/.DS_Store index 8eea4f3..b62cbdd 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/index.html b/index.html index 25ede8b..a4de16a 100644 --- a/index.html +++ b/index.html @@ -185,7 +185,7 @@ Chat about n-gon in the discord.
Let me know about ideas, or bugs.


- + diff --git a/js/bullet.js b/js/bullet.js index f1a7817..a8e8d39 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -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) - // } - // }, }, ], }; \ No newline at end of file diff --git a/js/engine.js b/js/engine.js index 855a607..51658f2 100644 --- a/js/engine.js +++ b/js/engine.js @@ -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; diff --git a/js/level.js b/js/level.js index 43a3512..54e4a94 100644 --- a/js/level.js +++ b/js/level.js @@ -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 diff --git a/js/mob.js b/js/mob.js index e18a81f..100a139 100644 --- a/js/mob.js +++ b/js/mob.js @@ -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 diff --git a/js/player.js b/js/player.js index ff046a4..e0a0ecd 100644 --- a/js/player.js +++ b/js/player.js @@ -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(`m.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(`m.maxEnergy = ${(m.maxEnergy.toFixed(2))}`) }, fieldMeterColor: "#0cf", diff --git a/js/simulation.js b/js/simulation.js index 9ef1c34..04131cf 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -848,7 +848,6 @@ const simulation = { m.fireCDcycle = 0 m.drop(); m.hole.isOn = false; - level.zones = []; simulation.drawList = []; if (tech.isDronesTravel && m.alive) { diff --git a/js/spawn.js b/js/spawn.js index 2f9fce4..06952fe 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -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()) diff --git a/js/tech.js b/js/tech.js index 65ad875..2e941b7 100644 --- a/js/tech.js +++ b/js/tech.js @@ -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: "energy protects you instead of health
√ of harm reduction reduces max energy", description: "energy protects you instead of health
harm reduction effects provide no benefit", maxCount: 1, count: 0, @@ -3675,11 +3678,13 @@ const tech = { }, { name: "strange attractor", - description: `use ${powerUps.orb.research(2)} to spawn 1 tech
with double your duplication chance`, + descriptionFunction() { return `use ${powerUps.orb.research(2)} to spawn 1 tech with double
your duplication chance (${(2*tech.duplicationChance()*100).toFixed(0)}%)` }, + + // description: `use ${powerUps.orb.research(2)} to spawn 1 tech with double
your duplication chance (${(2*tech.duplicationChance()*100).toFixed(0)}%)`, 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 explosive radius by 80%, but
you take 200% more harm from explosions", + description: "increase explosive radius by 70%, but
you take 50% more harm from explosions", 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
reduce combat difficulty by 2 levels", + 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 blocks
blocks have a chance to spawn power ups", @@ -7907,7 +7932,7 @@ const tech = { }, { name: "closed timelike curve", - description: "spawn 5 field power ups, but every 12 seconds
teleport a second into your future
", + description: "spawn 5 field power ups, but every 12 seconds
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: `
path integral`, diff --git a/todo.txt b/todo.txt index e6c8ced..a4bb3b4 100644 --- a/todo.txt +++ b/todo.txt @@ -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