From 59085ef2af4614265cffff0ee7c1b23e1522534c Mon Sep 17 00:00:00 2001 From: landgreen Date: Sat, 2 Jul 2022 16:47:19 -0700 Subject: [PATCH] iridescence tech: iridescence - laser does 100% damage to mobs hit near their center tech: lens - laser does extra damage if you fire through a lens that revolves around you tech: arc length - increase the size of the lens virtual particles costs 4->6 research for 11% duplication quantum eraser has less duplication chance at higher difficulty modes community map temple updates bug fixes --- js/bullet.js | 118 ++-- js/level.js | 1512 +++++++++++++++++++++++++++++++++++++++++++++++--- js/player.js | 4 +- js/tech.js | 190 ++++--- todo.txt | 43 +- 5 files changed, 1672 insertions(+), 195 deletions(-) diff --git a/js/bullet.js b/js/bullet.js index 57878ad..b6eb1df 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -2384,18 +2384,30 @@ const b = { }; const laserHitMob = function() { if (best.who.alive) { - best.who.damage(damage); best.who.locatePlayer(); if (best.who.damageReduction) { - simulation.drawList.push({ //add dmg to draw queue - x: path[path.length - 1].x, - y: path[path.length - 1].y, - // radius: Math.sqrt(damage) * 100 * mob[k].damageReduction, - // radius: 600 * damage * best.who.damageReduction, - radius: Math.sqrt(2000 * damage * best.who.damageReduction) + 2, - color: tech.laserColorAlpha, - time: simulation.drawTime - }); + if ( //crit + tech.laserCrit && !best.who.shield && + Vector.dot(Vector.normalise(Vector.sub(best.who.position, path[path.length - 1])), Vector.normalise(Vector.sub(path[path.length - 1], path[path.length - 2]))) > 0.99 - 0.6 / best.who.radius + ) { + damage *= 2 + simulation.drawList.push({ //add dmg to draw queue + x: path[path.length - 1].x, + y: path[path.length - 1].y, + radius: Math.sqrt(2500 * damage * best.who.damageReduction) + 5, + color: `hsla(${60 + 283*Math.random()},100%,70%,0.5)`, // random hue, but not red + time: 16 + }); + } else { + simulation.drawList.push({ //add dmg to draw queue + x: path[path.length - 1].x, + y: path[path.length - 1].y, + radius: Math.sqrt(2000 * damage * best.who.damageReduction) + 2, + color: tech.laserColorAlpha, + time: simulation.drawTime + }); + } + best.who.damage(damage); } if (tech.isLaserPush) { //push mobs away const index = path.length - 1 @@ -3878,7 +3890,7 @@ const b = { 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 if (tech.isNailCrit) { - if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 2 / who.radius) { + if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { b.explosion(this.position, 150 + 30 * Math.random()); //makes bullet do explosive damage at end } } @@ -3912,7 +3924,7 @@ const b = { } if (!immune) { if (tech.isNailCrit) { - if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 2 / who.radius) { + if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { b.explosion(this.position, 220 + 50 * Math.random()); //makes bullet do explosive damage at end } } else if (tech.isCritKill) b.crit(who, this) @@ -3970,7 +3982,7 @@ const b = { } if (!immune) { if (tech.isNailCrit) { - if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 2 / who.radius) { + if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { b.explosion(this.position, 220 + 50 * Math.random()); //makes bullet do explosive damage at end } } else if (tech.isCritKill) b.crit(who, this) @@ -5117,7 +5129,7 @@ const b = { b.explosion(this.position, 100 + (Math.random() - 0.5) * 20); //makes bullet do explosive damage at end } if (tech.isNailCrit) { - if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 2 / who.radius) { + if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { b.explosion(this.position, 300 + 40 * Math.random()); //makes bullet do explosive damage at end } } else if (tech.isCritKill) b.crit(who, this) @@ -5203,7 +5215,7 @@ const b = { b.explosion(this.position, 100 + (Math.random() - 0.5) * 20); //makes bullet do explosive damage at end } if (tech.isNailCrit) { - if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 2 / who.radius) { + if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { b.explosion(this.position, 300 + 40 * Math.random()); //makes bullet do explosive damage at end } } else if (tech.isCritKill) b.crit(who, this) @@ -5292,7 +5304,7 @@ const b = { mobs.statusSlow(who, 60) if (tech.isNailRadiation) mobs.statusDoT(who, 1 * (tech.isFastRadiation ? 1.3 : 0.44), tech.isSlowRadiation ? 360 : (tech.isFastRadiation ? 60 : 180)) // one tick every 30 cycles if (tech.isNailCrit) { - if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 2 / who.radius) { + if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { b.explosion(this.position, 150 + 30 * Math.random()); //makes bullet do explosive damage at end } } @@ -7009,19 +7021,52 @@ const b = { have: false, charge: 0, isStuckOn: false, + angle: 0, + arcRange: 0.78, //1.57, + isInsideArc(angle) { + const mod = (a, n) => { + return a - Math.floor(a / n) * n + } + let diff = mod(angle - this.angle + Math.PI, 2 * Math.PI) - Math.PI + return Math.abs(diff) < this.arcRange + }, + lensDamage: 1, + lens() { + this.stuckOn(); + this.angle += 0.02 + if (this.isInsideArc(m.angle)) { + this.lensDamage = 2.5 //150% damage increase + } else { + this.lensDamage = 1 + } + + const radius = 60 + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, radius, this.angle - this.arcRange, this.angle + this.arcRange); + ctx.strokeStyle = '#fff' //'rgba(255,255,255,0.9)' //'hsl(189, 100%, 95%)' //tech.laserColor + ctx.lineWidth = (this.lensDamage > 1) ? 10 : 2 //3 + ctx.stroke(); + // const a = { x: radius * Math.cos(this.angle + this.arcRange), y: radius * Math.sin(this.angle + this.arcRange) } + // const b = Vector.add(m.pos, a) + // ctx.lineTo(b.x, b.y) + // ctx.fillStyle = '#fff' + // ctx.fill() + }, + stuckOn() { + if (tech.isStuckOn) { + if (this.isStuckOn) { + if (!input.fire) this.fire(); + if (m.energy < tech.laserFieldDrain * tech.isLaserDiode) this.isStuckOn = false + } else if (input.fire) { + this.isStuckOn = true + } + } + }, do() {}, fire() {}, chooseFireMethod() { - this.do = () => { - if (tech.isStuckOn) { - if (this.isStuckOn) { - if (!input.fire) this.fire(); - if (m.energy < tech.laserFieldDrain * tech.isLaserDiode) this.isStuckOn = false - } else if (input.fire) { - this.isStuckOn = true - } - } - }; + this.lensDamage = 1 + if (tech.isLaserLens) this.do = this.lens if (tech.isPulseLaser) { this.fire = () => { const drain = 0.01 * tech.isLaserDiode * (tech.isCapacitor ? 10 : 1) @@ -7037,6 +7082,7 @@ const b = { const len = 1 + tech.historyLaser const spacing = Math.ceil(30 - 2 * tech.historyLaser) this.do = () => { + if (tech.isLaserLens) this.lens() if (this.charge > 0) { //draw charge level const mag = 4.1 * Math.sqrt(this.charge) @@ -7056,7 +7102,7 @@ const b = { for (let i = 0; i < len; i++) { const history = m.history[(m.cycle - i * spacing) % 600] const off = history.yOff - 24.2859 - b.pulse(1.65 * this.charge, history.angle, { x: history.position.x, y: history.position.y - off }) + b.pulse(1.65 * this.charge * this.lensDamage, history.angle, { x: history.position.x, y: history.position.y - off }) } } this.charge = 0; @@ -7065,6 +7111,7 @@ const b = { }; } else { this.do = () => { + if (tech.isLaserLens) this.lens() if (this.charge > 0) { //draw charge level ctx.beginPath(); @@ -7081,7 +7128,7 @@ const b = { const angle = m.angle - tech.beamSplitter * divergence / 2 for (let i = 0; i < 1 + tech.beamSplitter; i++) b.pulse(this.charge, angle + i * divergence) } else { - b.pulse(1.8 * this.charge, m.angle) + b.pulse(1.8 * this.charge * this.lensDamage, m.angle) } } this.charge = 0; @@ -7118,12 +7165,10 @@ const b = { b.laser(where, { x: where.x + 3000 * Math.cos(m.angle), y: where.y + 3000 * Math.sin(m.angle) - }, tech.laserDamage / b.fireCDscale); + }, tech.laserDamage / b.fireCDscale * this.lensDamage); } }, - firePulse() { - - }, + firePulse() {}, fireSplit() { if (m.energy < tech.laserFieldDrain) { m.fireCDcycle = m.cycle + 100; // cool down if out of energy @@ -7133,7 +7178,7 @@ const b = { // const divergence = input.down ? 0.15 : 0.2 // const scale = Math.pow(0.9, tech.beamSplitter) // const pushScale = scale * scale - let dmg = tech.laserDamage / b.fireCDscale // * scale //Math.pow(0.9, tech.laserDamage) + let dmg = tech.laserDamage / b.fireCDscale * this.lensDamage // * 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) @@ -7166,7 +7211,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 / b.fireCDscale // 3.5 * 0.55 = 200% more damage + const dmg = 0.70 * tech.laserDamage / b.fireCDscale * this.lensDamage // 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), @@ -7177,6 +7222,9 @@ const b = { ctx.globalAlpha = 0.5; ctx.beginPath(); if (Matter.Query.ray(map, eye, where).length === 0 && Matter.Query.ray(body, eye, where).length === 0) { + // this.isInsideArc(m.angle) ? 8 : 3 + + //where = {x: m.pos.x + 20 * Math.cos(m.angle),y: m.pos.y + 20 * Math.sin(m.angle)}, whereEnd = {x: where.x + 3000 * Math.cos(m.angle),y: where.y + 3000 * Math.sin(m.angle)}, dmg = tech.laserDamage, reflections = tech.laserReflections, isThickBeam = false, push = 1) { b.laser(eye, { x: eye.x + range.x, y: eye.y + range.y @@ -7218,7 +7266,7 @@ const b = { } else { m.fireCDcycle = m.cycle 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 dmg = 0.4 * tech.laserDamage / b.fireCDscale * this.lensDamage // 3.5 * 0.55 = 200% more damage const spacing = Math.ceil(4 - 0.3 * tech.historyLaser) ctx.beginPath(); b.laser({ diff --git a/js/level.js b/js/level.js index 3652ca9..93aa7ec 100644 --- a/js/level.js +++ b/js/level.js @@ -17,19 +17,18 @@ const level = { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.isHorizontalFlipped = true // m.addHealth(Infinity) - // m.setField("metamaterial cloaking") - // b.giveGuns("matter wave") - // b.giveGuns("shotgun") + // m.setField("time dilation") + // b.giveGuns("laser") // b.guns[0].ammo = 10000 // // b.giveGuns("mine") - // tech.giveTech("phonon") - // for (let i = 0; i < 3; ++i) tech.giveTech("smelting") + // tech.giveTech("lens") + // for (let i = 0; i < 2; ++i) tech.giveTech("diffraction grating") // for (let i = 0; i < 9; ++i) tech.giveTech("propagator") // for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot") // for (let i = 0; i < 9; ++i) tech.giveTech("emergence") - // tech.giveTech("resonance") - // tech.giveTech("microtransactions") - // tech.giveTech("cross disciplinary") + // tech.giveTech("laser-bot") + // tech.giveTech("slow light") + // tech.giveTech("iridescence") // m.maxHealth = 100 // m.health = m.maxHealth // for (let i = 0; i < 10; i++) tech.giveTech("tungsten carbide") @@ -41,13 +40,15 @@ const level = { // tech.tech[297].frequency = 100 // m.immuneCycle = Infinity //you can't take damage // simulation.enableConstructMode() //used to build maps in testing mode - // level.testChamber2(); + // level.temple(); // spawn.cellBossCulture(1900, -500) // powerUps.research.changeRerolls(100) + // spawn.starter(1900, -500, 40) + // spawn.starter(1900, -500, 20) // spawn.starter(1900, -500, 100) // for (let i = 0; i < 20; ++i) spawn.exploder(1900, -500) // spawn.timeSkipBoss(1900, -500) - // level.difficultyIncrease(20) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(50) //30 is near max on hard //60 is near max on why // level.testing(); //not in rotation, used for testing // for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); // for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); @@ -1466,7 +1467,7 @@ const level = { //****************************************************************************************************************** //****************************************************************************************************************** labs() { - level.isProcedural = true //used in generating text itn he level builder + level.isProcedural = true //used in generating text it the level builder level.defaultZoom = 1700 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d9d9de" //"#d3d3db" //"#dcdcdf"; @@ -9812,6 +9813,7 @@ const level = { powerUps.spawn(3000, -230, "heal"); // level.difficultyIncrease(60) }, + temple() { simulation.makeTextLog(`temple by Scar1337`); @@ -9993,6 +9995,7 @@ const level = { const pulseRadius = args[3] || Math.min(550, 250 + simulation.difficulty * 3) let me = mob[mob.length - 1]; me.fill = "#ace"; + me.damageReduction = 0; me.onDeath = function() { //damage player if in range if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) { @@ -10033,7 +10036,7 @@ const level = { me.isBoss = true; me.stroke = "transparent"; - me.eventHorizon = 950; + me.eventHorizon = 900; me.collisionFilter.mask = cat.player | cat.bullet | cat.body; me.memory = Infinity; @@ -10084,9 +10087,9 @@ const level = { id: 2 }]; me.ring = function() { - const rings = this.isInvulnerable ? [] : this.rings; + if (this.isInvulnerable) return; ctx.lineWidth = 10; - for (const ring of rings) { + for (const ring of this.rings) { const radius = ring.radius * (1 + 0.3 * Math.sin(simulation.cycle / 60 * (ring.id + 2))); if (Math.abs(distance(player.position, this.position) - radius) < 60 && m.immuneCycle < simulation.cycle) { m.damage(0.4 / radius); @@ -10096,6 +10099,7 @@ const level = { } } me.horizon = function() { + if (this.isInvulnerable) return; // eventHorizon waves in and out const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)); @@ -10136,7 +10140,7 @@ const level = { this.lastAttackCycle = simulation.cycle; Matter.Body.setVelocity(player, V.add(player.velocity, { x: 0, y: -20 })); if (m.immuneCycle < m.cycle) { - m.damage(0.015 * simulation.dmgScale); + m.damage(0.012 * simulation.dmgScale); } } const lightningCycle = simulation.cycle * 2 / 3 + this.lastAttackCycle / 3; @@ -10165,7 +10169,7 @@ const level = { } } // Spawn a bunch of mobs - if (!(this.spawnCycle % 600)) { + if (simulation.difficulty > 10 && !(this.spawnCycle % 600)) { // This is just ripped off of spawn.nodeGroup because I don't want the shield const nodes = 3; const radius = Math.ceil(Math.random() * 10) + 18; @@ -10248,8 +10252,17 @@ const level = { canvas.style.filter = ""; level.nextLevel = oldNextLevel; simulation.fallHeight = oldFallHeight; + m.oldDeath(); + } else { + m.switchWorlds(); + Matter.Body.setPosition(player, { + x: level.enter.x + 50, + y: level.enter.y - 20 + }); + makeLore("How did you not die?"); + setTimeout(() => makeLore("I'll let you off this one time."), 2000); + tech.isImmortal = false; } - m.oldDeath(); } let name = "⥟ᘊ5⪊Ыᳪៗⱕ␥ዘᑧ⍗"; addPartToMap = (len = map.length - 1) => { @@ -10405,7 +10418,7 @@ const level = { spawn.mapRect(-200, -13100, 800, 200); spawn.mapRect(3500, -13110, 100, 20); spawn.mapRect(3000, -13100, 800, 200); - for (let i = 0; i < 3; i++) spawn.bodyRect(500, -13400 + i * 100, 100, 100); + for (let i = 0; i < 4; i++) spawn.bodyRect(570, -13400 + i * 75, 30, 75); for (let i = 0; i < 3; i++) { diamond(1100 + 700 * i, -13000, 30, 30); @@ -10672,11 +10685,11 @@ const level = { level.exit.y = -10030; makeLore("Pathetic."); } - if (templePlayer.room1ToRoom2Anim === 241) { + if (templePlayer.room1ToRoom2Anim === 121) { makeLore("You will never succeed."); } - if (templePlayer.room1ToRoom2Anim >= 480 && templePlayer.room1ToRoom2Anim <= 960) { - const factor = 200 - 200 * Math.cos((templePlayer.room1ToRoom2Anim / 120) * Math.PI); + if (templePlayer.room1ToRoom2Anim >= 360 && templePlayer.room1ToRoom2Anim <= 720) { + const factor = 200 - 200 * Math.cos((templePlayer.room1ToRoom2Anim / 120 - 3) * Math.PI); ctx.translate(factor, factor); Promise.resolve().then(() => { ctx.save(); @@ -10687,16 +10700,16 @@ const level = { ctx.restore(); }); } - if (templePlayer.room1ToRoom2Anim === 960) { + if (templePlayer.room1ToRoom2Anim === 720) { makeLore("You are trying too hard."); relocateTo(0, -7050); simulation.fallHeight = -6000; templePlayer.stage = 2; } - if (templePlayer.room1ToRoom2Anim === 1200) { + if (templePlayer.room1ToRoom2Anim === 960) { makeLore("I have mastered the understandings of the universe."); } - if (templePlayer.room1ToRoom2Anim === 1260) { + if (templePlayer.room1ToRoom2Anim === 1200) { // Congrats, you discovered the actual words by looking at the source code. Are you happy now? const x = ( ["a speck of dust", "an insignificant hindrance", "a tiny obstacle"] @@ -10719,22 +10732,22 @@ const level = { level.exit.y = -13130; makeLore("Do not try me."); } - if (templePlayer.room2ToRoom3Anim === 240) { + if (templePlayer.room2ToRoom3Anim === 180) { makeLore("I have absolute power over you."); canvas.style.filter = "hue-rotate(90deg)"; } - if (templePlayer.room2ToRoom3Anim === 480) { + if (templePlayer.room2ToRoom3Anim === 360) { makeLore("You will not succeed..."); canvas.style.filter = "invert(0.2)"; } - if (templePlayer.room2ToRoom3Anim === 600) { - makeLore("
succeed...
"); + if (templePlayer.room2ToRoom3Anim === 420) { + makeLore("
...
"); canvas.style.filter = "invert(0.4)"; } - if (templePlayer.room2ToRoom3Anim > 660 && templePlayer.room2ToRoom3Anim <= 840) { - canvas.style.filter = `sepia(${(templePlayer.room2ToRoom3Anim - 660) / 180}) invert(${0.5 + (templePlayer.room2ToRoom3Anim - 660) / 360})`; + if (templePlayer.room2ToRoom3Anim > 480 && templePlayer.room2ToRoom3Anim <= 660) { + canvas.style.filter = `sepia(${(templePlayer.room2ToRoom3Anim - 480) / 180}) invert(${0.5 + (templePlayer.room2ToRoom3Anim - 480) / 180})`; } - if (templePlayer.room2ToRoom3Anim === 960) { + if (templePlayer.room2ToRoom3Anim === 780) { makeLore("Do not interfere with me."); templePlayer.stage = 3; relocateTo(50, -13150); @@ -10748,8 +10761,8 @@ const level = { } } } - if (templePlayer.room2ToRoom3Anim > 960 && templePlayer.room2ToRoom3Anim <= 1140) { - canvas.style.filter = `sepia(${(1140 - templePlayer.room2ToRoom3Anim) / 180}) invert(${(1140 - templePlayer.room2ToRoom3Anim) / 180})`; + if (templePlayer.room2ToRoom3Anim > 780 && templePlayer.room2ToRoom3Anim <= 960) { + canvas.style.filter = `sepia(${(960 - templePlayer.room2ToRoom3Anim) / 180}) invert(${(960 - templePlayer.room2ToRoom3Anim) / 180})`; } templePlayer.room2ToRoom3Anim++; }, @@ -10852,10 +10865,12 @@ const level = { level.exitCount + (input.down ? 8 : 2) > 100) { if (templePlayer.stage === 1) { templePlayer.drawExit = false; + level.exitCount = 0; templePlayer.room1ToRoom2Anim = 1; } else if (templePlayer.stage === 2) { templePlayer.drawExit = false; templePlayer.room2ToRoom3Anim = 1; + level.exitCount = 0; } else { level.exitCount = 99 - (input.down ? 8 : 2); if (!templePlayer.clearedCycle) templePlayer.clearedCycle = simulation.cycle; @@ -10953,7 +10968,7 @@ const level = { ctx.fillStyle = "#0004"; ctx.fillRect(canvas.width2 - 288, 50, 576, 20); ctx.fillStyle = "#0cf"; - ctx.fillRect(canvas.width2 - 288, 50, 0.8 * (600 - templePlayer.room1.cycles % 600), 20); + ctx.fillRect(canvas.width2 - 288, 50, 0.96 * (600 - templePlayer.room1.cycles % 600), 20); ctx.restore(); } // Second Room @@ -11157,34 +11172,7 @@ const level = { setPos(a, b); freeze(a); }; - const makeLore = x => simulation.makeTextLog(`

${name}:

 

${x}

`); - // TODO: Remove this before merging - window.TempleHelper = { - skipInitial() { - templePlayer.startAnim = 360; - }, - skipWaves() { - this.skipInitial(); - templePlayer.room1.cycles = 2500; - }, - skipToRoom2() { - this.skipInitial(); - templePlayer.room1ToRoom2Anim = 1; - }, - skipBossWaves() { - this.skipToRoom2(); - templePlayer.room2.spawnInitiatorCycles = Objects.room2Initiator.cap; - templePlayer.room2.cycles = 2200; - setTimeout(() => trapPlayer(0, -9100), 500); - }, - skipToRoom3() { - this.skipToRoom2(); - requestAnimationFrame(() => templePlayer.room2ToRoom3Anim = 1); - }, - spawnSecondRoomBoss(x, y) { - secondRoomBoss(x, y); - } - }; + const makeLore = (x, t) => simulation.makeTextLog(`

${name}:

 

${x}

`, t); level.custom = () => { // All the logic gets handled here. How nice! for (const i in LogicHandler) { @@ -11212,6 +11200,1406 @@ const level = { DrawHandler.room2Top(); }; }, + // temple() { + // simulation.makeTextLog(`temple by Scar1337`); + + // const V = Vector; + // const Equation = (function() { + // function Equation(a, b, c) { + // this.a = a; + // this.b = b; + // this.c = c; + // } + // Equation.prototype.getXfromY = function(y) { + // return (-this.b * y - this.c) / this.a; + // } + // Equation.prototype.getYfromX = function(x) { + // return (-this.a * x - this.c) / this.b; + // } + // Equation.fromPoints = function(v1, v2) { + // if (v1.x === v2.x) return new Equation(1, 0, -v1.x); + // if (v1.y === v2.y) return new Equation(0, 1, -v1.y); + // const d = (v2.y - v1.y) / (v2.x - v1.x); + // return new Equation(-d, 1, d * v1.x - v1.y); + // }; + // return Equation; + // })(); + // const Rect = (function() { + // function Rect(x, y, w, h) { + // this.pos = { x, y }; + // this.width = w; + // this.height = h; + // } + // Rect.prototype.has = function({ x, y }) { + // return x >= this.pos.x && x <= this.pos.x + this.width && + // y >= this.pos.y && y <= this.pos.y + this.height; + // } + // Rect.prototype.hasLine = function(eq) { + // const leftInter = eq.getYfromX(this.pos.x); + // const rightInter = eq.getYfromX(this.pos.x + this.width); + // const topInter = eq.getXfromY(this.pos.y); + // return (leftInter >= this.pos.y && leftInter <= this.pos.y + this.height) || + // (rightInter >= this.pos.y && rightInter <= this.pos.y + this.height) || + // (topInter >= this.pos.x && topInter <= this.pos.x + this.width); + // } + // Rect.prototype.addToMap = function() { + // spawn.mapRect(this.pos.x, this.pos.y, this.width, this.height); + // } + // Object.defineProperty(Rect.prototype, "midPos", { + // get() { + // return V.add(this.pos, { x: this.width / 2, y: this.height / 2 }); + // } + // }); + // Rect.fromBounds = function(min, max) { + // return new Rect(min.x, min.y, max.x - min.x, max.y - min.y); + // } + // return Rect; + // })(); + + // function isInBound(bound) { + // return bound.has(player.bounds.min) || bound.has(player.bounds.max); + // } + + // function addWIMP(x, y) { + // spawn.WIMP(x, y); + // const me = mob[mob.length - 1]; + // me.isWIMP = true; + // } + + // function relocateWIMPs(x, y) { + // for (const i of mob) { + // if (i.isWIMP) { + // setPos(i, { x: x + 300 * (Math.random() - 0.5), y: y + 300 * (Math.random() - 0.5) }); + // } + // } + // } + + // function secondRoomBoss(x, y, radius = 25, isDark = false) { + // mobs.spawn(x, y, 12, radius, isDark ? "#000" : "#fff"); + // let me = mob[mob.length - 1]; + // me.isBoss = true; + // me.isDark = isDark; + + // me.stroke = "transparent"; + // me.eventHorizon = 500; // How family friendly content much do I have to reduce this + // me.seeAtDistance2 = 5e6; // Basically just see at all times, in the context it's given + // me.accelMag = 0.00003 * simulation.accelScale; + // me.collisionFilter.mask = cat.player | cat.bullet; + // me.memory = 1600; + // me.randomPRNGMult = Math.random() * 500; + + // me.attackCycle = 0; + // me.lastAttackCycle = 0; + // Matter.Body.setDensity(me, 0.012); // extra dense, normal is 0.001 // makes effective life much larger + // me.onDeath = function() { + // // applying forces to player doesn't seem to work inside this method, not sure why + // powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); + // if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); + // if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); + // }; + // me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); + // me.do = function() { + // // keep it slow, to stop issues from explosion knock backs + // if (this.speed > 1) { + // Matter.Body.setVelocity(this, { + // x: this.velocity.x * 0.95, + // y: this.velocity.y * 0.95 + // }); + // } + // if (!(simulation.cycle % this.seePlayerFreq)) { + // if (this.distanceToPlayer2() < this.seeAtDistance2) { // ignore cloak for black holes + // this.locatePlayer(); + // if (!this.seePlayer.yes) this.seePlayer.yes = true; + // } else if (this.seePlayer.recall) { + // this.lostPlayer(); + // } + // } + // this.checkStatus(); + // if (this.seePlayer.recall) { + // // accelerate towards the player + // const forceMag = this.accelMag * this.mass; + // const dx = this.seePlayer.position.x - this.position.x + // const dy = this.seePlayer.position.y - this.position.y + // const mag = Math.sqrt(dx * dx + dy * dy) + // this.force.x += forceMag * dx / mag; + // this.force.y += forceMag * dy / mag; + + // // eventHorizon waves in and out + // const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)); + + // // draw darkness + // ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.6)" : "rgba(225,215,255,0.6)"; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI); + // ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.4)" : "rgba(225,215,255,0.4)"; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.4, 0, 2 * Math.PI); + // ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.3)" : "rgba(225,215,255,0.3)"; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.6, 0, 2 * Math.PI); + // ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.2)" : "rgba(225,215,255,0.2)"; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.8, 0, 2 * Math.PI); + // ctx.fillStyle = this.isDark ? "rgba(0,0,0,0.05)" : "rgba(255,255,255,0.05)"; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI); + // // when player is inside event horizon + // if (distance(this.position, player.position) < eventHorizon) { + // if (this.isDark) { + // // Standard black hole stuff + // if (m.immuneCycle < m.cycle) { + // if (m.energy > 0) m.energy -= 0.003; + // if (m.energy < 0.1) m.damage(0.00015 * simulation.dmgScale); + // } + // const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); + // player.force.x -= 0.0005 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1); + // player.force.y -= 0.0005 * Math.sin(angle) * player.mass; + // // draw line to player + // ctx.lineWidth = Math.min(60, this.radius * 2); + // ctx.strokeStyle = "rgba(0,0,0,0.5)"; + // DrawTools.line([this.position, m.pos]); + // ctx.fillStyle = "rgba(0,0,0,0.3)"; + // DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); + // } else { + // // Lightning attacks + // this.attackCycle++; + // if (this.attackCycle >= 30) { + // this.attackCycle = 0; + // this.lastAttackCycle = simulation.cycle; + // Matter.Body.setVelocity(player, V.add(player.velocity, { x: 0, y: -10 })); + // if (m.immuneCycle < m.cycle) { + // if (m.energy > 0) m.energy -= 0.03; + // m.damage(0.005 * simulation.dmgScale); + // } + // } + // DrawTools.lightning(this.position, m.pos, this.lastAttackCycle, this.randomPRNGMult); + // ctx.fillStyle = `rgba(255,240,127,${0.12 * Math.max(15 - simulation.cycle + this.lastAttackCycle, 0)})`; + // DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); + // } + // } + // } + // } + // }; + + // function mobGrenade(...args) { + // spawn.grenade(...args); + // const pulseRadius = args[3] || Math.min(550, 250 + simulation.difficulty * 3) + // let me = mob[mob.length - 1]; + // me.fill = "#ace"; + // me.onDeath = function() { + // //damage player if in range + // if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) { + // m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage + // m.damage(0.02 * simulation.dmgScale); + // } + // simulation.drawList.push({ //add dmg to draw queue + // x: this.position.x, + // y: this.position.y, + // radius: pulseRadius, + // color: "rgba(170,204,238,0.3)", + // time: simulation.drawTime + // }); + // }; + // me.do = function() { + // this.timeLimit(); + // ctx.beginPath(); //draw explosion outline + // ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay + // ctx.fillStyle = "rgba(170,204,238,0.1)"; + // ctx.fill(); + // }; + // } + // // Todo: nerf ThirdRoomBoss a bit? + // function thirdRoomBoss(x, y) { + // mobs.spawn(x, y, 6, 60, "#000"); + // let me = mob[mob.length - 1]; + // // Fix in place + // me.constraint = Constraint.create({ + // pointA: { + // x: me.position.x, + // y: me.position.y + // }, + // bodyB: me, + // stiffness: 1, + // damping: 1 + // }); + // Composite.add(engine.world, me.constraint); + // me.isBoss = true; + + // me.stroke = "transparent"; + // me.eventHorizon = 950; + // me.collisionFilter.mask = cat.player | cat.bullet | cat.body; + + // me.memory = Infinity; + // me.attackCycle = 0; + // me.lastAttackCycle = 0; + // me.spawnCycle = 0; + // Matter.Body.setDensity(me, 0.08); //extra dense //normal is 0.001 //makes effective life much larger + // me.onDeath = function() { + // for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die + // for (let i = 0, len = mob.length; i < len; ++i) { + // if (mob[i] !== this) { + // if (mob[i].isInvulnerable) { //disable invulnerability + // mob[i].isInvulnerable = false + // mob[i].damageReduction = 1 + // } + // mob[i].damage(Infinity, true); + // } + // } + // } + // // You earned it: One more tech + // powerUps.spawn(this.position.x, this.position.y, "tech"); + // powerUps.spawnBossPowerUp(this.position.x, this.position.y); + // templePlayer.room3ToEndAnim = 1; + // }; + // me.nextHealthThreshold = 0.75; + // me.trapCycle = 0; + // me.onDamage = function() { + // if (this.health < this.nextHealthThreshold) { + // this.health = this.nextHealthThreshold - 0.01 + // this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25 + // this.trapCycle = 1; + // this.isInvulnerable = true; + // this.damageReduction = 0; + // } + // }; + // me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); + // me.rings = [{ + // colour: "#65f", + // radius: 300, + // id: 0 + // }, { + // colour: "#0f0", + // radius: 400, + // id: 1 + // }, { + // colour: "#f00", + // radius: 500, + // id: 2 + // }]; + // me.ring = function() { + // const rings = this.isInvulnerable ? [] : this.rings; + // ctx.lineWidth = 10; + // for (const ring of rings) { + // const radius = ring.radius * (1 + 0.3 * Math.sin(simulation.cycle / 60 * (ring.id + 2))); + // if (Math.abs(distance(player.position, this.position) - radius) < 60 && m.immuneCycle < simulation.cycle) { + // m.damage(0.4 / radius); + // } + // ctx.strokeStyle = ring.colour; + // DrawTools.arcOut(this.position.x, this.position.y, radius, 0, Math.PI * 2); + // } + // } + // me.horizon = function() { + // // eventHorizon waves in and out + // const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)); + + // const charge = this.attackCycle / 90; + // this.fill = this.isInvulnerable ? "#f00" : `rgb(${charge * 255},${charge * 255},${charge * 255})`; + // // draw darkness + // ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.6)`; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI); + // ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.4)`; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.4, 0, 2 * Math.PI); + // ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.3)`; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.6, 0, 2 * Math.PI); + // ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.2)`; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.8, 0, 2 * Math.PI); + // ctx.fillStyle = `rgba(${charge * 255},${charge * 255},${charge * 255},0.05)`; + // DrawTools.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI); + + // // when player is inside event horizon + // if (V.magnitude(V.sub(this.position, player.position)) < eventHorizon) { + // // Standard black hole stuff + // if (m.immuneCycle < m.cycle) { + // if (m.energy > 0) m.energy -= 0.004; + // if (m.energy < 0.1) m.damage(0.0002 * simulation.dmgScale); + // } + // const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); + // player.force.x -= 0.001 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1); + // player.force.y -= 0.001 * Math.sin(angle) * player.mass; + // // draw line to player + // ctx.lineWidth = Math.min(60, this.radius * 2); + // ctx.strokeStyle = "rgba(0,0,0,0.5)"; + // DrawTools.line([this.position, m.pos]); + // ctx.fillStyle = "rgba(0,0,0,0.3)"; + // DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); + // // Lightning attacks + // this.attackCycle++; + // if (this.attackCycle >= 90) { + // this.attackCycle = 0; + // this.lastAttackCycle = simulation.cycle; + // Matter.Body.setVelocity(player, V.add(player.velocity, { x: 0, y: -20 })); + // if (m.immuneCycle < m.cycle) { + // m.damage(0.015 * simulation.dmgScale); + // } + // } + // const lightningCycle = simulation.cycle * 2 / 3 + this.lastAttackCycle / 3; + // DrawTools.lightning(this.position, m.pos, lightningCycle, 1, 12); + // DrawTools.lightning(this.position, m.pos, lightningCycle, 2, 12); + // ctx.fillStyle = `rgba(255,240,127,${0.12 * Math.max(15 - simulation.cycle + this.lastAttackCycle, 0)})`; + // DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); + // } + // } + // me.periodicSpawns = function() { + // if (this.isInvulnerable) return; + // this.spawnCycle++; + // // Spawn annoying purple thing(s) that chases the player + // if (!(this.spawnCycle % 180)) { + // spawn.seeker(this.position.x, this.position.y, 15 * (0.7 + 0.5 * Math.random()), 7); + // spawn.seeker(this.position.x, this.position.y, 4 * (0.7 + 0.5 * Math.random()), 7); + // spawn.seeker(this.position.x, this.position.y, 4 * (0.7 + 0.5 * Math.random()), 7); + // } + // // Spawn the annoying pink (now blue) exploder that doesn't chase the player + // if (!(this.spawnCycle % 300)) { + // for (let i = 0; i < 3; i++) { + // mobGrenade(1100 + 700 * i, -13030, undefined, Math.min(700, 300 + simulation.difficulty * 4), 10); + // setVel(mob[mob.length - 1], { x: 0, y: -10 }); + // mobGrenade(1100 + 700 * i, -14370, undefined, Math.min(700, 300 + simulation.difficulty * 4), 10); + // setVel(mob[mob.length - 1], { x: 0, y: 10 }); + // } + // } + // // Spawn a bunch of mobs + // if (!(this.spawnCycle % 600)) { + // // This is just ripped off of spawn.nodeGroup because I don't want the shield + // const nodes = 3; + // const radius = Math.ceil(Math.random() * 10) + 18; + // const sideLength = Math.ceil(Math.random() * 100) + 70; + // const stiffness = Math.random() * 0.03 + 0.005; + // spawn.allowShields = false; //don't want shields on individual group mobs + // const angle = 2 * Math.PI / nodes + // for (let i = 0; i < nodes; ++i) { + // spawn.focuser(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius); + // } + // spawn.constrainAllMobCombos(nodes, stiffness); + // spawn.allowShields = true; + // } + // } + // me.invulnerableTrap = function() { + // if (this.trapCycle < 1) return; + // this.trapCycle++; + // // 24 is just an arbitrarily large number + // const spawnCycles = Math.min(24, Math.max(6, 4 + Math.floor(simulation.difficulty / 3))); + // // I have no idea how to balance at all, please help me + // const spawnDelay = Math.floor(5 + 10 / (1 + Math.sqrt(simulation.difficulty) / 5)); + // if (this.trapCycle >= 90) { + // const cycle = this.trapCycle - 90; + // if (!(cycle % spawnDelay)) { + // const radius = Math.min(500, 200 + simulation.difficulty * 3); + // mobGrenade(600, -13050, 30, radius); + // Matter.Body.setVelocity(mob[mob.length - 1], { x: 35, y: 0 }); + // mobGrenade(3000, -13050, 30, radius); + // Matter.Body.setVelocity(mob[mob.length - 1], { x: -35, y: 0 }); + // mobGrenade(600, -14350, 30, radius); + // Matter.Body.setVelocity(mob[mob.length - 1], { x: 35, y: 0 }); + // mobGrenade(3000, -14350, 30, radius); + // Matter.Body.setVelocity(mob[mob.length - 1], { x: -35, y: 0 }); + // if (Math.floor(cycle / spawnDelay) >= spawnCycles - 1) { + // this.trapCycle = 0; + // this.isInvulnerable = false; + // this.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); + // } + // } + // } + // ctx.font = "100px Arial"; + // ctx.fillStyle = "#f00"; + // ctx.shadowBlur = 10; + // ctx.shadowColor = "#f00"; + // ctx.textAlign = "center"; + // ctx.textBaseLine = "middle"; + // ctx.fillText("!", 900, -13050); + // ctx.fillText("!", 900, -14350); + // ctx.fillText("!", 1800, -13050); + // ctx.fillText("!", 1800, -14350); + // ctx.fillText("!", 2700, -13050); + // ctx.fillText("!", 2700, -14350); + // ctx.shadowBlur = 0; + // } + // me.do = function() { + // this.checkStatus(); + // this.horizon(); + // this.ring(); + // this.periodicSpawns(); + // this.invulnerableTrap(); + // } + // }; + // let oldNextLevel = level.nextLevel; + // const oldFallHeight = simulation.fallHeight; + // level.nextLevel = () => { + // color.map = "#444"; + // m.death = m.oldDeath; + // canvas.style.filter = ""; + // level.nextLevel = oldNextLevel; + // simulation.fallHeight = oldFallHeight; + // oldNextLevel(); + // } + // let bounds = []; + // let mobPositionsQueue = Array.from(Array(10), () => []); + // m.oldDeath = m.death; + // m.death = function() { + // if (!tech.isImmortal) { + // requestAnimationFrame(() => color.map = "#444"); + // m.death = m.oldDeath; + // canvas.style.filter = ""; + // level.nextLevel = oldNextLevel; + // simulation.fallHeight = oldFallHeight; + // } + // m.oldDeath(); + // } + // let name = "⥟ᘊ5⪊Ыᳪៗⱕ␥ዘᑧ⍗"; + // addPartToMap = (len = map.length - 1) => { + // map[len].collisionFilter.category = cat.map; + // map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; + // Matter.Body.setStatic(map[len], true); // make static + // Composite.add(engine.world, map[len]); + // } + // level.setPosToSpawn(50, -50); // normal spawn + // // Make the level exit really far away so WIMP powerups don't show up at all + // level.exit.x = 1e6; + // level.exit.y = -1e6; + // Promise.resolve().then(() => { + // // Clear all WIMPS and their research + // for (let i = 0; i < mob.length; i++) { + // while (mob[i] && !mob[i].isMACHO) { + // mob[i].replace(i); + // } + // } + // for (let i = 0; i < powerUp.length; i++) { + // while (powerUp[i] && powerUp[i].name === "research") { + // Matter.Composite.remove(engine.world, powerUp[i]); + // powerUp.splice(i, 1); + // } + // } + // level.exit.x = 1500; + // level.exit.y = -30; + // }); + // spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); + // spawn.mapRect(1500, -10, 100, 20); + // level.defaultZoom = 1800 + // simulation.setZoom(1200); + // document.body.style.backgroundColor = "#daa69f"; + // color.map = "#600"; + + // function box(x, y, w, h, s) { + // spawn.mapRect(x, y, w, s); + // spawn.mapRect(x, y, s, h); + // spawn.mapRect(x + w - s, y, s, h); + // spawn.mapRect(x, y + h - s, w, s); + // } + + // function diamond(x, y, s) { + // spawn.mapVertex(x, y, `0 -${s} -${s} 0 0 ${s} ${s} 0`); + // } + + // // Fake level + // bounds.push(new Rect(-200, -500, 2000, 600)); + // box(-200, -500, 2000, 600, 100); + + // // Actual level, Room 1 + // const firstRoomBounds = new Rect(-200, -4000, 5000, 2100); + // bounds.push(firstRoomBounds); + + // box(-200, -4000, 5000, 2100, 100); + // spawn.mapRect(-200, -2500, 1300, 100); + // spawn.mapRect(3500, -2500, 1300, 100); + // spawn.mapRect(-200, -4000, 1000, 1600); + // spawn.mapRect(3800, -4000, 1000, 1600); + // // Enter and Exit platforms + // spawn.mapRect(0, -2010, 100, 20); + // spawn.mapRect(4500, -2010, 100, 20); + + // // Altar of Room 1 + // spawn.mapRect(2100, -2200, 100, 300); + // spawn.mapRect(2400, -2200, 100, 300); + // spawn.mapRect(2070, -2200, 460, 20); + + // spawn.debris(1700, -2100, 300, 10); + // spawn.debris(2500, -2100, 300, 10); + + // // Actual level, Room 2 + // const secondRoomBounds = new Rect(-1500, -10500, 3000, 3600); + // bounds.push(secondRoomBounds); + + // box(-1500, -10500, 3000, 3600, 100); + // spawn.mapRect(-2000, -8500, 1600, 1600); + // spawn.mapRect(400, -8500, 1600, 1600); + // // Enter and Exit platforms + // spawn.mapRect(-50, -7010, 100, 20); + // spawn.mapRect(-50, -10010, 100, 20); + + // // Hazard traversing + // spawn.mapRect(-300, -7320, 800, 20); + // spawn.mapRect(175, -7600, 325, 20); + // spawn.mapRect(200, -7775, 300, 20); + // spawn.mapRect(-500, -7600, 325, 20); + // spawn.mapRect(-500, -7775, 300, 20); + // spawn.mapRect(-500, -7950, 800, 20); + // spawn.mapRect(-300, -8100, 800, 20); + // spawn.mapRect(-500, -8250, 800, 20); + // for (let i = 0; i < 2; i++) spawn.mapRect(-250, -8400 + 150 * i, 500, 60); + // const room2SlimePit = level.hazard(-400, -8410, 800, 1090); + // room2SlimePit.logic = function() { + // if (this.height > 0 && Matter.Query.region([player], this).length) { + // if (m.immuneCycle < m.cycle) { + // // Trolled + // const hasCPT = tech.isRewindAvoidDeath; + // tech.isRewindAvoidDeath = false; + // const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen; + // if (m.energy > DRAIN && !tech.isEnergyHealth) { + // m.energy -= DRAIN; + // } + // m.damage(0.00015 * (tech.isRadioactiveResistance ? 0.25 : 1)); + // if (tech.isEnergyHealth) { + // const previousEnergy = m.energy; + // m.regenEnergy(); + // const energyRegenerated = m.energy - previousEnergy; + // if (energyRegenerated > 0) { + // m.energy = previousEnergy; + // m.damage(energyRegenerated); + // } + // } + // tech.isRewindAvoidDeath = hasCPT; + // } + // player.force.y -= 0.3 * player.mass * simulation.g; + // setVel(player, Vector.sub(player.velocity, { x: 0, y: player.velocity.y * 0.02 })); + // } + // // Float power ups + // powerUpCollide = Matter.Query.region(powerUp, this) + // for (let i = 0, len = powerUpCollide.length; i < len; i++) { + // const diameter = 2 * powerUpCollide[i].size + // const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter + // powerUpCollide[i].force.y -= buoyancy * 1.14 * powerUpCollide[i].mass * simulation.g; + // setVel(powerUpCollide[i], { x: powerUpCollide[i].velocity.x, y: 0.96 * powerUpCollide[i].velocity.y }); + // } + // } + // room2SlimePit.draw = function() { + // if (this.isOn) { + // ctx.fillStyle = "hsla(160, 100%, 35%, 0.75)"; + // ctx.fillRect(this.min.x, this.min.y, this.width, this.height); + // } + // } + // // Room 2 spawning bounds + // const secondRoomSpawnBounds = new Rect(-1500, -10500, 3000, 2000); + // spawn.mapRect(-700, -8700, 150, 20); + // spawn.mapRect(550, -8700, 150, 20); + // spawn.mapRect(-400, -8900, 800, 20); + // diamond(-600, -9800, 30); + // diamond(0, -9800, 30); + // diamond(600, -9800, 30); + + // spawn.mapRect(-1000, -10000, 2000, 30); + + // // Actual level, Room 3 (Final Boss?) + // const thirdRoomBounds = new Rect(-200, -14500, 4000, 1600); + // bounds.push(thirdRoomBounds); + // box(-200, -14500, 4000, 1600, 100); + // spawn.mapRect(-200, -14500, 800, 1100); + // spawn.mapRect(3000, -14500, 800, 1100); + // // Enter and Exit platforms + // spawn.mapRect(0, -13110, 100, 20); + // spawn.mapRect(-200, -13100, 800, 200); + // spawn.mapRect(3500, -13110, 100, 20); + // spawn.mapRect(3000, -13100, 800, 200); + // for (let i = 0; i < 3; i++) spawn.bodyRect(500, -13400 + i * 100, 100, 100); + + // for (let i = 0; i < 3; i++) { + // diamond(1100 + 700 * i, -13000, 30, 30); + // diamond(1100 + 700 * i, -14400, 30, 30); + // } + + // const Objects = { + // altar: { + // get isHeal() { + // return simulation.cycle % 600 >= 300; + // }, + // pos: { + // x: 2300, + // y: -2200 + // }, + // get isActive() { + // const roughPlayerCentre = V.add(m.pos, { x: 0, y: 40 }); + // return distance(roughPlayerCentre, this.pos) < 240 && + // (Math.abs(angle(roughPlayerCentre, this.pos) - Math.PI / 2) < 1); + // }, + // logic() { + // if (!this.isActive) return; + // if (this.isHeal) { + // m.energy += 0.005; + // } else { + // m.energy = Math.max(m.energy - 0.007 - m.fieldRegen, 0); + // if (m.energy <= 0.01 && m.immuneCycle < m.cycle) m.damage(0.002); + // } + // }, + // drawTop() { + // if (!isInBound(firstRoomBounds)) return; + // const colour = this.isHeal ? m.fieldMeterColor : "#f00"; + // DrawTools.flame([2300, -2200, 26, 4, colour], 7); + // ctx.fillStyle = colour; + // ctx.fillRect(2200, -2200, 200, 200); + // }, + // drawBottom() { + // ctx.fillStyle = this.isHeal ? "#fff5" : "#0005"; + // for (const radius of [230, 180, 130, 80, 30]) { + // DrawTools.arc(2300, -2200, radius, 0, Math.PI, true); + // } + // } + // }, + // room2Initiator: { + // pos: { + // x: 0, + // y: -9050 + // }, + // get distance() { + // return distance(player.position, this.pos); + // }, + // range: 120, + // rings: [{ + // colour: [102, 85, 255], + // radius: 200 + // }, { + // colour: [0, 255, 0], + // radius: 300 + // }, { + // colour: [255, 0, 0], + // radius: 400 + // }], + // get ringNumber() { + // return this.rings.length; + // }, + // get cap() { + // return (this.ringNumber + 1) * 90 + 240; + // }, + // get capped() { + // return templePlayer.room2.spawnInitiatorCycles > this.cap; + // }, + // logic() { + // if (this.distance < this.range) { + // templePlayer.room2.spawnInitiatorCycles++; + // } + // }, + // draw() { + // Promise.resolve().then(() => { + // const cycle = templePlayer.room2.spawnInitiatorCycles; + // if (!this.capped && this.distance < 400) { + // ctx.fillStyle = `rgba(0, 0, 0, ${Math.min(1, (400 - this.distance) / (400 - this.range)) * 0.9})`; + // ctx.fillRect(0, 0, canvas.width, canvas.height); + // } + // ctx.save(); + // simulation.camera(); + // if (this.distance < this.range && !this.capped) { + // DrawTools.lightning(V.sub(this.pos, { x: 300, y: 300 }), V.add(this.pos, { x: 300, y: 300 }), simulation.cycle - 5); + // DrawTools.lightning(V.add(this.pos, { x: -300, y: 300 }), V.add(this.pos, { x: 300, y: -300 }), simulation.cycle - 5); + // } + // if (!this.capped && cycle >= this.cap - 200) { + // const multCoeff = (cycle - this.cap + 200) * 0.4 + // ctx.translate((Math.random() - 0.5) * multCoeff, (Math.random() - 0.5) * multCoeff); + // } + // ctx.shadowBlur = 20; + // ctx.lineWidth = 12; + // ctx.strokeStyle = (templePlayer.room2.cycles % 60 < 30) ? "#fff" : "#000"; + // ctx.shadowColor = (templePlayer.room2.cycles % 60 < 30) ? "#fff" : "#000"; + // DrawTools.arcOut(this.pos.x, this.pos.y, 100, 0, Math.PI * 2); + // if (templePlayer.room2.cycles <= 100) { + // for (let i = 0; i < this.ringNumber; i++) { + // if (cycle < i * 90 + 90) break; + // const ring = this.rings[i]; + // ctx.shadowColor = `rgb(${ring.colour.join(",")})`; + // const opacity = this.capped ? 1 - 0.01 * templePlayer.room2.cycles : (cycle / 180 - i / 2 - 0.5); + // ctx.strokeStyle = `rgba(${ring.colour.join(",")}, ${Math.min(opacity, 1)})`; + // const radius = (this.capped ? 1 + 0.07 * templePlayer.room2.cycles : Math.sin(Math.min(cycle - i * 90 - 90, 45) / 90 * Math.PI)) * ring.radius; + // DrawTools.arcOut(this.pos.x, this.pos.y, radius, 0, Math.PI * 2); + // } + // } + // ctx.restore(); + // }); + // } + // }, + // room2Lightning: { + // one: [{ x: -1400, y: -10400 }, { x: 1400, y: -8500 }], + // two: [{ x: -1400, y: -8500 }, { x: 1400, y: -10400 }], + // get isHeal() { + // return simulation.cycle % 360 < 180; + // }, + // get oneEq() { + // return Equation.fromPoints(this.one[0], this.one[1]); + // }, + // get twoEq() { + // return Equation.fromPoints(this.two[0], this.two[1]); + // }, + // logic() { + // if (!isInBound(secondRoomSpawnBounds) || !templePlayer.room2.cycles) return; + + // const playerbounds = Rect.fromBounds(player.bounds.min, player.bounds.max); + // if (playerbounds.hasLine(this.oneEq) || playerbounds.hasLine(this.twoEq)) { + // if (this.isHeal) { + // m.energy += 0.003; + // } else if (m.immuneCycle < m.cycle) { + // m.energy -= 0.003; + // } + // } + // }, + // draw() { + // if (!isInBound(secondRoomBounds) || !templePlayer.room2.cycles) return; + + // const colour = this.isHeal ? undefined : [0, 0, 0]; + // DrawTools.lightning(...this.one, Math.floor(simulation.cycle / 15) * 15, 1, 9, colour); + // DrawTools.lightning(...this.two, Math.floor(simulation.cycle / 15) * 15, 2, 9, colour); + // } + // }, + // room2GeneratedPath: { + // rects: (function() { + // const rects = []; + // for (let i = 0; i < 4; i++) { + // rects.push(new Rect(-1405 + (i & 1) * 200, -9700 + i * 300, 205, 30)); + // rects.push(new Rect(1200 - (i & 1) * 200, -9700 + i * 300, 205, 30)); + // } + // return rects; + // })(), + // logic() { + // if (templePlayer.room2.readyPathCycle && simulation.cycle - templePlayer.room2.readyPathCycle === 180) { + // for (const r of this.rects) { + // r.addToMap(); + // addPartToMap(); + // simulation.draw.setPaths(); + // } + // } + // }, + // draw() { + // if (templePlayer.room2.readyPathCycle && simulation.cycle - templePlayer.room2.readyPathCycle < 180) { + // ctx.fillStyle = "#fe79"; + // for (const r of this.rects) { + // ctx.fillRect(r.pos.x, r.pos.y, r.width, r.height); + // } + // } else if (simulation.cycle - templePlayer.room2.readyPathCycle < 195) { + // for (const r of this.rects) { + // DrawTools.lightning(Objects.room2Initiator.pos, r.midPos, templePlayer.room2.readyPathCycle + 180); + // } + // } + // } + // }, + // room3Rotors: { + // rotor1: (function() { + // const rotor = level.spinner(900, -13700, 200, 30); + // rotor.rotate = function() { + // Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity + 0.01) * 0.9) + // } + // return rotor; + // })(), + // rotor2: (function() { + // const rotor = level.spinner(2700, -13700, 200, 30); + // rotor.rotate = function() { + // Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity - 0.01) * 0.9) + // } + // return rotor; + // })(), + // logic() { + // this.rotor1.rotate(); + // this.rotor2.rotate(); + // } + // }, + // room3SlimePits: { + // pit1: level.hazard(-100, -13400, 0, 0, 0.004), + // pit2: level.hazard(3700, -13400, 0, 0, 0.004), + // logic() { + // if (templePlayer.room2ToRoom3Anim >= 1320 && templePlayer.room2ToRoom3Anim <= 1570) { + // this.pit1.height = this.pit2.height = 300; + // this.pit1.max.y = this.pit2.max.y = -13100; + // this.pit1.width = this.pit2.width = templePlayer.room2ToRoom3Anim * 2 - 2640; + // this.pit1.max.x = this.pit1.min.x + this.pit1.width; + // this.pit2.min.x = this.pit2.max.x - this.pit2.width; + // } + // if (templePlayer.room3ToEndAnim) { + // this.pit1.height = this.pit1.width = 0; + // this.pit2.height = this.pit2.width = 0; + // } + // }, + // draw() { + // this.pit1.query(); + // this.pit2.query(); + // } + // } + // }; + // let templePlayer = { + // room1: { + // cycles: 300 + // }, + // room2: { + // spawnInitiatorCycles: 0, + // cycles: 0, + // readyPathCycle: 0 + // }, + // stage: 1, + // startAnim: 0, + // room1ToRoom2Anim: 0, + // room2ToRoom3Anim: 0, + // room3ToEndAnim: 0, + // initialTrapY: 0, + // clearedCycle: 0, + // drawExit: true + // }; + + // const RoomTransitionHandler = { + // room0() { + // if (templePlayer.startAnim <= 0) return; + // templePlayer.startAnim++; + // if (templePlayer.startAnim == 120) { + // makeLore("Not so fast."); + // } + // if (templePlayer.startAnim < 360) { + // trapPlayer(1000, templePlayer.initialTrapY); + // } else { + // level.exit.x = 4500; + // level.exit.y = -2030; + // relocateTo(50, -2050); + // simulation.fallHeight = -1000; + // simulation.setZoom(1800); + // templePlayer.startAnim = -1; + // for (let i = 0; i < tech.wimpCount + tech.wimpExperiment; i++) { + // addWIMP(); + // } + // templePlayer.drawExit = false; + // } + // }, + // room1() { + // if (templePlayer.room1ToRoom2Anim <= 0) return; + // if (templePlayer.room1ToRoom2Anim === 1) { + // level.exit.x = -50; + // level.exit.y = -10030; + // makeLore("Pathetic."); + // } + // if (templePlayer.room1ToRoom2Anim === 241) { + // makeLore("You will never succeed."); + // } + // if (templePlayer.room1ToRoom2Anim >= 480 && templePlayer.room1ToRoom2Anim <= 960) { + // const factor = 200 - 200 * Math.cos((templePlayer.room1ToRoom2Anim / 120) * Math.PI); + // ctx.translate(factor, factor); + // Promise.resolve().then(() => { + // ctx.save(); + // ctx.globalCompositeOperation = "color-burn"; + // ctx.fillStyle = DrawTools.randomColours; + // DrawTools.updateRandomColours(5); + // ctx.fillRect(0, 0, canvas.width, canvas.height); + // ctx.restore(); + // }); + // } + // if (templePlayer.room1ToRoom2Anim === 960) { + // makeLore("You are trying too hard."); + // relocateTo(0, -7050); + // simulation.fallHeight = -6000; + // templePlayer.stage = 2; + // } + // if (templePlayer.room1ToRoom2Anim === 1200) { + // makeLore("I have mastered the understandings of the universe."); + // } + // if (templePlayer.room1ToRoom2Anim === 1260) { + // // Congrats, you discovered the actual words by looking at the source code. Are you happy now? + // const x = ( + // ["a speck of dust", "an insignificant hindrance", "a tiny obstacle"] + // )[Math.floor(Math.random() * 3)].split(""); + // for (let i = 0; i < x.length / 1.6; i++) { + // const randomIndex = Math.floor(Math.random() * x.length); + // if (x[randomIndex] !== " ") { + // x[randomIndex] = String.fromCharCode(Math.floor(Math.random() * 50) + 192); + // } + // }; + // makeLore(`You are no more than ${x.join("")} to me.`); + // relocateWIMPs(0, -10030); + // } + // templePlayer.room1ToRoom2Anim++; + // }, + // room2() { + // if (templePlayer.room2ToRoom3Anim <= 0) return; + // if (templePlayer.room2ToRoom3Anim === 1) { + // level.exit.x = 3500; + // level.exit.y = -13130; + // makeLore("Do not try me."); + // } + // if (templePlayer.room2ToRoom3Anim === 240) { + // makeLore("I have absolute power over you."); + // canvas.style.filter = "hue-rotate(90deg)"; + // } + // if (templePlayer.room2ToRoom3Anim === 480) { + // makeLore("You will not succeed..."); + // canvas.style.filter = "invert(0.2)"; + // } + // if (templePlayer.room2ToRoom3Anim === 600) { + // makeLore("
succeed...
"); + // canvas.style.filter = "invert(0.4)"; + // } + // if (templePlayer.room2ToRoom3Anim > 660 && templePlayer.room2ToRoom3Anim <= 840) { + // canvas.style.filter = `sepia(${(templePlayer.room2ToRoom3Anim - 660) / 180}) invert(${0.5 + (templePlayer.room2ToRoom3Anim - 660) / 360})`; + // } + // if (templePlayer.room2ToRoom3Anim === 960) { + // makeLore("Do not interfere with me."); + // templePlayer.stage = 3; + // relocateTo(50, -13150); + // simulation.fallHeight = -10000; + // simulation.zoomTransition(1800); + // templePlayer.startAnim = -1; + // // Might be a bit harsh to the player if the WIMPs are involved in the third level + // for (let i = 0; i < mob.length; i++) { + // while (mob[i] && !mob[i].isWIMP) { + // mob[i].replace(i); + // } + // } + // } + // if (templePlayer.room2ToRoom3Anim > 960 && templePlayer.room2ToRoom3Anim <= 1140) { + // canvas.style.filter = `sepia(${(1140 - templePlayer.room2ToRoom3Anim) / 180}) invert(${(1140 - templePlayer.room2ToRoom3Anim) / 180})`; + // } + // templePlayer.room2ToRoom3Anim++; + // }, + // room3() { + // if (templePlayer.room3ToEndAnim <= 0) return; + // if (templePlayer.room3ToEndAnim === 1) { + // makeLore("No."); + // } + // if (templePlayer.room3ToEndAnim === 120) { + // makeLore("This cannot be."); + // } + // if (templePlayer.room3ToEndAnim === 240) { + // makeLore("Has my power failed me?"); + // } + // if (templePlayer.room3ToEndAnim === 360) { + // makeLore("Was it worth it, destroying this place?"); + // } + // if (templePlayer.room3ToEndAnim === 600) { + // makeLore("No one is greater than me."); + // } + // const text = "noone-"; + // for (let i = 0; i < 12; i++) { + // if (templePlayer.room3ToEndAnim === 720 + i * 20) { + // name = name.slice(0, -1); + // simulation.makeTextLog(`${name}:   ${text[i % 6]}`); + // canvas.style.filter = `brightness(${1 - i / 22})`; + // } + // } + // if (templePlayer.room3ToEndAnim === 1060) { + // templePlayer.drawExit = true; + // for (let i = 0; i < 5 * tech.wimpCount; i++) { + // powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false); + // } + // canvas.style.filter = ""; + // } + // templePlayer.room3ToEndAnim++; + // }, + // end() { + // if (!templePlayer.clearedCycle) return; + // Promise.resolve().then(() => { + // ctx.save(); + // ctx.setTransform(1, 0, 0, 1, 0, 0); + // ctx.fillStyle = `rgba(0, 0, 0, ${(simulation.cycle - templePlayer.clearedCycle) / 300})`; + // ctx.fillRect(0, 0, canvas.width, canvas.height); + // ctx.restore(); + // }); + // if (simulation.cycle - templePlayer.clearedCycle > 420) level.nextLevel(); + // } + // }; + // const LogicHandler = { + // bounds() { + // let isInBounds = false; + // for (const b of bounds) { + // if (isInBound(b)) { + // isInBounds = true; + // break; + // } + // } + // if (!isInBounds) { + // m.damage(0.1 * simulation.difficultyMode); + // trapPlayer(level.enter.x, level.enter.y); + // simulation.makeTextLog("" + name + ":   You thought I could let you get away with that?"); + // } + // }, + // room0() { + // // Block the player from entering the first seemingly innocuous exit + // if ((m.pos.x > 1000) && templePlayer.startAnim === 0) { + // spawn.mapRect(1200, -500, 100, 600); + // templePlayer.initialTrapY = Math.min(player.position.y, -75); + // trapPlayer(1000, templePlayer.initialTrapY); + + // addPartToMap(); + // simulation.draw.setPaths(); + // templePlayer.startAnim = 1; + // } + // }, + // room1() { + // WaveHandler.room1(); + // Objects.altar.logic(); + // }, + // room2() { + // room2SlimePit.logic(); + // Objects.room2Initiator.logic(); + // Objects.room2Lightning.logic(); + // Objects.room2GeneratedPath.logic(); + // WaveHandler.room2(); + // }, + // room3() { + // Objects.room3Rotors.logic(); + // Objects.room3SlimePits.logic(); + // WaveHandler.room3(); + // }, + // exit() { + // if (!templePlayer.drawExit) return; + // if (player.position.x > level.exit.x && + // player.position.x < level.exit.x + 100 && + // player.position.y > level.exit.y - 150 && + // player.position.y < level.exit.y - 40 && + // player.velocity.y < 0.1 && + // level.exitCount + (input.down ? 8 : 2) > 100) { + // if (templePlayer.stage === 1) { + // templePlayer.drawExit = false; + // templePlayer.room1ToRoom2Anim = 1; + // } else if (templePlayer.stage === 2) { + // templePlayer.drawExit = false; + // templePlayer.room2ToRoom3Anim = 1; + // } else { + // level.exitCount = 99 - (input.down ? 8 : 2); + // if (!templePlayer.clearedCycle) templePlayer.clearedCycle = simulation.cycle; + // } + // } + // } + // }; + // const DrawHandler = { + // // Bottom layer + // base() { + // // Draw base red background + // ctx.save(); + // ctx.setTransform(1, 0, 0, 1, 0, 0); + // ctx.fillStyle = color.map; + // ctx.fillRect(0, 0, canvas.width, canvas.height); + // ctx.restore(); + + // // Draw the normal bg on the bounds + // ctx.fillStyle = "#eab6af"; + // for (const b of bounds) { + // if (isInBound(b)) ctx.fillRect(b.pos.x + 2, b.pos.y + 2, b.width - 4, b.height - 4); + // } + // }, + // entrance() { + // ctx.beginPath(); + // ctx.moveTo(level.enter.x, level.enter.y + 30); + // ctx.lineTo(level.enter.x, level.enter.y - 80); + // ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80); + // ctx.lineTo(level.enter.x + 100, level.enter.y + 30); + // ctx.lineTo(level.enter.x, level.enter.y + 30); + // ctx.fillStyle = "#fca"; + // ctx.fill(); + // }, + // room1() { + // if (!isInBound(firstRoomBounds)) return; + + // // Draw Cross + // ctx.fillStyle = "#fed"; + // ctx.fillRect(2200, -3300, 200, 800); + // ctx.fillRect(2000, -3100, 600, 200); + + // // Final boss-like spawn fire thing. Was it necessary? No! + // const spawnFlameAngle = Math.min(Math.min(templePlayer.room1.cycles, 2520) % 600, 120) * Math.PI / 30 + Math.PI / 2; + // DrawTools.flame([2300, -3000, 26, 4, "#f60", spawnFlameAngle], 7); + + // Objects.altar.drawBottom(); + // }, + // room2() { + // if (!isInBound(secondRoomBounds)) return; + + // if (templePlayer.room2.cycles) { + // ctx.fillStyle = "#0006"; + // ctx.fillRect(secondRoomBounds.pos.x + 2, secondRoomBounds.pos.y + 2, secondRoomBounds.width - 4, secondRoomBounds.height - 4); + // } + // room2SlimePit.draw(); + // }, + // room3() { + // if (!isInBound(thirdRoomBounds)) return; + // ctx.fillStyle = "#0006"; + // ctx.fillRect(thirdRoomBounds.pos.x + 2, thirdRoomBounds.pos.y + 2, thirdRoomBounds.width - 4, thirdRoomBounds.height - 4); + // Objects.room3SlimePits.draw(); + // }, + // // Top layer + // mobTrails() { + // if (simulation.cycle % 4 === 0) { + // let newMobPositions = []; + // for (const i of mob) { + // if (!(i.isMACHO || i.isWIMP)) newMobPositions.push({ x: i.position.x, y: i.position.y }); + // } + // mobPositionsQueue.shift(); + // mobPositionsQueue.push(newMobPositions); + // } + // // Draw "holy" trails for mobs for no particular reason at all + // ctx.strokeStyle = "#bae"; + // ctx.lineWidth = 3; + // for (let i = 0; i < 10; i++) { + // const p = mobPositionsQueue[i]; + // for (const m of p) { + // DrawTools.holy(m.x, m.y, i / 2 + 10); + // } + // } + // ctx.shadowBlur = 0; + // }, + // waveTimer() { + // const roomConditions = [ + // isInBound(firstRoomBounds) && templePlayer.room1.cycles < 2400, + // isInBound(secondRoomBounds) && templePlayer.room2.cycles > 0 && templePlayer.room2.cycles < 2160, + // isInBound(thirdRoomBounds) && templePlayer.room2ToRoom3Anim < 1320 + // ]; + // Promise.resolve(roomConditions).then(roomConditions => { + // // First Room + // if (roomConditions[0]) { + // ctx.save(); + // ctx.setTransform(1, 0, 0, 1, 0, 0); + // ctx.fillStyle = "#0004"; + // ctx.fillRect(canvas.width2 - 288, 50, 576, 20); + // ctx.fillStyle = "#0cf"; + // ctx.fillRect(canvas.width2 - 288, 50, 0.8 * (600 - templePlayer.room1.cycles % 600), 20); + // ctx.restore(); + // } + // // Second Room + // if (roomConditions[1]) { + // ctx.save(); + // ctx.setTransform(1, 0, 0, 1, 0, 0); + // ctx.fillStyle = "#0004"; + // ctx.fillRect(canvas.width2 - 288, 50, 576, 20); + // ctx.fillStyle = (Math.ceil(templePlayer.room2.cycles / 720) & 1) ? "#000" : "#e1d7ff"; + // ctx.fillRect(canvas.width2 - 288, 50, 0.8 * (720 - templePlayer.room2.cycles % 720), 20); + // ctx.restore(); + // } + // // Third Room + // if (roomConditions[2]) { + // ctx.save(); + // ctx.setTransform(1, 0, 0, 1, 0, 0); + // ctx.fillStyle = "#0004"; + // ctx.fillRect(canvas.width2 - 288, 50, 576, 20); + // ctx.fillStyle = "#000"; + // ctx.fillRect(canvas.width2 - 288, 50, 1.6 * (1320 - templePlayer.room2ToRoom3Anim), 20); + // ctx.restore(); + // } + // }); + // }, + // room2Top() { + // if (!isInBound(secondRoomBounds)) return; + // Objects.room2Lightning.draw(); + // Objects.room2GeneratedPath.draw(); + // Objects.room2Initiator.draw(); + // } + // }; + // const WaveHandler = { + // room1() { + // if (!isInBound(firstRoomBounds)) return; + // if (templePlayer.room1.cycles === 0) powerUps.spawnStartingPowerUps(0, -2050); + // templePlayer.room1.cycles++; + // if (templePlayer.room1.cycles === 2400) { + // spawn.secondaryBossChance(2300, -2800); + // powerUps.addResearchToLevel(); + // } + // if (templePlayer.room1.cycles % 600 === 0 && templePlayer.room1.cycles <= 2400) { + // const spawnAmt = Math.min(3 + Math.pow(simulation.difficulty / 1.7, 0.6), 10) + Math.floor(templePlayer.room1.cycles / 720); + // for (let i = 0; i < spawnAmt; i++) { + // if (Math.random() < 0.5 + 0.07 * simulation.difficulty) { + // spawn.randomMob(800 + Math.random() * 3e3, -2400 - Math.random() * 600, Infinity); + // } + // } + // spawn.randomMob(800 + Math.random() * 3e3, -2400 - Math.random() * 600, Infinity); + // } + // if (templePlayer.room1.cycles === 2520) { + // templePlayer.drawExit = true; + // } + // }, + // room2() { + // if (!isInBound(secondRoomBounds)) return; + // if (templePlayer.room2.spawnInitiatorCycles > Objects.room2Initiator.cap) { + // if (templePlayer.room2.cycles % 720 === 0 && templePlayer.room2.cycles <= 2160) { + // const isOdd = Math.floor(templePlayer.room2.cycles / 720) & 1; + // secondRoomBoss(-600, -9800, 25, isOdd); + // secondRoomBoss(600, -9800, 25, isOdd); + // secondRoomBoss(0, -9800, 25, !isOdd); + // } + // templePlayer.room2.cycles++; + // if (templePlayer.room2.cycles === 2400) { + // templePlayer.drawExit = true; + // templePlayer.room2.readyPathCycle = simulation.cycle; + // } + // } + // }, + // room3() { + // if (templePlayer.room2ToRoom3Anim === 1320) { + // thirdRoomBoss(1800, -13700); + // for (let i = 0; i < 3; i++) { + // powerUps.spawn(m.spawnPos.x, m.spawnPos.y, "heal"); + // } + // } + // } + // }; + // const DrawTools = { + // get randomColours() { + // return `rgb(${this._randomColours.join(",")})` + // }, + // _randomColours: [Math.random() * 255, Math.random() * 255, Math.random() * 255], + // updateRandomColours(x = 0.8) { + // for (let i = 0; i < this._randomColours.length; i++) { + // this._randomColours[i] = Math.max(Math.min(this._randomColours[i] + (this.randFact() * x * 2) - x, 255), 0); + // } + // }, + // randFact() { + // return Math.random() * 0.8 + Math.sin(Date.now() / 300) * 0.2; + // }, + + // line(vecs) { + // ctx.beginPath(); + // ctx.moveTo(vecs[0].x, vecs[0].y); + // for (const v of vecs.slice(1)) ctx.lineTo(v.x, v.y); + // ctx.stroke(); + // }, + // arc(...x) { + // ctx.beginPath(); + // ctx.arc(...x); + // ctx.fill(); + // }, + // arcOut(...x) { + // ctx.beginPath(); + // ctx.arc(...x); + // ctx.stroke(); + // }, + // flame(props, repeat) { + // for (let i = 0; i < repeat; i++) this.singleFlame(...props); + // }, + // singleFlame(x, y, size = 10, repeat = 3, color = "#f00", angle = Math.PI / 2) { + // ctx.strokeStyle = color; + // ctx.lineWidth = 3; + // const path = [{ x, y }]; + // for (let i = 0; i < repeat; i++) { + // const randAng = (Math.random() - 0.5) * 2 + angle; + // const randLen = 2 * size + Math.random() * size; + + // x += Math.cos(randAng) * randLen; + // y -= Math.sin(randAng) * randLen; + // path.push({ x, y }) + // } + // DrawTools.line(path); + // }, + // lightning(from, to, cycle, randomPRNGMult = 1, width = 8, color = [255, 240, 127]) { + // const diff = simulation.cycle - cycle; + // if (diff >= 15) return; + // ctx.strokeStyle = `rgba(${color.join(",")},${(1 - diff / 15) * 255})`; + // ctx.lineWidth = width * (1 - diff / 15); + // ctx.shadowColor = `rgb(${color.join(",")})`; + // ctx.shadowBlur = 20; + // const path = [{ x: from.x, y: from.y }]; + // let vector = { x: from.x, y: from.y }; + // let distanceLeft = V.magnitude(V.sub(from, to)); + // const d = distanceLeft > 800 ? distanceLeft / 40 : 20; + // const normalised = V.normalise(V.sub(to, from)); + // while (1) { + // const randOffset = rotateVector({ y: RNG(Math.floor(cycle * randomPRNGMult + distanceLeft)) * 2 * d - d, x: 0 }, normalised); + // const randLen = RNG(Math.floor(cycle * (randomPRNGMult + 1) + distanceLeft)) * d + d; + // distanceLeft -= randLen; + // if (distanceLeft <= 0) { + // path.push({ x: to.x, y: to.y }); + // break; + // } + // vector = V.add(vector, V.mult(normalised, randLen)); + // path.push({ x: vector.x + randOffset.x, y: vector.y + randOffset.y }); + // } + // DrawTools.line(path); + // ctx.shadowBlur = 0; + // }, + // holy(x, y, size = 12) { + // this.line([{ x, y: y - size }, { x: x - size, y }, + // { x, y: y + size }, { x: x + size, y }, { x, y: y - size } + // ]); + // } + // }; + + // function RNG(x) { + // x += Math.seed; + // let start = Math.pow(x % 97, 4.3) * 232344573; + // const a = 15485863; + // const b = 521791; + // start = (start * a) % b; + // for (let i = 0; i < (x * x) % 90 + 90; i++) { + // start = (start * a) % b; + // } + // return start / b; + // } + + // function rotateVector(v, ang) { + // const c = typeof ang === "number" ? { x: Math.cos(ang), y: Math.sin(ang) } : V.normalise(ang); + // return { x: v.x * c.x - v.y * c.y, y: v.y * c.x + v.x * c.y }; + // } + + // function trapPlayer(x, y) { + // setPosAndFreeze(player, { x, y }); + // const bLen = bullet.length; + // for (let i = 0; i < bLen; i++) { + // if (bullet[i].botType) setPosAndFreeze(bullet[i], V.add(player.position, { x: 100 * (RNG(i) - 0.5), y: 100 * (RNG(i + bLen) - 0.5) })); + // } + // } + + // function relocateTo(x, y) { + // level.setPosToSpawn(x, y); + // trapPlayer(x, y); + // for (let i = 0; i < mob.length; i++) { + // if (mob[i].isMACHO) { + // setPos(mob[i], { x, y }); + // break; + // } + // } + // m.resetHistory(); + // } + // const distance = (a, b) => V.magnitude(V.sub(a, b)); + // const angle = (a, b) => Math.atan2(b.y - a.y, a.x - b.x); + // const setPos = (a, b) => Matter.Body.setPosition(a, b); + // const setVel = (a, b) => Matter.Body.setVelocity(a, b); + // const freeze = a => setVel(a, { x: 0, y: 0 }); + // const setPosAndFreeze = (a, b) => { + // setPos(a, b); + // freeze(a); + // }; + // const makeLore = x => simulation.makeTextLog(`

${name}:

 

${x}

`); + // // TODO: Remove this before merging + // window.TempleHelper = { + // skipInitial() { + // templePlayer.startAnim = 360; + // }, + // skipWaves() { + // this.skipInitial(); + // templePlayer.room1.cycles = 2500; + // }, + // skipToRoom2() { + // this.skipInitial(); + // templePlayer.room1ToRoom2Anim = 1; + // }, + // skipBossWaves() { + // this.skipToRoom2(); + // templePlayer.room2.spawnInitiatorCycles = Objects.room2Initiator.cap; + // templePlayer.room2.cycles = 2200; + // setTimeout(() => trapPlayer(0, -9100), 500); + // }, + // skipToRoom3() { + // this.skipToRoom2(); + // requestAnimationFrame(() => templePlayer.room2ToRoom3Anim = 1); + // }, + // spawnSecondRoomBoss(x, y) { + // secondRoomBoss(x, y); + // } + // }; + // level.custom = () => { + // // All the logic gets handled here. How nice! + // for (const i in LogicHandler) { + // LogicHandler[i](); + // } + + // // Animations and lore for things that seem like exits + // for (const i in RoomTransitionHandler) { + // RoomTransitionHandler[i](); + // } + + // // Bottom layer graphics + // DrawHandler.base(); + // DrawHandler.room1(); + // DrawHandler.room2(); + // DrawHandler.room3(); + // DrawHandler.entrance(); + // if (templePlayer.drawExit) level.exit.drawAndCheck(); + // }; + // level.customTopLayer = () => { + // // Top layer graphics + // DrawHandler.mobTrails(); + // Objects.altar.drawTop(); + // DrawHandler.waveTimer(); + // DrawHandler.room2Top(); + // }; + // }, dripp() { simulation.makeTextLog(`dripp by M. B.`); diff --git a/js/player.js b/js/player.js index 798c554..0840f95 100644 --- a/js/player.js +++ b/js/player.js @@ -3297,7 +3297,7 @@ const m = { Matter.Composite.remove(engine.world, body[i]); body.splice(i, 1); m.fieldRange *= 0.8 - if (tech.isWormholeEnergy) m.energy += 0.53 + if (tech.isWormholeEnergy) m.energy += 0.5 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)); @@ -3320,7 +3320,7 @@ const m = { body.splice(i, 1); m.fieldRange *= 0.8 // if (tech.isWormholeEnergy && m.energy < m.maxEnergy * 2) m.energy = m.maxEnergy * 2 - if (tech.isWormholeEnergy && m.immuneCycle < m.cycle) m.energy += 0.53 + if (tech.isWormholeEnergy && m.immuneCycle < m.cycle) m.energy += 0.5 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()))) Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 5)); diff --git a/js/tech.js b/js/tech.js index 90b3657..f066287 100644 --- a/js/tech.js +++ b/js/tech.js @@ -256,7 +256,7 @@ const tech = { return dmg * tech.slowFire * tech.aimDamage }, duplicationChance() { - return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) + tech.isQuantumEraserDuplication) + return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) + tech.isQuantumEraserDuplication * (1 - 0.01 * (simulation.difficultyMode ** 2))) }, isScaleMobsWithDuplication: false, maxDuplicationEvent() { @@ -812,7 +812,7 @@ const tech = { { name: "microstates", link: `microstates`, - description: "for each active bullets / bots
+0.7% damage", + description: "for each active bullet / bot
+0.7% damage", maxCount: 1, count: 0, frequency: 1, @@ -3998,7 +3998,7 @@ const tech = { }, { name: "supercritical fission", - description: "if bullets strike mobs near their center
they can explode (nails, needles, rivets)", + description: "if nails, needles, or rivets strike mobs
near their center they can explode", isGunTech: true, maxCount: 1, count: 0, @@ -5867,7 +5867,7 @@ const tech = { allowed() { return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock }, - requires: "harpoon, not railgun, UHMWPE, toggling harpoon, Higgs mechanism", + requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism", effect() { tech.isGrapple = true; for (i = 0, len = b.guns.length; i < len; i++) { //find which gun @@ -6061,7 +6061,7 @@ const tech = { effect() { let techGiven = 0 for (let j = 0; j < 3; j++) { - const names = ["laser diode", "free-electron laser", "relativistic momentum", "specular reflection", "diffraction grating", "diffuse beam", "output coupler", "slow light"] + const names = ["lens", "arc length", "laser diode", "free-electron laser", "relativistic momentum", "specular reflection", "diffraction grating", "diffuse beam", "output coupler", "slow light"] //convert names into indexes const options = [] for (let i = 0; i < names.length; i++) { @@ -6089,7 +6089,7 @@ const tech = { } if (techGiven > 0) { tech.isStuckOn = true - } else { + } else { //eject if none found simulation.makeTextLog(`0 tech found //optical amplifier`); const loop = () => { if (!simulation.paused && m.alive) { @@ -6157,7 +6157,7 @@ const tech = { }, { name: "relativistic momentum", - description: "all lasers push mobs and blocks
affects laser-gun, laser-bot, and laser-mines", + description: "lasers push mobs and blocks", isGunTech: true, maxCount: 1, count: 0, @@ -6174,9 +6174,69 @@ const tech = { tech.isLaserPush = false; } }, + { + name: "iridescence", + // description: "if a laser hits a mob at a low angle of illumination
+66% laser damage", + description: "if mobs are struck near their center
+66% laser damage", + isGunTech: true, + maxCount: 3, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade || tech.isLaserMine + }, + requires: "laser, not pulse", + effect() { + tech.laserCrit = true; + }, + remove() { + tech.laserCrit = false; + } + }, + { + name: "lens", + description: "if directed through a revolving π / 4 circular arc
+150% laser gun damage", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.haveGunCheck("laser") + }, + requires: "laser", + effect() { + tech.isLaserLens = true + b.guns[11].chooseFireMethod() + }, + remove() { + tech.isLaserLens = false + b.guns[11].chooseFireMethod() + } + }, + { + name: "arc length", + description: "increase the circular arc of your laser lens
by +π / 4", + isGunTech: true, + maxCount: 3, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isLaserLens && tech.haveGunCheck("laser") + }, + requires: "laser gun, lens", + effect() { + b.guns[11].arcRange += 0.78 + }, + remove() { + b.guns[11].arcRange = 0.78 + } + }, { name: "specular reflection", - description: "+2 laser reflections
affects laser-gun, laser-bot, and laser-mines", + description: "+2 laser beam reflections", isGunTech: true, maxCount: 3, count: 0, @@ -6195,7 +6255,7 @@ const tech = { }, { name: "diffraction grating", - description: `+1 angled laser gun beam`, + description: `+1 laser gun beam`, isGunTech: true, maxCount: 9, count: 0, @@ -6207,23 +6267,19 @@ const tech = { requires: "laser gun, not neocognitron, diffuse beam, or slow light", effect() { tech.beamSplitter++ - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() }, remove() { if (tech.beamSplitter !== 0) { tech.beamSplitter = 0 - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() } } }, { name: "diffuse beam", link: `diffuse beam`, - description: "laser beam is wider and doesn't reflect
+220% laser damage", + description: "laser gun beam is wider and doesn't reflect
+220% laser damage", isGunTech: true, maxCount: 1, count: 0, @@ -6236,23 +6292,19 @@ const tech = { effect() { if (tech.wideLaser === 0) tech.wideLaser = 3 tech.isWideLaser = true; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() }, remove() { if (tech.isWideLaser) { // tech.wideLaser = 0 tech.isWideLaser = false; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() } } }, { name: "output coupler", - description: "+30% laser beam width
+30% laser damage", + description: "+30% laser gun beam width
+30% laser damage", isGunTech: true, maxCount: 9, count: 0, @@ -6264,9 +6316,7 @@ const tech = { requires: "laser gun, diffuse beam", effect() { tech.wideLaser += 2 - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() }, remove() { if (tech.isWideLaser) { @@ -6274,14 +6324,12 @@ const tech = { } else { tech.wideLaser = 0 } - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() } }, { name: "slow light", - description: "laser beam is spread into your recent past
+300% total beam damage", + description: "laser gun beam is spread into your recent past
+300% total beam damage", isGunTech: true, maxCount: 9, count: 0, @@ -6294,17 +6342,13 @@ const tech = { effect() { // this.description = `add 5 more laser beams into into your past` tech.historyLaser++ - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() }, remove() { // this.description = "laser beam is spread into your recent past
increase total beam damage by 300%" if (tech.historyLaser) { tech.historyLaser = 0 - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() } } }, @@ -6322,16 +6366,12 @@ const tech = { requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier", effect() { tech.isPulseLaser = true; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() }, remove() { if (tech.isPulseLaser) { tech.isPulseLaser = false; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() - } + b.guns[11].chooseFireMethod() } } }, @@ -6918,25 +6958,6 @@ const tech = { // tech.isPlasmaRange = 1; // } // }, - { - name: "degenerate matter", - description: "if your field is active
+75% defense", - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isEnergyHealth - }, - requires: "plasma torch, perfect diamagnetism, pilot wave, not mass-energy", - effect() { - tech.isHarmReduce = true - }, - remove() { - tech.isHarmReduce = false; - } - }, { name: "tokamak", description: "throwing a block converts it into energy
and a pulsed fusion explosion", @@ -6956,6 +6977,25 @@ const tech = { tech.isTokamak = false; } }, + { + name: "degenerate matter", + description: "if your field is active
+75% defense", + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isEnergyHealth + }, + requires: "plasma torch, perfect diamagnetism, pilot wave, not mass-energy", + effect() { + tech.isHarmReduce = true + }, + remove() { + tech.isHarmReduce = false; + } + }, { name: "plasma-bot", link: `plasma-bot`, @@ -7195,6 +7235,8 @@ const tech = { }, { name: "quantum eraser", + descriptionFunction() { return `for each mob left alive after you exit a level
kill a mob as they spawn at ${100-simulation.difficultyMode**2}% duplication
` }, + description: `for each mob left alive after you exit a level
kill a mob as they spawn at 100% duplication
`, isFieldTech: true, maxCount: 1, @@ -7366,8 +7408,8 @@ const tech = { isFieldTech: true, maxCount: 9, count: 0, - frequency: 1, - frequencyDefault: 1, + frequency: 2, + frequencyDefault: 2, allowed() { return m.fieldUpgrades[m.fieldMode].name === "wormhole" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation" }, @@ -7383,33 +7425,33 @@ const tech = { }, { name: "virtual particles", - description: `use ${powerUps.orb.research(4)}to exploit your field for a
+12% chance to duplicate spawned power ups`, + description: `use ${powerUps.orb.research(6)}to exploit your field for a
+11% chance to duplicate spawned power ups`, isFieldTech: true, maxCount: 1, count: 0, frequency: 3, frequencyDefault: 3, allowed() { - return (m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "wormhole") && (build.isExperimentSelection || powerUps.research.count > 3) + return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "wormhole") && (build.isExperimentSelection || powerUps.research.count > 3) }, - requires: "wormhole, time dilation, negative mass", + requires: "wormhole, time dilation, negative mass, pilot wave", effect() { - tech.fieldDuplicate = 0.12 + tech.fieldDuplicate = 0.11 powerUps.setDupChance(); //needed after adjusting duplication chance if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.13); - for (let i = 0; i < 4; i++) { + for (let i = 0; i < 6; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) } }, remove() { tech.fieldDuplicate = 0 powerUps.setDupChance(); //needed after adjusting duplication chance - if (this.count > 0) powerUps.research.changeRerolls(4) + if (this.count > 0) powerUps.research.changeRerolls(6) } }, { name: "Penrose process", - description: "after a block falls into a wormhole
+53 energy", + description: "after a block falls into a wormhole
+50 energy", isFieldTech: true, maxCount: 1, count: 0, @@ -7448,7 +7490,7 @@ const tech = { }, { name: "geodesics", - description: `your projectiles can traverse wormholes
spawn 2 guns and ${powerUps.orb.ammo(4)}`, + description: `your bullets can traverse wormholes
spawn 2 guns and ${powerUps.orb.ammo(4)}`, isFieldTech: true, maxCount: 1, count: 0, @@ -7474,7 +7516,7 @@ const tech = { }, { name: "cosmic string", - description: "after tunneling through mobs with a wormhole
stun then and do radioactive damage", + description: "after tunneling through mobs with a wormhole
stun then and do radioactive damage", isFieldTech: true, maxCount: 1, count: 0, @@ -10429,5 +10471,7 @@ const tech = { isQuantumEraserDuplication: null, quantumEraserCount: null, isPhononBlock: null, - isMicroTransactions: null + isMicroTransactions: null, + isLaserLens: null, + laserCrit: null } \ No newline at end of file diff --git a/todo.txt b/todo.txt index d4e8077..a607401 100644 --- a/todo.txt +++ b/todo.txt @@ -1,33 +1,38 @@ ******************************************************** NEXT PATCH ************************************************** +tech: iridescence - laser does 100% damage to mobs hit near their center +tech: lens - laser does extra damage if you fire through a lens that revolves around you + tech: arc length - increase the size of the lens -tech: resonance - when a block gets vibrated by phonon, it has a chance to spin towards mobs -cross disciplinary gives 4% duplication -boson composite lets you move through elevators again - -JUNK tech: microtransactions - buy in-game skins for 1 research anytime you choose a tech +virtual particles costs 4->6 research for 11% duplication +quantum eraser has less duplication chance at higher difficulty modes +community map temple updates bug fixes - *********************************************************** TODO ***************************************************** -make buying skins from microtransactions have a lasting effect with a local storage list - add a dropdown menu to choose in settings - maybe just one at a time +give laser gun _____ if you fire in an angle range + draw angle range as a slowly rotation circle arc around player + effect: + bonus damage + extra beams + extra reflections -JUNK tech micro transactions - all tech selection menus include the option to buy skins for 1 research - -improve mob invincible graphic - opacity oscillates from 100% to 0%? - make different from stun +laser tech: critical hits do _______ damage? + name? polarized light, iridescence hopBossMom spawns lots of small hopBullets drops eggs, that hatch into hopBullets like sporangium normally runs away from player, but goes closer to drop eggs + +level element: exploding barrels + +improve mob invincible graphic + opacity oscillates from 100% to 0%? + make different from stun junk tech give strange CSS to a keyword @keyframes bounce-munch { @@ -38,14 +43,6 @@ junk tech give strange CSS to a keyword make plasma ball power up and block pick up still work when you have no no energy make a unique CD var for plasma ball? -give laser gun _____ if you fire in an angle range - draw angle range as a slowly rotation circle arc around player - effect: - bonus damage - extra beams - extra reflections - - wormhole tech: entropic gravity - gain defense for each research requires wormhole or negative mass field or pilot wave