diff --git a/img/demineralization.webp b/img/demineralization.webp new file mode 100644 index 0000000..81b9468 Binary files /dev/null and b/img/demineralization.webp differ diff --git a/img/equivalence principle.webp b/img/equivalence principle.webp new file mode 100644 index 0000000..b20075f Binary files /dev/null and b/img/equivalence principle.webp differ diff --git a/img/remineralization.webp b/img/remineralization.webp new file mode 100644 index 0000000..a34545c Binary files /dev/null and b/img/remineralization.webp differ diff --git a/js/bullet.js b/js/bullet.js index dcca903..08ffc80 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -2180,7 +2180,7 @@ const b = { const d = Vector.sub(path[path.length - 1], path[path.length - 2]); const nn = Vector.mult(n, 2 * Vector.dot(d, n)); const r = Vector.normalise(Vector.sub(d, nn)); - path[path.length] = Vector.add(Vector.mult(r, 3000), path[path.length - 1]); + path[path.length] = Vector.add(Vector.mult(r, 5000), path[path.length - 1]); }; checkForCollisions(); @@ -3929,7 +3929,7 @@ const b = { bullet[me] = Bodies.rectangle(pos.x, pos.y, 25 * tech.bulletSize, 2 * tech.bulletSize, b.fireAttributes(Math.atan2(velocity.y, velocity.x))); Matter.Body.setVelocity(bullet[me], velocity); Composite.add(engine.world, bullet[me]); //add bullet to world - bullet[me].endCycle = simulation.cycle + 60 + 18 * Math.random(); + bullet[me].endCycle = simulation.cycle + 80 + 18 * Math.random(); bullet[me].dmg = tech.isNailRadiation ? 0 : dmg bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech if (tech.isNailRadiation) mobs.statusDoT(who, dmg * (tech.isFastRadiation ? 1.3 : 0.44), tech.isSlowRadiation ? 360 : (tech.isFastRadiation ? 60 : 180)) // one tick every 30 cycles @@ -6744,8 +6744,12 @@ const b = { isDischarge: false, knockBack: 0.0005, //set in tech: cavitation applyKnock(velocity) { - player.force.x -= this.knockBack * velocity.x - player.force.y -= 2 * this.knockBack * velocity.y + player.force.x -= 0.7 * this.knockBack * velocity.x + if (velocity.y > 0) { + player.force.y -= 4.3 * this.knockBack * velocity.y + } else { + player.force.y -= this.knockBack * velocity.y + } }, chooseFireMethod() { if (tech.isFoamPressure) { @@ -6771,7 +6775,7 @@ const b = { } const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } b.foam(position, Vector.rotate(velocity, spread), radius) - // this.applyKnock(velocity) + this.applyKnock(velocity) m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale); }, doCharges() { @@ -6798,7 +6802,7 @@ const b = { y: m.pos.y + 30 * Math.sin(m.angle) } b.foam(position, Vector.rotate(velocity, spread), radius) - // this.applyKnock(velocity) + this.applyKnock(velocity) this.charge -= 0.75 m.fireCDcycle = m.cycle + 2; //disable firing and adding more charge until empty } else if (!input.fire) { @@ -6826,7 +6830,7 @@ const b = { const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } b.foam(position, Vector.rotate(velocity, spread), radius) - // this.applyKnock(velocity) + this.applyKnock(velocity) m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale); this.charge += 1 + tech.isCapacitor }, @@ -7386,8 +7390,8 @@ const b = { m.energy -= drain 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) + x: where.x + 5000 * Math.cos(m.angle), + y: where.y + 5000 * Math.sin(m.angle) }, tech.laserDamage / b.fireCDscale * this.lensDamage); } }, diff --git a/js/engine.js b/js/engine.js index dc9b6e3..52fc42d 100644 --- a/js/engine.js +++ b/js/engine.js @@ -177,8 +177,8 @@ function collisionChecks(event) { let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); Matter.Body.setVelocity(player, { x: player.velocity.x + 8 * Math.cos(angle), y: player.velocity.y + 8 * Math.sin(angle) }); Matter.Body.setVelocity(mob[k], { x: mob[k].velocity.x - 8 * Math.cos(angle), y: mob[k].velocity.y - 8 * Math.sin(angle) }); - if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.1 && mob[k].damageReduction > 0) { - m.energy -= 0.1 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy + if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.08 && mob[k].damageReduction > 0) { + m.energy -= 0.08 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy if (m.immuneCycle === m.cycle + m.collisionImmuneCycles) m.immuneCycle = 0; //player doesn't go immune to collision damage mob[k].death(); simulation.drawList.push({ //add dmg to draw queue diff --git a/js/index.js b/js/index.js index ec4aaa9..e36a298 100644 --- a/js/index.js +++ b/js/index.js @@ -497,7 +497,7 @@ const build = { level ${((m.dmgScale)).toPrecision(4)}x
damage taken ${(m.defense()).toPrecision(4)}x level ${(simulation.dmgScale).toPrecision(4)}x -
health (${(m.health * 100).toFixed(0)} / ${(m.maxHealth * 100).toFixed(0)}) +
health (${level.isHideHealth ? "null" : (m.health * 100).toFixed(0)} / ${(m.maxHealth * 100).toFixed(0)}) ${powerUps.research.count} ${powerUps.orb.research()}
energy (${(m.energy * 100).toFixed(0)} / ${(m.maxEnergy * 100).toFixed(0)}) + (${(m.fieldRegen * 6000 * level.isReducedRegen).toFixed(0)}/s) ${tech.totalCount} ${powerUps.orb.tech()} diff --git a/js/level.js b/js/level.js index 1308368..85eb04b 100644 --- a/js/level.js +++ b/js/level.js @@ -17,6 +17,8 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode + // simulation.difficultyMode = 1 + // simulation.isHorizontalFlipped = true // spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns // spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns @@ -31,7 +33,7 @@ const level = { // tech.tech[297].frequency = 100 // tech.addJunkTechToPool(0.5) // m.couplingChange(10) - // m.setField("time dilation") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook + // m.setField("negative mass") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook // m.energy = 0 // powerUps.research.count = 3 // tech.isHookWire = true @@ -48,28 +50,26 @@ const level = { // requestAnimationFrame(() => { tech.giveTech("non-renewables") }); // tech.giveTech("dark matter") // tech.addJunkTechToPool(0.5) - // for (let i = 0; i < 1; ++i) tech.giveTech("pigeonhole principle") - // for (let i = 0; i < 1; ++i) tech.giveTech("generalist") + // for (let i = 0; i < 1; ++i) tech.giveTech("demineralization") + // for (let i = 0; i < 1; ++i) tech.giveTech("remineralization") // m.skin.egg(); - // for (let i = 0; i < 1; ++i) tech.giveTech("many-worlds") // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("quasiparticles") }); // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("interest") }); // for (let i = 0; i < 1; i++) tech.giveTech("interest") // m.lastKillCycle = m.cycle - // for (let i = 0; i < 1; i++) powerUps.directSpawn(450, -50, "warp"); + // for (let i = 0; i < 7; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 7; i++) powerUps.directSpawn(m.pos.x + 200, m.pos.y - 250, "research", false); // spawn.bodyRect(575, -700, 150, 150); //block mob line of site on testing - // level.corridor(); + // level.testing(); level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** - // for (let i = 0; i < 1; ++i) spawn.powerUpBossBaby(1900, -500) + // for (let i = 0; i < 10; ++i) spawn.starter(1900, -500) // for (let i = 0; i < 1; i++) spawn.mantisBoss(1900, -500) - // for (let i = 0; i < 1; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "entanglement"); - // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "boost"); + // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "gun"); // for (let i = 0; i < 100; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo"); // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false); //lore testing @@ -145,22 +145,6 @@ const level = { } level.setConstraints() - if (!localSettings.isHideHUD) { - requestAnimationFrame(() => { - //grow and get bright - document.getElementById("right-HUD-constraint").style.opacity = 1 - document.getElementById("right-HUD-constraint").style.fontSize = "23px" - document.getElementById("right-HUD-constraint").style.top = simulation.difficultyMode > 6 ? "6px" : "9px" - setTimeout(() => { - if (m.alive) { - //fade to background - document.getElementById("right-HUD-constraint").style.opacity = 0.35 - document.getElementById("right-HUD-constraint").style.fontSize = "20px" - document.getElementById("right-HUD-constraint").style.top = "12px" - } - }, 5000); - }); - } }, newLevelOrPhase() { //runs on each new level but also on final boss phases //used for generalist and pigeonhole principle @@ -285,6 +269,46 @@ const level = { } }, constraintIndex: 0, + constraintPopUp() { + //pause + if (!simulation.paused) { + simulation.paused = true; + simulation.isChoosing = true; //stops p from un pausing on key down + + document.body.style.cursor = "auto"; + document.getElementById("choose-grid").style.pointerEvents = "auto"; + document.getElementById("choose-grid").style.transitionDuration = "0s"; + } + //build level info + document.getElementById("choose-grid").classList.add('choose-grid-no-images') + document.getElementById("choose-grid").classList.remove('choose-grid') + document.getElementById("choose-grid").style.gridTemplateColumns = "auto"//"450px" + let text = `
${level.constraintDescription1}
` + if (level.constraintDescription2) text += `
${level.constraintDescription2}
` + text += `
continue
` + + document.getElementById("choose-grid").innerHTML = text + //show level info + document.getElementById("choose-grid").style.opacity = "1" + document.getElementById("choose-grid").style.transitionDuration = "0.25s"; //how long is the fade in on + document.getElementById("choose-grid").style.visibility = "visible" + document.getElementById("choose-unPause").addEventListener("click", () => { + level.unPause() + document.body.style.cursor = "none"; + //reset hide image style + if (localSettings.isHideImages) { + document.getElementById("choose-grid").classList.add('choose-grid-no-images'); + document.getElementById("choose-grid").classList.remove('choose-grid'); + } else { + document.getElementById("choose-grid").classList.add('choose-grid'); + document.getElementById("choose-grid").classList.remove('choose-grid-no-images'); + } + }); + requestAnimationFrame(() => { + ctx.fillStyle = `rgba(150,150,150,0.9)`; //`rgba(221,221,221,0.6)`; + ctx.fillRect(0, 0, canvas.width, canvas.height); + }); + }, setConstraints() { //populate array with possible constraints and reset constraints level.constraintDescription1 = level.constraintDescription2 = "" @@ -303,7 +327,6 @@ const level = { level.constraintDescription1 = level.constraint[level.constraintIndex].description level.constraintIndex++ if (level.constraintIndex > level.constraint.length - 1) level.constraintIndex = 0 - if (simulation.difficultyMode > 6 && possible.length) { level.constraint[level.constraintIndex].effect() possible.splice(level.constraintIndex, 1) @@ -312,6 +335,24 @@ const level = { if (level.constraintIndex > level.constraint.length - 1) level.constraintIndex = 0 } document.getElementById("right-HUD-constraint").style.display = "block"; + // level.constraintPopUp() + //animate making constraint HUD bigger then smaller + if (!localSettings.isHideHUD) { + requestAnimationFrame(() => { + //grow and get bright + document.getElementById("right-HUD-constraint").style.opacity = 1 + document.getElementById("right-HUD-constraint").style.fontSize = "23px" + document.getElementById("right-HUD-constraint").style.top = simulation.difficultyMode > 6 ? "6px" : "9px" + setTimeout(() => { + if (m.alive) { + //fade to background + document.getElementById("right-HUD-constraint").style.opacity = 0.35 + document.getElementById("right-HUD-constraint").style.fontSize = "20px" + document.getElementById("right-HUD-constraint").style.top = "12px" + } + }, 5000); + }); + } } else { document.getElementById("right-HUD-constraint").style.display = "none"; } @@ -320,10 +361,10 @@ const level = { } //update HUD with constraints let text = `${level.constraintDescription1}` - if (level.constraintDescription1) simulation.inGameConsole(`constraint: ${level.constraintDescription1}`) + if (level.constraintDescription1) simulation.inGameConsole(`level.constraint.description: "${level.constraintDescription1}"`) if (simulation.difficultyMode > 6 && level.constraintDescription2) { text += `
${level.constraintDescription2}` - if (level.constraintDescription2) simulation.inGameConsole(`constraint: ${level.constraintDescription2}`) + if (level.constraintDescription2) simulation.inGameConsole(`level.constraint.description: "${level.constraintDescription2}"`) } document.getElementById("right-HUD-constraint").innerHTML = text @@ -427,7 +468,7 @@ const level = { } }, { - description: "0.3x damage after getting power ups", + description: "0.3x damage after using power ups", effect() { level.isNoDamage = true level.noDamageCycle = 0 @@ -1719,7 +1760,7 @@ const level = { }, vanish(x, y, width, height, isVertical = false, hide = { x: 0, - y: 150 + y: 400 }) { x = x + width / 2 y = y + height / 2 @@ -6761,26 +6802,34 @@ const level = { level.defaultZoom = 1500 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; - spawn.debris(-150, -775, 1425, 3); //16 debris per level - spawn.debris(1525, -25, 950, 3); //16 debris per level - spawn.debris(-650, -2100, 575, 2); //16 debris per level - + // spawn.debris(-150, -775, 1425, 3); //16 debris per level + // spawn.debris(1525, -25, 950, 3); //16 debris per level + // spawn.debris(-650, -2100, 575, 2); //16 debris per level + powerUps.chooseRandomPowerUp(2075, -1525); + powerUps.chooseRandomPowerUp(2550, -1825); + powerUps.chooseRandomPowerUp(1975, 250); //bottom floor //entrance spawn.mapRect(-200, -750, 1500, 100); - spawn.mapRect(-575, 0, 2150, 500); + // spawn.mapRect(-575, 0, 2150, 500); + spawn.mapRect(-575, 0, 2150, 165); + const mover = level.mover(-525, 270, 2050, 75, 15 * (simulation.isHorizontalFlipped ? -1 : 1)) + spawn.bodyRect(-1050, -75, 75, 75); + spawn.bodyRect(-573, 170, 30, 105); + // spawn.mapRect(-1275, 275, 875, 225); - spawn.mapRect(-1275, 275, 3975, 225); + spawn.mapRect(-1300, 275, 4025, 3300); + // spawn.mapRect(-1275, 275, 3975, 225); spawn.mapRect(-1050, 0, 325, 50); spawn.mapRect(-775, 0, 50, 140); vanish.push(level.vanish(-725, 13, 150, 25)) spawn.mapRect(-200, -750, 100, 600); - // spawn.mapRect(1200, -750, 100, 600); - vanish.push(level.vanish(-350, -225, 150, 225)) - vanish.push(level.vanish(-350, -450, 150, 223)) + vanish.push(level.vanish(-525, -150, 425, 150)) + vanish.push(level.vanish(-475, -300, 275, 150)) + vanish.push(level.vanish(-425, -450, 225, 150)) + vanish.push(level.vanish(-375, -600, 175, 150)) + vanish.push(level.vanish(-325, -750, 125, 150)) spawn.mapRect(2475, -1800, 250, 2300); - - spawn.mapRect(1200, -750, 100, 450); spawn.mapRect(1200, -375, 250, 75); powerUps.spawnStartingPowerUps(550, -100); @@ -6789,10 +6838,18 @@ const level = { spawn.bodyRect(1350, -175, 150, 175, 0.5); spawn.bodyRect(1350, -600, 125, 225, 0.2); + spawn.bodyRect(1575, 50, 50, 225); + vanish.push(level.vanish(1900, -25, 325, 25)) + vanish.push(level.vanish(1925, -375, 275, 25)) + vanish.push(level.vanish(1950, -725, 225, 25)) + vanish.push(level.vanish(1950, -1075, 225, 25)) + spawn.mapRect(1950, -1500, 225, 25); + vanish.push(level.vanish(1350, -1075, 225, 25)) + vanish.push(level.vanish(1637, -1300, 225, 25)) + //middle floor spawn.bodyRect(215, -1175, 100, 100, 0.3); spawn.mapRect(-1300, -1800, 250, 2300); - // spawn.mapRect(-1300, -2075, 250, 2575); if (Math.random() < 0.5) { spawn.mapRect(500, -1350, 525, 425); spawn.mapRect(25, -1050, 300, 198); @@ -6800,34 +6857,17 @@ const level = { spawn.mapRect(500, -1350, 525, 497); spawn.mapRect(25, -1050, 300, 150); } - if (Math.random() < 0.5) { - vanish.push(level.vanish(400, -1600, 175, 25)) - vanish.push(level.vanish(950, -1600, 175, 25)) - } else { - vanish.push(level.vanish(550, -1575, 50, 225)) - vanish.push(level.vanish(925, -1575, 50, 225)) - } - - // vanish.push(level.vanish(575, -1575, 375, 225)) spawn.bodyRect(225, -850, 50, 100, 0.4); - spawn.mapRect(600, -1800, 325, 225); - spawn.mapRect(1900, -1500, 325, 25); + // spawn.mapRect(600, -1800, 325, 225); + spawn.mapRect(650, -1800, 225, 225); + vanish.push(level.vanish(600, -1575, 100, 225)) + vanish.push(level.vanish(825, -1575, 100, 225)) + spawn.bodyRect(1050, -1825, 250, 20, 0.2); - if (Math.random() < 0.5) { - vanish.push(level.vanish(1400, -1000, 200, 25)) - vanish.push(level.vanish(1625, -1250, 200, 25)) - } else { - vanish.push(level.vanish(1400, -1075, 175, 175)) - vanish.push(level.vanish(1575, -1250, 175, 175)) - } + vanish.push(level.vanish(1125, -1800, 625, 25)) - - // vanish.push(level.vanish(1500, -1800, 225, 25)) vanish.push(level.vanish(-50, -1800, 450, 25)) - //exit - // spawn.mapRect(-1050, -1450, 700, 25); - // spawn.mapRect(-1050, -1800, 525, 25); spawn.mapRect(-575, -1800, 50, 200); spawn.mapRect(-1050, -1800, 525, 75); spawn.mapRect(-1050, -1450, 700, 75); @@ -6864,8 +6904,10 @@ const level = { level.exit.drawAndCheck(); level.enter.draw(); + mover.push(); }; level.customTopLayer = () => { + mover.draw(); //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" ctx.fillRect(-1450, -300, 150, 325); @@ -6873,7 +6915,9 @@ const level = { ctx.fillRect(725, 50, 325, 225) ctx.fillRect(-325, -950, 300, 225) ctx.fillRect(-1025, -1000, 525, 275); - ctx.fillRect(-925, -1600, 325, 275); + ctx.fillRect(-875, -1600, 225, 275); + ctx.fillStyle = "rgba(68,68,68,0.93)" + ctx.fillRect(-1575, 150, 2150, 150); for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query() }; @@ -6888,16 +6932,20 @@ const level = { level.exit.drawAndCheck(); level.enter.draw(); + mover.push(); }; level.customTopLayer = () => { + mover.draw(); //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" ctx.fillRect(1300, -300, 150, 325); ctx.fillRect(-200, -675, 1500, 700) ctx.fillRect(500, -950, 525, 225); - ctx.fillRect(600, -1600, 325, 275); + ctx.fillRect(650, -1600, 225, 275); ctx.fillRect(-1050, 50, 325, 225) ctx.fillRect(25, -950, 300, 225) + ctx.fillStyle = "rgba(68,68,68,0.93)" + ctx.fillRect(-575, 150, 2150, 150); for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query() }; } @@ -7178,6 +7226,12 @@ const level = { simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d0d5d5"; color.map = "#444" + powerUps.chooseRandomPowerUp(-1550, 300); + powerUps.chooseRandomPowerUp(200, 50); + powerUps.chooseRandomPowerUp(-975, -1475); + powerUps.chooseRandomPowerUp(2150, -750); + powerUps.chooseRandomPowerUp(1850, 1925); + let buttons = [] let lasers = [] @@ -7202,8 +7256,8 @@ const level = { classType: "body", holdX: 1762, maxHeight: -1580, - minHeight: 130, - verticalForce: 0.03, + minHeight: 90, + verticalForce: 0.02, isUp: false, drag: 0.01, move() { @@ -7269,7 +7323,7 @@ const level = { let buildMapOutline = function () { //boxes center on zero,zero with deep walls to hide background - spawn.mapRect(2025, -2000, 1975, 4000); //right map wall + spawn.mapRect(2225, -2000, 1775, 4000); //right map wall spawn.mapRect(-4000, -2000, 2000, 4000); //left map wall spawn.mapRect(-4000, -5000, 8000, 3000); //map ceiling spawn.mapRect(-4000, 2000, 8000, 3000); //floor @@ -7325,13 +7379,13 @@ const level = { //lower right side //far right wall ledges - spawn.mapRect(1925, -1700, 200, 200); - spawn.mapRect(1925, -1200, 200, 200); - spawn.mapRect(1925, -700, 200, 200); - spawn.mapRect(1925, -200, 200, 200); - spawn.mapRect(1925, 300, 200, 200); - spawn.mapRect(1925, 800, 200, 200); - spawn.mapRect(1925, 1300, 200, 200); + spawn.mapRect(1925, -1700, 400, 200); + spawn.mapRect(1925, -1200, 400, 200); + spawn.mapRect(1925, -700, 400, 200); + spawn.mapRect(1925, -200, 400, 200); + spawn.mapRect(1925, 300, 400, 200); + spawn.mapRect(1925, 800, 400, 200); + spawn.mapRect(1925, 1300, 400, 200); spawn.mapRect(1250, 1650, 500, 25); spawn.mapRect(1300, 1125, 400, 25); @@ -7402,13 +7456,13 @@ const level = { spawn.mapVertex(-350, -835, "-225 -475 225 -475 225 475 0 500 -225 475"); //far right wall ledges - spawn.mapRect(1925, 1700 - 200, 200, 200); - spawn.mapRect(1925, 1200 - 200, 200, 200); - spawn.mapRect(1925, 700 - 200, 200, 200); - spawn.mapRect(1925, 200 - 200, 200, 200); - spawn.mapRect(1925, -300 - 200, 200, 200); - spawn.mapRect(1925, -800 - 200, 200, 200); - spawn.mapRect(1925, -1300 - 200, 200, 200); + spawn.mapRect(1925, 1700 - 200, 400, 200); + spawn.mapRect(1925, 1200 - 200, 400, 200); + spawn.mapRect(1925, 700 - 200, 400, 200); + spawn.mapRect(1925, 200 - 200, 400, 200); + spawn.mapRect(1925, -300 - 200, 400, 200); + spawn.mapRect(1925, -800 - 200, 400, 200); + spawn.mapRect(1925, -1300 - 200, 400, 200); spawn.mapRect(1250, -1650 - 25, 500, 25); spawn.mapRect(1300, -1125 - 25, 400, 25); @@ -7559,7 +7613,7 @@ const level = { //background structure ctx.fillStyle = "#c3c7c7" ctx.fillRect(1487, -75 - 1925, 25, 1925); - ctx.fillRect(1925, -2050, 125, 4100); + ctx.fillRect(1925, -2050, 300, 4100); //exit room ctx.fillStyle = "#d4f4f4" @@ -7580,7 +7634,7 @@ const level = { //background structure ctx.fillStyle = "#c5c9c9" ctx.fillRect(1487, 75, 25, 1925); - ctx.fillRect(1925, -2050, 125, 4100); + ctx.fillRect(1925, -2050, 300, 4100); //draw flipped exit ctx.fillStyle = "#d4f4f4" @@ -7604,7 +7658,7 @@ const level = { ctx.moveTo(balance[i].center.x, balance[i].center.y) ctx.arc(balance[i].center.x, balance[i].center.y, 9, 0, 2 * Math.PI); //rotor spins and stops at vertical and horizontal angles - if ((simulation.cycle % 90) < 15) { + if ((simulation.cycle % 140) < 15) { balance[i].torque = 0.0002 * balance[i].inertia } else if (Math.floor(10 * (balance[i].angle % (Math.PI / 2))) === 0) { Matter.Body.setAngularVelocity(balance[i], balance[i].angularVelocity * 0.1) @@ -7653,6 +7707,8 @@ const level = { spawn.bodyRect(1325, -1775, 175, 175); spawn.bodyRect(-375, -1725, 100, 75, 0.5); spawn.bodyRect(-900, -1625, 125, 200, 0.5); + spawn.bodyRect(875, -25, 200, 175); + spawn.bodyRect(-1662, 1325, 25, 175); spawn.bodyRect(-1662, 1825, 25, 175); @@ -7708,6 +7764,9 @@ const level = { simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#c3d6e1"; color.map = "#444" + powerUps.chooseRandomPowerUp(-1825, 975); + powerUps.chooseRandomPowerUp(-3975, 975); + powerUps.chooseRandomPowerUp(3900, 925); let buttons = [] level.isFlipped = false; @@ -8220,12 +8279,14 @@ const level = { spawn.randomMob(2825, 75, 0.9); spawn.randomLevelBoss(2400, 600); spawn.secondaryBossChance(800, -300) - powerUps.spawnStartingPowerUps(600, 375); + powerUps.chooseRandomPowerUp(600, 375); + powerUps.chooseRandomPowerUp(600, 925); + powerUps.spawnStartingPowerUps(1750, -325); powerUps.addResearchToLevel() //needs to run after mobs are spawned - powerUps.directSpawn(2825, 175, "heal"); - powerUps.directSpawn(2475, -650, "heal"); - powerUps.directSpawn(2100, 925, "heal"); - powerUps.directSpawn(625, -100, "heal"); + powerUps.chooseRandomPowerUp(2825, 175); + powerUps.chooseRandomPowerUp(2475, -650); + powerUps.chooseRandomPowerUp(2100, 925); + powerUps.chooseRandomPowerUp(625, -100); }, corridor() { // simulation.fallHeight = 4000 @@ -8235,6 +8296,10 @@ const level = { document.body.style.backgroundColor = "#d0d5d5"; color.map = "#444" + powerUps.chooseRandomPowerUp(5925, -2125); + powerUps.chooseRandomPowerUp(75, -4225); + powerUps.chooseRandomPowerUp(2950, -1450); + // level.isHorizontalFlipped = true if (level.isHorizontalFlipped) { level.setPosToSpawn(14075, -625); @@ -8473,8 +8538,8 @@ const level = { spawn.randomMob(3575, 375, 0.6); spawn.randomGroup(5300, -1400, 1.3); - spawn.randomLevelBoss(2025, -1825); - spawn.secondaryBossChance(-1900, -1800); + spawn.randomLevelBoss(2025, -1825, ["pulsarBoss", "shieldingBoss", "laserLayerBoss", "shooterBoss"]); + spawn.secondaryBossChance(-1900, -1800, ["historyBoss", "spawnerBossCulture", "blockBoss"]); powerUps.spawnStartingPowerUps(11750, -1000); powerUps.addResearchToLevel() //needs to run after mobs are spawned }, @@ -8948,18 +9013,17 @@ const level = { button0.query(); if (!button0.isUp) { //summon second set of mobs //1 boss, 1-2 groups, 11 mobs (all on lower ground level, where the slime is leaving) - spawn.randomMob(918, 2695, 0.1); - spawn.randomMob(1818, 2719, 0.2); - spawn.randomMob(2530, 2460, 0.2); - spawn.randomMob(3109, 2665, 0.3); - spawn.randomMob(3909, 2191, 0.3); - spawn.randomMob(4705, 2711, 0.4); - spawn.randomMob(5800, 2796, 0.5); - spawn.randomMob(7287, 2757, 0.6); - spawn.randomMob(5759, 2691, 0.9); - spawn.randomMob(5675, 2225, 0.8); - spawn.randomMob(7450, 2775, 0.8); - + spawn.randomMob(918, 2695, 0); + spawn.randomMob(1818, 2719, 0.1); + spawn.randomMob(2530, 2460, 0.1); + spawn.randomMob(3109, 2665, 0.2); + spawn.randomMob(3909, 2191, 0.2); + spawn.randomMob(4705, 2711, 0.3); + spawn.randomMob(5800, 2796, 0.3); + spawn.randomMob(7287, 2757, 0.4); + spawn.randomMob(5759, 2691, 0.4); + spawn.randomMob(5675, 2225, 0.5); + spawn.randomMob(7450, 2775, 0.5); spawn.randomGroup(6600, 2400, 0.1); if (simulation.difficulty > 1) spawn.randomLevelBoss(6076, 2341); } @@ -9050,7 +9114,9 @@ const level = { spawn.bodyRect(3825, 2240, 150, 75, 0.5); spawn.mapVertex(3500, 2452, "-500 -135 500 -135 500 35 400 135 -400 135 -500 35"); - spawn.mapVertex(1200, 2875, "-400 0 -300 -100 300 -100 400 0"); + spawn.mapVertex(1200, 2850, "-500 -100 -550 -50 500 -100 550 -50 550 300 -550 300"); + // spawn.mapVertex(1200, 2875, "-400 0 -300 -100 300 -100 400 0"); + spawn.mapVertex(1317, 275, "-500 0 -300 -200 300 -200 550 50 550 500 -500 500"); spawn.mapVertex(1300, -357, "-300 0 -400 -100 400 -100 300 0"); spawn.bodyRect(1550, -308, 50, 208, 0.5); @@ -9081,17 +9147,17 @@ const level = { spawn.mapRect(7625, 2890, 400, 25); spawn.mapRect(7800, 2880, 100, 25); - spawn.randomMob(2450, 250, 0.2); - spawn.randomMob(3250, 325, 0.2); - spawn.randomMob(3625, 350, 0.3); - spawn.randomMob(1750, -25, 0.4); - spawn.randomMob(1300, 1750, 0.5); - spawn.randomMob(2350, 1725, 0.6); - spawn.randomMob(3350, 1775, 0.7); - spawn.randomMob(1025, 750, 0.8); - spawn.randomMob(2400, 1775, 0.8); - spawn.randomMob(1250, 1725, 0.8); - spawn.randomMob(775, 1775, 0.9); + spawn.randomMob(2450, 250, 0); + spawn.randomMob(3250, 325, 0); + spawn.randomMob(3625, 350, 0.1); + spawn.randomMob(1750, -25, 0.1); + spawn.randomMob(1300, 1750, 0.2); + spawn.randomMob(2350, 1725, 0.2); + spawn.randomMob(3350, 1775, 0.2); + spawn.randomMob(1025, 750, 0.3); + spawn.randomMob(2400, 1775, 0.3); + spawn.randomMob(1250, 1725, 0.3); + spawn.randomMob(775, 1775, 0.4); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(1822, 1336) @@ -9102,7 +9168,7 @@ const level = { balance1 = level.rotor(-800 - 25, -395, 25, 390, 0.001) //entrance balance2 = level.rotor(-2605 - 390, 500, 390, 25, 0.001) //falling - balance3 = level.rotor(-2608 - 584, 1950, 584, 25, 0.001) //falling + balance3 = level.rotor(-2608 - 400, 1950, 400, 25, 0.001) //falling balance5 = level.rotor(-2605 - 390, 1020, 390, 25, 0.001) //falling button1.min.x = -button1.min.x - 126 @@ -9129,17 +9195,17 @@ const level = { button0.query(); if (!button0.isUp) { //summon second set of mobs //1 boss, 1-2 groups, 11 mobs (all on lower ground level, where the slime is leaving) - spawn.randomMob(-7475, 2800, 0.1); - spawn.randomMob(-6475, 2500, 0.2); - spawn.randomMob(-4575, 2775, 0.3); - spawn.randomMob(-7575, 2850, 0.3); - spawn.randomMob(-6425, 2575, 0.3); - spawn.randomMob(-5750, 2775, 0.4); - spawn.randomMob(-4675, 2800, 0.5); - spawn.randomMob(-3425, 2800, 0.6); - spawn.randomMob(-2475, 2475, 0.7); - spawn.randomMob(-3350, 2250, 0.8); - spawn.randomMob(-1275, 2725, 0.9); + spawn.randomMob(-7475, 2800, 0); + spawn.randomMob(-6475, 2500, 0.1); + spawn.randomMob(-4575, 2775, 0.2); + spawn.randomMob(-7575, 2850, 0.2); + spawn.randomMob(-6425, 2575, 0.2); + spawn.randomMob(-5750, 2775, 0.3); + spawn.randomMob(-4675, 2800, 0.3); + spawn.randomMob(-3425, 2800, 0.4); + spawn.randomMob(-2475, 2475, 0.4); + spawn.randomMob(-3350, 2250, 0.5); + spawn.randomMob(-1275, 2725, 0.5); spawn.randomGroup(-6225, 2400, 0.1); if (simulation.difficulty > 1) spawn.randomLevelBoss(-6250, 2350); } @@ -9168,7 +9234,7 @@ const level = { rotor2 = level.rotor(1525, 1900, 650, 50, 0.001, 0, 0.01, 0, -0.0007) balance1 = level.rotor(800, -395, 25, 390, 0.001) //entrance balance2 = level.rotor(2605, 500, 390, 25, 0.001) //falling - balance3 = level.rotor(2608, 1950, 584, 25, 0.001) //falling + balance3 = level.rotor(2608, 1950, 400, 25, 0.001) //falling balance5 = level.rotor(2605, 1020, 390, 25, 0.001) //falling } @@ -34957,8 +35023,8 @@ const level = { y: mob[k].velocity.y - 8 * Math.sin(angle) }); - if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && g.energy > 0.1 && mob[k].damageReduction > 0) { - g.energy -= 0.1 //* Math.max(g.maxEnergy, g.energy) //0.33 * g.energy + if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && g.energy > 0.08 && mob[k].damageReduction > 0) { + g.energy -= 0.08 //* Math.max(g.maxEnergy, g.energy) //0.33 * g.energy if (g.immuneCycle === g.cycle + g.collisionImmuneCycles) g.immuneCycle = 0; //genisis doesn't go immune to collision damage mob[k].death(); simulation.drawList.push({ //add dmg to draw queue diff --git a/js/mob.js b/js/mob.js index 30197db..df145f9 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1234,6 +1234,30 @@ const mobs = { m.energy -= 0.05; if (m.energy < 0) m.energy = 0 } + + + + if (tech.isRemineralize) { + //reduce mineral percent based on time since last check + const seconds = (simulation.cycle - tech.mineralLastCheck) / 60 + tech.mineralLastCheck = simulation.cycle + tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds); + tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds); + //apply mineral damage reduction + tech.mineralDamageReduction *= 0.85 + } + if (tech.isDemineralize) { + //reduce mineral percent based on time since last check + const seconds = (simulation.cycle - tech.mineralLastCheck) / 60 + tech.mineralLastCheck = simulation.cycle + tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds); + tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds); + //apply mineral damage + tech.mineralDamage *= 1.08 + } + + + powerUps.spawnRandomPowerUp(this.position.x, this.position.y); m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks() mobs.mobDeaths++ @@ -1253,9 +1277,11 @@ const mobs = { } else { for (let i = 0; i < amount; i++) b.spore(this.position) } - } else if (tech.isExplodeMob) { + } + if (tech.isExplodeMob) { b.explosion(this.position, Math.min(700, Math.sqrt(this.mass + 6) * (30 + 60 * Math.random()))) - } else if (tech.nailsDeathMob) { + } + if (tech.nailsDeathMob) { b.targetedNail(this.position, tech.nailsDeathMob, 39 + 6 * Math.random()) } if (tech.isBotSpawnerReset) { @@ -1269,7 +1295,7 @@ const mobs = { this.leaveBody = false; // no body since it turned into the bot } if (tech.isMobDeathImmunity) { - const immuneTime = 360 + const immuneTime = 300 if (m.immuneCycle < m.cycle + immuneTime) m.immuneCycle = m.cycle + immuneTime; //player is immune to damage } if (tech.isAddRemoveMaxHealth) { diff --git a/js/player.js b/js/player.js index 83d4a47..39a41bc 100644 --- a/js/player.js +++ b/js/player.js @@ -782,9 +782,9 @@ const m = { defense() { let dmg = 1 if (powerUps.boost.isDefense && powerUps.boost.endCycle > simulation.cycle) dmg *= 0.3 - if (tech.isMaxHealthDefense && m.health === m.maxHealth) dmg *= 0.2 + if (tech.isMaxHealthDefense && m.health === m.maxHealth) dmg *= 0.1 if (tech.isDiaphragm) dmg *= 0.55 + 0.35 * Math.sin(m.cycle * 0.0075); - if (tech.isZeno) dmg *= 0.15 + if (tech.isZeno) dmg *= 0.2 if (tech.isFieldHarmReduction) dmg *= 0.6 if (tech.isHarmDarkMatter) dmg *= (tech.isMoveDarkMatter || tech.isNotDarkMatter) ? 0.25 : 0.4 if (tech.isImmortal) dmg *= 0.7 @@ -795,12 +795,20 @@ const m = { if (tech.isHarmReduce && input.field) dmg *= 0.1 if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05 if (tech.isBotArmor) dmg *= 0.96 ** b.totalBots() - if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.3; + if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.4; if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3 if (tech.isTurret && m.crouch) dmg *= 0.3; if (tech.isFirstDer && b.inventory[0] === b.activeGun) dmg *= 0.85 ** b.inventory.length // if (tech.isLowHealthDefense) dmg *= Math.pow(0.3, Math.max(0, (tech.isEnergyHealth ? m.maxEnergy - m.energy : m.maxHealth - m.health))) if (tech.isLowHealthDefense) dmg *= Math.pow(0.2, Math.max(0, 1 - (tech.isEnergyHealth ? m.energy / m.maxEnergy : m.health / m.maxHealth))) + if (tech.isRemineralize) { + //reduce mineral percent based on time since last check + const seconds = (simulation.cycle - tech.mineralLastCheck) / 60 + tech.mineralLastCheck = simulation.cycle + tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds); + tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds); + dmg *= tech.mineralDamageReduction + } // return tech.isEnergyHealth ? Math.pow(dmg, 0.7) : dmg //defense has less effect // dmg *= m.fieldHarmReduction return dmg * m.fieldHarmReduction @@ -2736,10 +2744,10 @@ const m = { m.fieldThreshold = Math.cos((m.fieldArc) * Math.PI) }, setHoldDefaults() { - if (tech.isFreeWormHole && m.fieldMode !== 9) { //not wormhole - const removed = tech.removeTech("charmed baryon") //neutronum can get player stuck so it has to be removed if player has wrong field - if (removed) powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); - } + // if (tech.isFreeWormHole && m.fieldMode !== 9) { //not wormhole + // const removed = tech.removeTech("charmed baryon") //neutronum can get player stuck so it has to be removed if player has wrong field + // if (removed) powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); + // } if (tech.isNeutronium && m.fieldMode !== 3) { //not negative mass field const removed = tech.removeTech("neutronium") //neutronum can get player stuck so it has to be removed if player has wrong field if (removed) powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); @@ -2835,7 +2843,7 @@ const m = { } else if (m.fieldMode === 8) { m.fieldRegen = 0.001667 //10 energy per second pilot wave } else if (m.fieldMode === 9) { - m.fieldRegen = 0.00117 //7 energy per second wormhole + m.fieldRegen = 0.001334 //8 energy per second wormhole } else if (m.fieldMode === 10) { m.fieldRegen = 0.0015 //9 energy per second grappling hook } else { @@ -4011,14 +4019,14 @@ const m = { { name: "negative mass", //
hold blocks as if they have a lower mass - description: `use energy to nullify  gravity
0.4x damage taken
6 energy per second`, + description: `use energy to nullify  gravity
0.5x damage taken
6 energy per second`, fieldDrawRadius: 0, effect: () => { m.fieldFire = true; m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping m.fieldMeterColor = "#333" m.eyeFillColor = m.fieldMeterColor - m.fieldHarmReduction = 0.4; + m.fieldHarmReduction = 0.5; m.fieldDrawRadius = 0; m.hold = function () { @@ -4032,8 +4040,7 @@ const m = { if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); - const DRAIN = 0.00035 - if (m.energy > DRAIN && m.fieldCDcycle < m.cycle) { + if (m.energy > tech.negativeMassCost && m.fieldCDcycle < m.cycle) { if (tech.isFlyFaster) { //look for nearby objects to make zero-g function moveThis(who, range, mag = 1.06) { @@ -4065,13 +4072,13 @@ const m = { moveThis(powerUp, this.fieldDrawRadius, 0); moveThis(body, this.fieldDrawRadius, 0); } else if (input.up) { //up - m.energy -= 5 * DRAIN; + m.energy -= 5 * tech.negativeMassCost; this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 1100 * 0.03; player.force.y -= 2.25 * player.mass * simulation.g; moveThis(powerUp, this.fieldDrawRadius, 1.8); moveThis(body, this.fieldDrawRadius, 1.8); } else { - m.energy -= DRAIN; + m.energy -= tech.negativeMassCost; this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 800 * 0.03; player.force.y -= 1.07 * player.mass * simulation.g; // slow upward drift moveThis(powerUp, this.fieldDrawRadius); @@ -4109,13 +4116,13 @@ const m = { verticalForce(powerUp, this.fieldDrawRadius, 0.7); verticalForce(body, this.fieldDrawRadius, 0.7); } else if (input.up) { //up - m.energy -= 5 * DRAIN; + m.energy -= 5 * tech.negativeMassCost; this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 850 * 0.03; player.force.y -= 1.45 * player.mass * simulation.g; verticalForce(powerUp, this.fieldDrawRadius, 1.38); verticalForce(body, this.fieldDrawRadius, 1.38); } else { - m.energy -= DRAIN; + m.energy -= tech.negativeMassCost; this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 650 * 0.03; player.force.y -= 1.07 * player.mass * simulation.g; // slow upward drift verticalForce(powerUp, this.fieldDrawRadius); @@ -5051,7 +5058,7 @@ const m = { } } if (tech.isCloakStun) { //stun nearby mobs after exiting cloak - let isMobsAround = false + // let isMobsAround = false const stunRange = m.fieldDrawRadius * 1.25 // const drain = 0.01 // if (m.energy > drain) { @@ -5358,7 +5365,7 @@ const m = { { name: "wormhole", //wormholes attract blocks and power ups
- description: "use energy to tunnel through a wormhole
+8% chance to duplicate spawned power ups
7 energy per second", //
bullets may also traverse wormholes + description: "use energy to tunnel through a wormhole
+8% chance to duplicate spawned power ups
8 energy per second", //
bullets may also traverse wormholes drain: 0, effect: function () { m.fieldMeterColor = "#bbf" //"#0c5" @@ -5454,8 +5461,10 @@ const m = { if (tech.isWormholeWorms) { //pandimensional spermia b.worm(Vector.add(m.hole.pos2, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random()))) Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -10)); - // for (let i = 0, len = Math.ceil(1.25 * Math.random()); i < len; i++) { - // } + if (Math.random() < 0.5) { //chance for a second worm + b.worm(Vector.add(m.hole.pos2, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random()))) + Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -10)); + } } break } @@ -5475,13 +5484,12 @@ const m = { if ((m.fieldMode === 0 || m.fieldMode === 9) && m.immuneCycle < m.cycle) m.energy += 0.02 * m.coupling * level.isReducedRegen if (m.fieldMode === 0 || m.fieldMode === 9) m.energy += 0.02 * m.coupling * level.isReducedRegen if (tech.isWormholeWorms) { //pandimensional spermia - b.worm(Vector.add(m.hole.pos1, Vector.rotate({ - x: m.fieldRange * 0.4, - y: 0 - }, 2 * Math.PI * Math.random()))) + b.worm(Vector.add(m.hole.pos1, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random()))) Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 5)); - // for (let i = 0, len = Math.ceil(1.25 * Math.random()); i < len; i++) { - // } + if (Math.random() < 0.5) { //chance for a second worm + b.worm(Vector.add(m.hole.pos1, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random()))) + Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 5)); + } } break } @@ -6239,8 +6247,8 @@ const m = { y: mob[k].velocity.y - 8 * Math.sin(angle) }); - if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy) { - m.energy -= 0.33 * Math.max(m.maxEnergy, m.energy) + if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.08) { + m.energy -= 0.08 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy m.immuneCycle = 0; //player doesn't go immune to collision damage mob[k].death(); simulation.drawList.push({ //add dmg to draw queue diff --git a/js/powerup.js b/js/powerup.js index 213eb8d..b7722bc 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -256,6 +256,8 @@ const powerUps = { powerUps.endDraft(type); }, showDraft() { + simulation.isChoosing = true; //stops p from un pausing on key down + //disable clicking for 1/2 a second to prevent mistake clicks document.getElementById("choose-grid").style.pointerEvents = "none"; document.body.style.cursor = "none"; @@ -264,7 +266,6 @@ const powerUps = { document.getElementById("choose-grid").style.pointerEvents = "auto"; document.getElementById("choose-grid").style.transitionDuration = "0s"; }, 400); - simulation.isChoosing = true; //stops p from un pausing on key down if (!simulation.paused) { if (tech.isNoDraftPause || level.isNoPause) { @@ -909,7 +910,7 @@ const powerUps = { } }, cancelText(type) { - if (tech.isSuperDeterminism) { + if (tech.isSuperDeterminism || type === "constraint") { return `
` } else if (tech.isCancelTech && tech.cancelTechCount === 0) { return `
randomize
` @@ -940,7 +941,9 @@ const powerUps = { }, researchAndCancelText(type) { let text = `
` - if (type === "entanglement") { + if (type === "constraint") { + return + } else if (type === "entanglement") { text += `entanglement` } else if (tech.isJunkResearch && powerUps.research.currentRerollCount < 2) { text += `` // style = "margin-left: 192px; margin-right: -192px;" @@ -1008,6 +1011,12 @@ const powerUps = { return text }, hideStyle: `style="height:auto; border: none; background-color: transparent;"`, + constraintText(choose, click) { + return `
+
+
  ${m.fieldUpgrades[choose].name}
+ ${m.fieldUpgrades[choose].description}
` + }, gunText(choose, click) { const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/gun/${b.guns[choose].name}.webp');"` return `
@@ -1607,6 +1616,8 @@ const powerUps = { } } } + powerUps.spawn(x + 25, y - 25, "ammo", false); + if (simulation.difficultyMode > 5) powerUps.spawn(x - 25, y - 50, "ammo", false); if (tech.isAddRemoveMaxHealth) { powerUps.spawn(x + 20, y, "tech", false) powerUps.spawn(x - 20, y, "research", false) diff --git a/js/spawn.js b/js/spawn.js index 9b9f2a8..4f743bc 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1,6 +1,6 @@ //main object for spawning things in a level const spawn = { - nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"], + nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture", "snakeBoss"], // other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss, hopMotherBoss //these need a particular level to work so they are not included in the random pool randomBossList: [ "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", @@ -114,9 +114,9 @@ const spawn = { } } }, - secondaryBossChance(x, y) { + secondaryBossChance(x, y, options = []) { if (simulation.difficultyMode > 2 && level.levelsCleared > 1) { - spawn.randomLevelBoss(x, y); + spawn.randomLevelBoss(x, y, options); powerUps.spawn(x - 30, y, "ammo"); powerUps.spawn(x + 30, y, "ammo"); } else { @@ -3921,8 +3921,8 @@ const spawn = { } me.frictionStatic = 0; me.friction = 0; - me.memory = 240 - me.seePlayerFreq = 55 + me.memory = 900; + me.seePlayerFreq = 41 me.delay = 5 + 2 * simulation.CDScale;//8 + 3 * simulation.CDScale; me.nextBlinkCycle = me.delay; me.JumpDistance = 0//set in redMode() @@ -4082,21 +4082,18 @@ const spawn = { move() } else if (this.seePlayer.recall) { //chase player's history this.lostPlayer(); - if (!m.isCloak) { - for (let i = 0; i < 50; i++) { //if lost player lock onto a player location in history + if (m.isCloak) { + move(this.seePlayer.position) //go after where you last saw the player + } else { + for (let i = 0; i < 55; i++) { //if lost player lock onto a player location in history let history = m.history[(m.cycle - 10 * i) % 600] if (Matter.Query.ray(map, this.position, history.position).length === 0) { - this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep - this.seePlayer.position.x = history.position.x; - this.seePlayer.position.y = history.position.y; - this.seePlayer.yes = true; - move() + move(history.position) //go after where you last saw the player break } } } } - } this.checkStatus(); if (this.isInvulnerable) { @@ -4170,7 +4167,7 @@ const spawn = { me.fire = function () { // this.armor(); this.checkStatus(); - if (!m.isCloak && !this.isStunned) { + if (!this.isStunned) { if (this.isFiring) { if (this.fireCycle > this.fireDelay) { //fire this.isFiring = false @@ -4221,7 +4218,9 @@ const spawn = { } } else { //aim at player this.fireCycle++ - this.fireDir = Vector.normalise(Vector.sub(m.pos, this.position)); //set direction to turn to fire + //if cloaked, aim at player's history from 3 seconds ago + const whereIsPlayer = m.isCloak ? m.history[(m.cycle - 180) % 600].position : m.pos + this.fireDir = Vector.normalise(Vector.sub(whereIsPlayer, this.position)); //set direction to turn to fire //rotate towards fireAngle const angle = this.angle + Math.PI / 2; const c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; @@ -4233,7 +4232,7 @@ const spawn = { } else if (this.fireCycle > 45) { //fire unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100) this.fireTarget = Vector.add(this.vertices[1], unit) - if (Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur + if (Vector.magnitude(Vector.sub(whereIsPlayer, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur Matter.Body.setAngularVelocity(this, 0) this.fireLockCount = 0 this.isFiring = true @@ -4277,7 +4276,7 @@ const spawn = { }, Vector.normalise(Vector.sub(this.fireTarget, this.position))); //distance between the target and the player's location if ( - m.isCloak || + // m.isCloak || dot > 0.03 || // not looking at target Matter.Query.ray(map, this.fireTarget, this.position).length || Matter.Query.ray(body, this.fireTarget, this.position).length || //something blocking line of sight Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) > 1000 // distance from player to target is very far, (this is because dot product can't tell if facing 180 degrees away) @@ -5056,7 +5055,7 @@ const spawn = { me.laserSword = function (where, angle, length) { best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) }; - best = vertexCollision(where, look, m.isCloak ? [map] : [map, [playerBody, playerHead]]); + best = vertexCollision(where, look, [map, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -5663,7 +5662,7 @@ const spawn = { best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second @@ -5762,7 +5761,7 @@ const spawn = { me.laserSword = function (where, angle) { best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -5854,7 +5853,7 @@ const spawn = { me.laserSword = function (where, angle) { best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -5964,7 +5963,7 @@ const spawn = { me.laserSpear = function (where, angle) { best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead)) { this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player @@ -6180,7 +6179,7 @@ const spawn = { mobs.spawn(x, y, 7, radius, "transparent"); let me = mob[mob.length - 1]; me.seeAtDistance2 = 500000; - me.accelMag = 0.00007 + 0.0001 * simulation.accelScale; + me.accelMag = 0.0002 + 0.0001 * simulation.accelScale; if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search Matter.Body.setDensity(me, 0.0002); //normal is 0.001 me.damageReduction = 0.1 @@ -6222,7 +6221,7 @@ const spawn = { if (this.health < 0.8) me.seeAtDistance2 = 2000000; } me.do = function () { - if (this.speed > 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 0.8, y: this.velocity.y * 0.8 }); //cap max speed to avoid getting launched by deflection, explosion + if (this.speed > 6) Matter.Body.setVelocity(this, { x: this.velocity.x * 0.8, y: this.velocity.y * 0.8 }); //cap max speed to avoid getting launched by deflection, explosion this.seePlayerCheckByDistance(); this.checkStatus(); this.attraction(); @@ -7215,6 +7214,7 @@ const spawn = { me.do = function () { this.seePlayerByHistory(60); this.attraction(); + if (this.distanceToPlayer2() > 9000000) this.attraction(); //extra attraction if far away this.checkStatus(); this.eventHorizon = 950 + 250 * Math.sin(simulation.cycle * 0.005) if (!simulation.isTimeSkipping) { diff --git a/js/tech.js b/js/tech.js index 778fa1b..954987c 100644 --- a/js/tech.js +++ b/js/tech.js @@ -141,7 +141,7 @@ const tech = { if (tech.tech[index].isLost) tech.tech[index].isLost = false; //give specific tech if (tech.isBanish && tech.tech[index].isBanished) tech.tech[index].isBanished = false //stops the bug where you can't gets stacks of tech you take with decoherence, I think if (tech.isDamageFieldTech && tech.tech[index].isFieldTech) { - tech.damage *= 1.15 + tech.damage *= 1.2 // simulation.inGameConsole(`damage *= ${1.05}`) simulation.inGameConsole(`tech.damage *= ${1.1} //hidden-variable theory`); } @@ -273,7 +273,7 @@ const tech = { if (tech.isDamageCooldown) dmg *= m.lastKillCycle + tech.isDamageCooldownTime > m.cycle ? 0.4 : 4 if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 2 if (tech.isDivisor && b.activeGun !== undefined && b.activeGun !== null && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.9 - if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.9 : 2 + if (tech.offGroundDamage && !m.onGround) dmg *= tech.offGroundDamage if (tech.isDilate) dmg *= 1.9 + 1.1 * Math.sin(m.cycle * 0.01) if (tech.isGunChoice) dmg *= 1 + 0.4 * b.inventory.length if (powerUps.boost.endCycle > simulation.cycle) dmg *= 1 + powerUps.boost.damage @@ -294,11 +294,19 @@ const tech = { if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 if (tech.isSpeedDamage) dmg *= 1 + Math.min(2, ((tech.speedAdded + player.speed) * 0.033))//1 + Math.min(1, (tech.speedAdded + player.speed) * 0.0193) if (tech.isAxion && tech.isHarmDarkMatter) dmg *= ((tech.isMoveDarkMatter || tech.isNotDarkMatter) ? 3.2 : 2) - if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3; + if (tech.isHarmDamage && m.lastHarmCycle + 240 > m.cycle) dmg *= 4; if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit // if (tech.isLowHealthDmg) dmg *= 1 + 0.6 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health)) if (tech.isLowHealthDmg) dmg *= 1 + 0.6 * Math.max(0, (tech.isEnergyHealth ? m.maxEnergy - m.energy : m.maxHealth - m.health)) if (tech.isJunkDNA) dmg *= 1 + 2 * (tech.junkChance + level.junkAdded) + if (tech.isDemineralize) { + //reduce mineral percent based on time since last check + const seconds = (simulation.cycle - tech.mineralLastCheck) / 60 + tech.mineralLastCheck = simulation.cycle + tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds); + tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds); + dmg *= tech.mineralDamage + } return dmg }, duplicationChance() { @@ -430,7 +438,7 @@ const tech = { }, { name: "Hilbert space", - description: "4x damage
after a collision enter an alternate reality", + description: "3x damage
after a collision enter an alternate reality", maxCount: 1, count: 0, frequency: 1, @@ -441,7 +449,7 @@ const tech = { return !m.isAltSkin && !tech.isResearchReality && !tech.isSwitchReality }, requires: "not skinned, Ψ(t) collapse, many-worlds", - damage: 4, + damage: 3, effect() { m.skin.anodize(); tech.damage *= this.damage @@ -549,8 +557,8 @@ const tech = { }, maxCount: 1, count: 0, - frequency: 5, - frequencyDefault: 5, + frequency: 4, + frequencyDefault: 4, allowed() { return tech.isEnergyHealth && !tech.isOverHeal }, @@ -781,7 +789,7 @@ const tech = { { name: "pigeonhole principle", descriptionFunction() { - return `1.4x damage per ${powerUps.orb.gun()}, but your equipped ${powerUps.orb.gun()}
cycles each level and you can't switch` + return `1.4x damage per ${powerUps.orb.gun()}, but your active ${powerUps.orb.gun()}
cycles each level and you can't switch` }, // descriptionFunction() { // let info = "" @@ -1010,7 +1018,7 @@ const tech = { { name: "Pareto efficiency", descriptionFunction() { - return `for each ${powerUps.orb.gun()} in your inventory
randomly get 5x or 0.2x ammo per ${powerUps.orb.ammo(1)}` + return `all you ${powerUps.orb.gun()} randomly get
5x or 0.2x ammo per ${powerUps.orb.ammo(1)}` }, maxCount: 1, count: 0, @@ -1395,6 +1403,64 @@ const tech = { tech.isCrit = false; } }, + { + name: "remineralization", + descriptionFunction() { + //reduce mineral percent based on time since last check + const seconds = (simulation.cycle - tech.mineralLastCheck) / 60 + tech.mineralLastCheck = simulation.cycle + tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds); + tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds); + + return `after mobs die gain 0.85x damage taken
effects stack, but fade 10% every second(${tech.mineralDamageReduction.toFixed(2)}x)` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { return true }, + requires: "", + effect() { + tech.isRemineralize = true + tech.mineralDamageReduction = 1 + tech.mineralLastCheck = simulation.cycle + }, + remove() { + tech.isRemineralize = false + tech.mineralDamageReduction = 1 + tech.mineralLastCheck = simulation.cycle + } + }, + { + name: "demineralization", + descriptionFunction() { + //reduce mineral percent based on time since last check + const seconds = (simulation.cycle - tech.mineralLastCheck) / 60 + tech.mineralLastCheck = simulation.cycle + tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds); + tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds); + + return `after mobs die gain 1.08x damage
effects stack, but fade 10% every second(${tech.mineralDamage.toFixed(2)}x)` + }, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return true + }, + requires: "", + effect() { + tech.isDemineralize = true + tech.mineralDamage = 1 + tech.mineralLastCheck = simulation.cycle + }, + remove() { + tech.isDemineralize = false + tech.mineralDamage = 1 + tech.mineralLastCheck = simulation.cycle + } + }, { name: "shear stress", description: "after mobs die
they fire a nail at nearby mobs", @@ -1403,9 +1469,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath + return true }, - requires: "no other mob death tech", + requires: "", effect() { tech.nailsDeathMob++ }, @@ -1421,9 +1487,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath + return true }, - requires: "no other mob death tech", + requires: "", effect() { tech.isExplodeMob = true; }, @@ -1437,22 +1503,16 @@ const tech = { descriptionFunction() { return `after mobs die there is a 13% chance
they grow ${b.guns[6].nameString('s')}` }, - // description: "after mobs die
they have a +10% chance to grow spores", maxCount: 9, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return !tech.nailsDeathMob && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath + return true }, - requires: "no other mob death tech", + requires: "", effect() { tech.sporesOnDeath += 0.13; - // if (tech.isSporeWorm) { - // for (let i = 0; i < 4; i++) b.worm(m.pos) - // } else { - // for (let i = 0; i < 8; i++) b.spore(m.pos) - // } }, remove() { tech.sporesOnDeath = 0; @@ -2658,7 +2718,7 @@ const tech = { { name: "non-Newtonian armor", link: `non-Newtonian armor`, - description: "after mob collisions
0.3x damage taken for 10 seconds", + description: "after mob collisions
0.4x damage taken for 10 seconds", maxCount: 1, count: 0, frequency: 1, @@ -2735,7 +2795,7 @@ const tech = { }, { name: "fermion", - description: `for 6 seconds after mobs die
become invulnerable and inhibit energy regen`, + description: `for 5 seconds after mobs die
become invulnerable and inhibit energy regen`, maxCount: 1, count: 0, frequency: 1, @@ -3066,7 +3126,7 @@ const tech = { { name: "stability", descriptionFunction() { - return `0.2x damage taken
while your health is at maximum` + return `0.1x damage taken
while your health is at maximum` }, maxCount: 1, count: 0, @@ -3168,7 +3228,7 @@ const tech = { { name: "Zenos paradox", descriptionFunction() { - return `0.15x damage taken
–5% of current ${tech.isEnergyHealth ? "energy" : "health"} every 5 seconds` + return `0.2x damage taken
–5% of current ${tech.isEnergyHealth ? "energy" : "health"} every 5 seconds` }, maxCount: 1, count: 0, @@ -3576,7 +3636,7 @@ const tech = { { name: "Ψ(t) collapse", link: `Ψ(t) collapse`, - description: `after a boss dies spawn ${powerUps.orb.research(6)}
if you research enter an alternate reality`, + description: `after a boss dies spawn ${powerUps.orb.research(4)}
if you research enter an alternate reality`, maxCount: 1, count: 0, frequency: 1, @@ -5812,7 +5872,7 @@ const tech = { }, { name: "launch system", - description: `5x missile fire rate
1.2x missile ammo per ${powerUps.orb.ammo(1)}`, + description: `5x missile fire rate
1.3x missile ammo per ${powerUps.orb.ammo(1)}`, isGunTech: true, maxCount: 1, count: 0, @@ -5822,7 +5882,7 @@ const tech = { return tech.haveGunCheck("missiles") && !tech.isMissileBig }, requires: "missiles, not cruise missile", - ammoBonus: 1.2, + ammoBonus: 1.3, effect() { tech.missileFireCD = 10 for (i = 0, len = b.guns.length; i < len; i++) { //find which gun @@ -7898,7 +7958,7 @@ const tech = { { name: "radiative equilibrium", descriptionFunction() { - return `after losing ${tech.isEnergyHealth ? "energy" : "health"}
3x damage for 8 seconds` + return `after losing ${tech.isEnergyHealth ? "energy" : "health"}
4x damage for 4 seconds` }, isFieldTech: true, maxCount: 1, @@ -7925,13 +7985,13 @@ const tech = { maxCount: 3, count: 0, frequency: 2, - frequencyDefault: 200, + frequencyDefault: 2, allowed() { return m.fieldMode === 8 || m.fieldMode === 3 }, requires: "negative mass, pilot wave", effect() { - tech.lastHitDamage += 6; + tech.lastHitDamage += 8; }, remove() { tech.lastHitDamage = 0; @@ -7946,9 +8006,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return m.fieldMode === 3 + return m.fieldMode === 3 && tech.negativeMassCost !== 0 }, - requires: "negative mass", + requires: "negative mass, not equivalence principle", effect() { tech.isNeutronium = true tech.baseFx *= 0.86 @@ -7966,29 +8026,51 @@ const tech = { } }, { - name: "aerostat", - descriptionFunction() { - return `2x damage while off the ground
0.9x damage while on the ground(${(m.onGround ? 0.9 : 2).toFixed(1)}x)` - }, + name: "equivalence principle", + description: `negative mass field doesn't cost energy
`, isFieldTech: true, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, + allowed() { + return m.fieldMode === 3 && !tech.isNeutronium + }, + requires: "negative mass, not neutronium", + effect() { + tech.negativeMassCost = 0 + }, + //also removed in m.setHoldDefaults() if player switches into a bad field + remove() { + tech.negativeMassCost = 0.00035 + } + }, + { + name: "aerostat", + descriptionFunction() { + const damage = m.onGround ? 1 : (tech.offGroundDamage) + const infoText = this.count ? `
(${damage.toFixed(0)}x)` : "" + return `2x damage while off the ground${infoText}` + }, + isFieldTech: true, + maxCount: 3, + count: 0, + frequency: 2, + frequencyDefault: 2, allowed() { return m.fieldMode === 3 || m.fieldMode === 10 }, requires: "negative mass, grappling hook", effect() { - tech.isNoGroundDamage = true + tech.offGroundDamage++ }, remove() { - tech.isNoGroundDamage = false + tech.offGroundDamage = 1 } }, { name: "annihilation", - description: "after colliding with non-boss mobs
they are annihilated and –10 energy", + description: "mobs you collide with are annihilated
–8 energy each time", isFieldTech: true, maxCount: 1, count: 0, @@ -8723,12 +8805,12 @@ const tech = { }, { name: "hidden-variable theory", - description: `1.15x damage each time you choose ${powerUps.orb.fieldTech()}`, + description: `1.2x damage after you choose ${powerUps.orb.fieldTech()}`, isFieldTech: true, maxCount: 1, count: 0, - frequency: 1, - frequencyDefault: 1, + frequency: 4, + frequencyDefault: 4, allowed() { return m.fieldMode === 8 }, @@ -8742,7 +8824,7 @@ const tech = { }, { name: "WIMPs", - description: `at each level's exit, spawn ${powerUps.orb.research(4)}
and a dangerous particle that slowly chases you`, + description: `at the exit to each level spawn ${powerUps.orb.research(4)}
and a dangerous particle that slowly chases you`, isFieldTech: true, maxCount: 9, count: 0, @@ -8770,9 +8852,9 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2) + return (m.fieldMode === 8 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2) }, - requires: "wormhole, time dilation, negative mass, pilot wave", + requires: "wormhole, pilot wave", effect() { tech.fieldDuplicate = 0.11 powerUps.setPowerUpMode(); //needed after adjusting duplication chance @@ -8792,7 +8874,7 @@ const tech = { { name: "transdimensional worms", link: `transdimensional worms`, - description: "after a block falls into a wormhole
spawn a worm", + description: "after a block falls into a wormhole
spawn 1-2 worms", isFieldTech: true, maxCount: 1, count: 0, @@ -8812,7 +8894,7 @@ const tech = { { name: "anyon", descriptionFunction() { - return `2x energy after duplicating a power up
+6% chance to duplicate spawned power ups` + return `2x stored energy after duplicating power ups
+6% chance to duplicate spawned power ups` }, isFieldTech: true, maxCount: 1, @@ -8903,35 +8985,44 @@ const tech = { }, { name: "holographic principle", - description: `0.8x movement and jumping
wormholes cost zero energy`, + cost: 2, + descriptionFunction() { + return `use ${powerUps.orb.research(this.cost)}
making wormholes doesn't cost energy` + }, isFieldTech: true, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return m.fieldMode === 9 && !tech.isWormholeMapIgnore + return m.fieldMode === 9 && !tech.isWormholeMapIgnore && (build.isExperimentSelection || powerUps.research.count > this.cost - 1) }, requires: "wormhole, not affine connection", effect() { + for (let i = 0; i < this.cost; i++) { + if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) + } tech.isFreeWormHole = true - tech.baseFx *= 0.8 - tech.baseJumpForce *= 0.8 - m.setMovement() + // tech.baseFx *= 0.8 + // tech.baseJumpForce *= 0.8 + // m.setMovement() }, //also removed in m.setHoldDefaults() if player switches into a bad field remove() { tech.isFreeWormHole = false - if (!tech.isNeutronium) { - tech.baseFx = 0.08 - tech.baseJumpForce = 10.5 - m.setMovement() + if (this.count) { + powerUps.research.changeRerolls(this.cost) } + // if (!tech.isNeutronium) { + // tech.baseFx = 0.08 + // tech.baseJumpForce = 10.5 + // m.setMovement() + // } } }, { name: "affine connection", - description: "wormholes can tunnel through anything
for 2x energy cost", + description: "wormholes can tunnel through anything
2x energy cost going through solids", isFieldTech: true, maxCount: 1, count: 0, @@ -10459,9 +10550,22 @@ const tech = { requires: "", effect() { setInterval(() => { + const unit = { + x: 1, + y: 0 + } + for (let i = 0; i < 5; i++) { + const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 2000 * Math.random())) + spawn.sucker(where.x, where.y, 140) + const who = mob[mob.length - 1] + who.locatePlayer() + // who.damageReduction = 0.2 + } + m.switchWorlds() simulation.trails() - }, 20000); //every 30 seconds + + }, 20000); //every 20 seconds }, remove() { } }, @@ -10485,6 +10589,26 @@ const tech = { }, remove() { } }, + { + name: "aerodynamics", + description: "reduce air friction for all power ups", + maxCount: 1, + count: 0, + frequency: 0, + isInstant: true, + isJunk: true, + allowed() { + return true + }, + requires: "", + effect() { + const styleEl = document.createElement('style'); + document.head.appendChild(styleEl); + const myStyle = styleEl.sheet; + myStyle.insertRule(".choose-grid-no-images {border-radius: 50%;}", 0); + }, + remove() { } + }, { name: "pop-ups", description: "sign up to learn endless easy ways to win n-gon
that Landgreen doesn't want you to know!!!1!!", @@ -12204,7 +12328,7 @@ const tech = { collidePowerUps: null, isDilate: null, isDiaphragm: null, - isNoGroundDamage: null, + offGroundDamage: null, isSuperBounce: null, isDivisor: null, isFoamCavitation: null, @@ -12236,4 +12360,9 @@ const tech = { isWiki: null, isStaticBlock: null, isDamageFieldTech: null, + isRemineralize: null, + mineralDamageReduction: null, + isDemineralize: null, + mineralDamage: null, + negativeMassCost: null, } \ No newline at end of file diff --git a/style.css b/style.css index 9b15685..b72325c 100644 --- a/style.css +++ b/style.css @@ -746,6 +746,18 @@ summary { background-color: rgba(255, 255, 255, 0.4); } +.constraint-module { + line-height: 160%; + padding: 20px; + border-radius: 5px; + font-size: 1.2em; + font-family: monospace; + font-weight: 800; + text-align: center; + color: #624; + background-color: rgba(255, 240, 250, 1); +} + #right-HUD-constraint { position: absolute; top: 12px; @@ -768,6 +780,39 @@ summary { transition: all 0.5s linear; } +.constraint { + color: rgb(141, 23, 88); +} + +.metallic-sparkle { + background: linear-gradient(90deg, + #c38aa6, + #e6c0d9, + #dca4c6, + #c38aa6, + #e6c0d9, + #dca4c6, + #c38aa6); + background-size: 200% 100%; + background-clip: text; + color: transparent; + animation: shimmer 4s infinite linear; +} + +@keyframes shimmer { + 0% { + background-position: 0% 50%; + } + + 50% { + background-position: 100% 50%; + } + + 100% { + background-position: 0% 50%; + } +} + #text-log { z-index: 2; position: absolute; @@ -783,12 +828,6 @@ summary { user-select: none; } -.constraint { - color: rgb(141, 23, 88); - /* font-weight: 100; */ - /* text-decoration: underline; */ -} - .color-text { color: #000; } diff --git a/todo.txt b/todo.txt index 7d47bf9..2802010 100644 --- a/todo.txt +++ b/todo.txt @@ -1,42 +1,65 @@ ******************************************************** NEXT PATCH ************************************************** -new level corridor - new level element fizzler - it removes blocks -interferometer has wider platforms, a few helpful blocks, and fewer mobs -level constraints are announced in console +tech: demineralization - after mobs die gain 0.85x damage taken, effect stacks, but fades 10% every second +tech: remineralization - after mobs die gain 1.08x damage, effect stacks, but fades 10% every second +tech: equivalence principle - negative mass field doesn't cost energy +new JUNK tech: aerodynamics -foam gun no longer pushes the player back when firing -wave gun buffs - 1.2x base damage - 1.1x base ammo - 0.1->0.13x speed in map - 0.25->0.30x speed in blocks - tech: phase velocity 1.4->1.5x damage -pigeonhole principle gives 1.3->1.4 damage per gun - you can no longer switch guns, your gun cycles each level -quenching 0.4->0.5x overheal converts into max health -tungsten carbide no longer has reduced coyote cycles -control theory 1.5->2x damage at max health -stability 0.3->0.2 damage taken at max health -overcharge +88->100 max energy, 4->5% JUNK -zoospore vector 10->13% chance for spores on mob death -replication 15->10% JUNK -interest 6->5% of your power ups spawn each level +interferometer + slower elevator and lasers + wider side ledges + large laser blocking blocks +flocculation + fewer mobs + it's easier to get out of the slime +pavilion + move vanish elements + easier traversal + secret tunnel + removed debris, but added power ups and blocks +corridor + limited to bosses that don't interact with the movers poorly +gravitron, substructure, corridor, interferometer + added more heal and ammo power ups to match other levels +because some newer levels are zoomed out more + laser max range is 3000->5000 + nails last 1/3 of a second longer +bosses spawn an extra ammo power up + and 2 extra ammo on the hardest 2 difficulties +slasher mob's laserSwords will now damage a cloaked player +constraint announcement text looks more like computer code style to match game theme -updated "about" details menu - moved classic n-gon to here from settings - added links to community content in "about" - Are there more links I should add? - added an n-gon SVG head image +foam recoil is back: 1->0.7x horizontal force and 2->4.3x vertical up force + this makes it less annoying to horizontally and easier to kinda fly/float +negative mass field damage reduction 0.4->0.5x +holographic principle no longer slows player movement + added 2 research cost +fermion gives 6->5 seconds of invulnerability after mobs die +stability 0.2->0.1x damage taken at max health +non-Newtonian armor 0.3->0.4x damage taken after collisions +Zeno's paradox 0.15->0.2x damage taken +annihilation energy cost 10->8 to destroy mobs after collisions +radiative equilibrium damage is 3->4x for 8->4 seconds +aerostat can be taken 1->3 times +dynamic equilibrium damage increased by 6->8x damage per last damage taken +aerostat no longer has 0.9x damage for being on the ground +launch system 1.2->1.3x ammo for missiles +research says that repeatedly entering alternate realities builds up some positive effects + Hilbert space 4x->3x damage + Ψ(t) collapse 6->4 research on boss death +transdimensional worms: 50% chance for a second worm per block in wormhole +wormhole 7->8 energy regen per second +hidden-variable theory 1.15->1.2 damage after choosing a field tech +ghoster mobs are less likely to get knocked far away from the player for long periods of time -bugs - fixed outline on splash screen doesn't sync right on safari browser - fixed possible lock out on training levels: "hold", "throw", "throwAt" - from losing block behind a door - shortcut sort buttons in experiment mode properly order tech without clicking sort - fixed/increased the horizontal velocity contribution for some guns - this makes bullets shot on moving platforms more realistic - nail gun, super balls, foam, harpoon +bug fixes + dynamic equilibrium was set to 100 times higher frequency then normal + when constraints hide health bar's it's now hidden in the pause menu + mobs aiming at cloaked player + snakeBoss more intelligently chases player for a few seconds + pulsarBoss aims at player's history 3 seconds in past + pulsar will not stop firing + but it will still not fire at cloaked player ******************************************************** BUGS ******************************************************** @@ -59,14 +82,20 @@ player can become crouched while not touching the ground if they exit the ground *********************************************************** TODO ***************************************************** -tech: demineralization - 0.2x damage taken, but it slowly reduces effect - increase to full: - at start of level? - when you get the tech - decrease: - over time - at start of new level +tech synergy ideas + a tech that spawns mobs that the player can use to trigger mob death tech +wormhole field needs a buff + it's good on wide open maps, but it needs a defensive effect on more closed maps + fix? + increase energy regen? + new tech? + a way to make more blocks + the block can feed into worms/coupling energy + + +tech: - remove the research costs of all tech + there's about 15 tech with a research cost !!conformal - similar rules for small and big scales linked to holographic principle !!holonomy - parallel transport of a vector leads to movement (applies to curved space) when far away from your wormhole regenerate 1% of your max energy per second @@ -179,6 +208,31 @@ improve new player experience When foam is in an explosion it also explodes with size proportional to the size of the foam bubble Requires foam, explosion source, not aerogel +new level similar to ash tray maze + !!not sure how this works with theme (most levels are locations that have industrial stuff) + this might work as another line of sight level? + could be fine without line of sight if rooms don't exist until they open up? + where to put in game sequence? + watch a run through https://www.youtube.com/watch?v=nudSXUMBEV4 + close off doors as player gets close + open up doors as player gets close + holes in the floor + slide large walls back to open up levels below + show a zone, then close it off, but eventually reveal it later + rise up pillars during combat + small maze rooms, 1-2 really huge rooms, long corridors, medium combat rooms + triggers for changes + clearing mobs in a zone + or time based if player is too slow + player gets close to a zone + make map elements shift around as player moves through the game + start with map elements filling everywhere and slow open up new zones + need a cool way to animate adding and removing map elements + maybe for the entire level redraw the map every 15 cycles? + simulation.draw.setPaths() //update map graphics + slide map around + small map squares that each add in sequentially + Cosmological natural selection: do something with black holes spawn black hole mobs after bosses die? @@ -1210,7 +1264,6 @@ possible names for tech amalgam, amalgamation - the action, process, or result of combining or uniting. thermoplastic - the stuff in 3-D printers, use for molecular assembler tech ergosphere - region of a spinning black hole that might allow FTL or alternate realities. - equivalence principle - gravity and acceleration are the same Casimir effect - attractive force between two close conductive plates difference engine - early calculator/computer cyanoacrylate - superglue use for a slowing effect? @@ -1254,25 +1307,4 @@ list of powerful synergies interest + coupling, research + (peer review? or Bayesian statistics) electronegativity and high energy? electronegativity + anyon + duplication + Maxwells demon + interest + pair production - chain reaction + invulnerable + Abelian group + parasitism = clear all mobs on level - - -************************************************* COMMUNITY LINKS ************************************************* - -load old commits - www.cornbread2100.com/n-gon-loader - -n-gon fork - kgurchiek.github.io/n-gon-portal-gun - 3xiondev.github.io/n-gon-upgraded - coaldeficit.github.io/c-gon - n-gon-enhanced.vercel.app - -bookmarlet - github.com/Whyisthisnotavalable/n-scythe - github.com/kgurchiek/n-gon-mobile - github.com/kgurchiek/n-gon-controller - -text - ngon.fandom.com/wiki/N-gon - github.com/3xionDev/n-docs \ No newline at end of file + chain reaction + invulnerable + Abelian group + parasitism = clear all mobs on level \ No newline at end of file