From 06c12858283d3cb7b97560717f6e8a223fe90128 Mon Sep 17 00:00:00 2001 From: landgreen Date: Mon, 30 May 2022 12:28:05 -0700 Subject: [PATCH] propagator tech: propagator - 67% damage, lose 1/2 second of time when a mob dies timeSkipBoss is back, maybe it will not cause bugs this time immune to harm unless player is inside horizon player loses time when inside horizon snake bosses are immune to harm until your remove their tail mob shields are 30% stronger time dilation: retrocausality automatically grabs power ups eternalism 50->40% damage paradigm shift 10->16% chance to get a research when ejecting tech reaction inhibitor 11->13% mob health reduction recycling 1->0.5% health for 5 seconds up to 2.5% per mob kill at normal max health bug fixes --- .DS_Store | Bin 6148 -> 6148 bytes js/bullet.js | 14 +- js/engine.js | 2 +- js/index.js | 4 +- js/level.js | 18 +-- js/mob.js | 18 ++- js/player.js | 37 +++--- js/powerup.js | 7 +- js/simulation.js | 6 +- js/spawn.js | 330 +++++++++++++++++++++++++++++------------------ js/tech.js | 121 ++++++++++++++--- todo.txt | 70 +++++----- 12 files changed, 407 insertions(+), 220 deletions(-) diff --git a/.DS_Store b/.DS_Store index 461e3353cbecdd215b602891f8039b3a4ed37021..2bf93988860c837ce228eb88b1778a8841b9b0a8 100644 GIT binary patch delta 23 ecmZoMXffEJ$;_-Q(l=R$*_TO0U~@Hdrw9N{_y!;V delta 23 ecmZoMXffEJ$;_ { if (this.endCycle < simulation.cycle + 1) this.isWave = false } - } else { //check if inside a body + } else { //check if inside a mob for (let i = 0, len = mob.length; i < len; i++) { const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) const radius = mob[i].radius + tech.extruderRange / 2 @@ -2387,14 +2387,14 @@ const b = { } if (tech.isLaserPush) { //push mobs away const index = path.length - 1 - Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.94, y: best.who.velocity.y * 0.94 }); - const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.006 * push * Math.min(6, best.who.mass)) + Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.95, y: best.who.velocity.y * 0.95 }); + const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.005 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } } else if (tech.isLaserPush && best.who.classType === "body") { const index = path.length - 1 - Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.94, y: best.who.velocity.y * 0.94 }); - const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.006 * push * Math.min(6, best.who.mass)) + Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.95, y: best.who.velocity.y * 0.95 }); + const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.005 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } }; @@ -6996,7 +6996,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.66 * tech.laserDamage // 3.5 * 0.55 = 200% more damage + const dmg = 0.70 * tech.laserDamage // 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), diff --git a/js/engine.js b/js/engine.js index 6129600..855a607 100644 --- a/js/engine.js +++ b/js/engine.js @@ -198,7 +198,7 @@ function collisionChecks(event) { const v = Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)); if (v > 9) { if (tech.blockDmg) { //electricity - console.log("hi") + // console.log("hi") Matter.Body.setVelocity(mob[k], { x: 0.5 * mob[k].velocity.x, y: 0.5 * mob[k].velocity.y }); if (tech.isBlockRadiation && !mob[k].isShielded && !mob[k].isMobBullet) { mobs.statusDoT(mob[k], tech.blockDmg * m.dmgScale * 4 / 12, 360) //200% increase -> x (1+2) //over 7s -> 360/30 = 12 half seconds -> 3/12 diff --git a/js/index.js b/js/index.js index 89aa3e2..bbb4704 100644 --- a/js/index.js +++ b/js/index.js @@ -187,7 +187,7 @@ window.addEventListener('load', () => { const canvas = document.getElementById("canvas"); //using "const" causes problems in safari when an ID shares the same name. const ctx = canvas.getContext("2d"); -// const ctx = canvas.getContext('2d', { alpha: false }); //optimization, but doesn't work +// const ctx = canvas.getContext('2d', { alpha: false }); //optimization, this works if you wipe with the background color of each level document.body.style.backgroundColor = "#fff"; @@ -278,7 +278,7 @@ ${simulation.isCheating ? "

lore disabled": ""} if (tech.tech[i].count > 0) { const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; if (tech.tech[i].isNonRefundable) { - text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` } else if (tech.tech[i].isFieldTech) { text += `
diff --git a/js/level.js b/js/level.js index b859f56..c7c8af0 100644 --- a/js/level.js +++ b/js/level.js @@ -17,10 +17,10 @@ const level = { if (level.levelsCleared === 0) { //this code only runs on the first level // // simulation.isHorizontalFlipped = true // m.addHealth(Infinity) - // m.setField("standing wave") + // m.setField("time dilation") // b.giveGuns("nail gun") // tech.giveTech("closed timelike curve") - // tech.giveTech("irradiated nails") + // tech.giveTech("retrocausality") // tech.giveTech("pneumatic actuator") // tech.giveTech("6s half-life") // for (let i = 0; i < 10; i++) tech.giveTech("replication") @@ -36,8 +36,8 @@ const level = { // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // simulation.enableConstructMode() //used to build maps in testing mode // level.testing(); - // level.reactor(); //not in rotation, used for testing - // spawn.timeBoss(1900, -500) + // spawn.snakeSpitBoss(1900, -500) + // level.reservoir(); //not in rotation, used for testing if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ // powerUps.research.changeRerolls(3000) @@ -2681,7 +2681,7 @@ const level = { // spawn.shieldingBoss(1700, -500) // for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40); - // for (let i = 0; i < 4; i++) spawn.starter(1900, -500) + for (let i = 0; i < 4; i++) spawn.starter(1900, -500) // spawn.pulsar(1900, -500) // spawn.shield(mob[mob.length - 1], 1900, -500, 1); // mob[mob.length - 1].isShielded = true @@ -3294,8 +3294,8 @@ const level = { } //2nd floor - spawn.mapVertex(855, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); - spawn.mapVertex(-687, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); + spawn.mapVertex(-687, -1936, "-625 50 0 100 625 50 625 -50 -625 -50"); + spawn.mapVertex(855, -1936, "-625 50 0 100 625 50 625 -50 -625 -50"); //2nd floor right building // spawn.mapRect(550, -3050, 600, 175); @@ -3328,11 +3328,11 @@ const level = { spawn.randomMob(950, -1725, 0.1); spawn.randomMob(-725, -1775, 0.1); spawn.randomMob(-200, -2075, 0); + spawn.randomMob(-550, -3500, -0.2); spawn.randomMob(375, -2125, 0); - spawn.randomMob(1025, -3200, 0); - spawn.randomMob(-550, -3500, 0); spawn.randomMob(-700, -2450, -0.1); spawn.randomMob(-1175, -2775, -0.1); + spawn.randomMob(1025, -3200, -0.2); spawn.randomMob(-525, -3750, -0.2); spawn.randomMob(1350, -2075, -0.3); spawn.randomMob(1775, 1000, -0.4); diff --git a/js/mob.js b/js/mob.js index 0197f71..e18a81f 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1119,7 +1119,7 @@ const mobs = { if (tech.iceIXOnDeath && this.isSlowed) { for (let i = 0, len = 2 * Math.sqrt(Math.min(this.mass, 25)) * tech.iceIXOnDeath; i < len; i++) b.iceIX(3, Math.random() * 2 * Math.PI, this.position) } - if (tech.deathSpawnsFromBoss || (tech.deathSpawns && this.isDropPowerUp)) { + if (tech.deathSpawnsFromBoss || tech.deathSpawns) { const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns)) for (let i = 0; i < len; i++) { @@ -1130,6 +1130,22 @@ const mobs = { }); } } + + if (tech.isDeathSkipTime && !m.isBodiesAsleep) { + requestAnimationFrame(() => { + simulation.timePlayerSkip(this.isBoss ? 45 : 25) + simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations + }); //wrapping in animation frame prevents errors, probably + + // if (tech.isFlipFlopOn) { + // m.rewind(this.isBoss ? 45 : 25) + // } else { + // requestAnimationFrame(() => { + // simulation.timePlayerSkip(this.isBoss ? 45 : 25) + // simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations + // }); //wrapping in animation frame prevents errors, probably + // } + } if (tech.isEnergyLoss) m.energy *= 0.75; 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() diff --git a/js/player.js b/js/player.js index 615ae94..dfd14f6 100644 --- a/js/player.js +++ b/js/player.js @@ -2529,6 +2529,25 @@ const m = { this.rewindCount = 0 m.grabPowerUpRange2 = 300000 m.hold = function() { + + m.grabPowerUp(); + + // //grab power ups + // for (let i = 0, len = powerUp.length; i < len; ++i) { + // if ( + // Vector.magnitudeSquared(Vector.sub(m.pos, powerUp[i].position)) < 100000 && + // !simulation.isChoosing && + // (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) + // ) { + // powerUps.onPickUp(powerUp[i]); + // powerUp[i].effect(); + // Matter.Composite.remove(engine.world, powerUp[i]); + // powerUp.splice(i, 1); + // break; //because the array order is messed up after splice + // } + // } + + if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -2568,20 +2587,6 @@ const m = { } else { m.undoCrouch() } - //grab power ups - for (let i = 0, len = powerUp.length; i < len; ++i) { - if ( - Vector.magnitudeSquared(Vector.sub(m.pos, powerUp[i].position)) < 100000 && - !simulation.isChoosing && - (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) - ) { - powerUps.onPickUp(powerUp[i]); - powerUp[i].effect(); - Matter.Composite.remove(engine.world, powerUp[i]); - powerUp.splice(i, 1); - break; //because the array order is messed up after splice - } - } if (!(this.rewindCount % 30)) { if (tech.isRewindBot) { for (let i = 0; i < tech.isRewindBot; i++) { @@ -2594,8 +2599,6 @@ const m = { const who = bullet[bullet.length - 1] who.endCycle = simulation.cycle + 60 } - - } } } @@ -2612,7 +2615,7 @@ const m = { } else { m.fieldFire = true; m.isBodiesAsleep = false; - m.drain = 0.003 + m.drain = 0.0025 m.hold = function() { if (m.isHolding) { m.wakeCheck(); diff --git a/js/powerup.js b/js/powerup.js index a726a19..b4eca9b 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -137,7 +137,7 @@ const powerUps = { }, doDefault() { //draw power ups - ctx.globalAlpha = 0.4 * Math.sin(m.cycle * 0.15) + 0.6; + ctx.globalAlpha = 0.4 * Math.sin(simulation.cycle * 0.15) + 0.6; for (let i = 0, len = powerUp.length; i < len; ++i) { ctx.beginPath(); ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI); @@ -237,7 +237,6 @@ const powerUps = { } }, choose(type, index) { - console.log('choose') if (type === "gun") { b.giveGuns(index) let text = `b.giveGuns("${b.guns[index].name}")` @@ -356,7 +355,7 @@ const powerUps = { // document.body.style.overflow = "hidden" // if (m.alive){} if (simulation.paused) requestAnimationFrame(cycle); - simulation.paused = false; + if (m.alive) simulation.paused = false; simulation.isChoosing = false; //stops p from un pausing on key down build.unPauseGrid() if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles @@ -1080,7 +1079,7 @@ const powerUps = { }, pauseEjectTech(index) { if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) { - if (Math.random() < 0.1 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) { + if (Math.random() < 0.16 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) { tech.removeTech(index) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); } else { diff --git a/js/simulation.js b/js/simulation.js index 80ab6aa..9ef1c34 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -521,9 +521,7 @@ const simulation = { } }, len * swapPeriod); }, - wipe() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - }, + wipe() {}, //set in simulation.startGame gravity() { function addGravity(bodies, magnitude) { for (var i = 0; i < bodies.length; i++) { @@ -1049,7 +1047,7 @@ const simulation = { if (m.lastKillCycle + 300 > m.cycle) { //effects active for 5 seconds after killing a mob if (tech.isEnergyRecovery && m.immuneCycle < m.cycle) m.energy += m.maxEnergy * 0.05 - if (tech.isHealthRecovery) m.addHealth(0.01 * m.maxHealth) + if (tech.isHealthRecovery) m.addHealth(0.005 * m.maxHealth) } if (!(m.cycle % 420)) { //once every 7 seconds diff --git a/js/spawn.js b/js/spawn.js index 8f12bd5..37f9ba8 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1,10 +1,11 @@ //main object for spawning things in a level const spawn = { nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"], - // other bosses: suckerBoss, laserBoss, tetherBoss, mantisBoss, bounceBoss, sprayBoss //these need a particular level to work so they are not included in the random pool - randomBossList: ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", - "powerUpBoss", "powerUpBossBaby", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", - "snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss" + // other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss //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", + "powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", + "snakeBoss", "snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "shieldingBoss", "timeSkipBoss" ], bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed bossTypeSpawnIndex: 0, //increases as the boss type cycles @@ -19,7 +20,7 @@ const spawn = { pickList: ["starter", "starter"], fullPickList: [ "hopper", "hopper", "hopper", - "slasher", "slasher", "hopper", + "slasher", "slasher", "slasher", "stabber", "stabber", "stabber", "springer", "springer", "springer", "shooter", "shooter", @@ -2028,7 +2029,6 @@ const spawn = { me.seePlayerFreq = 300; const springStiffness = 0.00008; //simulation.difficulty const springDampening = 0.01; - me.springTarget = { x: me.position.x, y: me.position.y @@ -2055,11 +2055,9 @@ const spawn = { Composite.add(engine.world, cons[cons.length - 1]); cons[len2].length = 100 + 1.5 * radius; me.cons2 = cons[len2]; - me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.invulnerabilityCountDown = 0 - me.do = function() { this.checkStatus(); this.gravity(); @@ -2069,7 +2067,6 @@ const spawn = { ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI); ctx.fillStyle = "#222"; ctx.fill(); - this.seePlayerCheck() // this.seePlayerByHistory() if (this.isInvulnerable) { @@ -2202,7 +2199,6 @@ const spawn = { } } }; - me.onDeath = function() { this.removeCons(); if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y) @@ -2215,7 +2211,6 @@ const spawn = { } } }; - const sideLength = 80 // distance between each node mob const nodes = 3 const angle = 2 * Math.PI / nodes @@ -2255,7 +2250,6 @@ const spawn = { } }; } - const stiffness = 0.01 const damping = 0.1 for (let i = 1; i < nodes; ++i) { //attach to center mob @@ -2287,88 +2281,86 @@ const spawn = { } spawn.allowShields = true; }, - timeSkipBoss(x, y, radius = 55) { - mobs.spawn(x, y, 6, radius, '#000'); - let me = mob[mob.length - 1]; - me.isBoss = true; - // me.stroke = "transparent"; //used for drawSneaker - me.timeSkipLastCycle = 0 - me.eventHorizon = 1800; //required for black hole - me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000 - me.accelMag = 0.0004 * simulation.accelScale; - // me.frictionAir = 0.005; - // me.memory = 1600; - // Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger - Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - spawn.shield(me, x, y, 1); + // timeSkipBoss(x, y, radius = 55) { + // mobs.spawn(x, y, 6, radius, '#000'); + // let me = mob[mob.length - 1]; + // me.isBoss = true; + // // me.stroke = "transparent"; //used for drawSneaker + // me.timeSkipLastCycle = 0 + // me.eventHorizon = 1800; //required for black hole + // me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000 + // me.accelMag = 0.0004 * simulation.accelScale; + // // me.frictionAir = 0.005; + // // me.memory = 1600; + // // Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger + // Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + // spawn.shield(me, x, y, 1); + // me.onDeath = function() { + // //applying forces to player doesn't seem to work inside this method, not sure why + // powerUps.spawnBossPowerUp(this.position.x, this.position.y) + // }; + // me.do = function() { + // //keep it slow, to stop issues from explosion knock backs + // if (this.speed > 8) { + // Matter.Body.setVelocity(this, { + // x: this.velocity.x * 0.99, + // y: this.velocity.y * 0.99 + // }); + // } + // this.seePlayerCheck(); + // this.checkStatus(); + // this.attraction() + // if (!simulation.isTimeSkipping) { + // const compress = 1 + // if (this.timeSkipLastCycle < simulation.cycle - compress && + // Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) { + // this.timeSkipLastCycle = simulation.cycle + // simulation.timeSkip(compress) + // this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})` + // this.stroke = "#014" + // this.isShielded = false; + // this.isDropPowerUp = true; + // this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets - me.onDeath = function() { - //applying forces to player doesn't seem to work inside this method, not sure why - powerUps.spawnBossPowerUp(this.position.x, this.position.y) - }; - me.do = function() { - //keep it slow, to stop issues from explosion knock backs - if (this.speed > 8) { - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.99, - y: this.velocity.y * 0.99 - }); - } - this.seePlayerCheck(); - this.checkStatus(); - this.attraction() - if (!simulation.isTimeSkipping) { - const compress = 1 - if (this.timeSkipLastCycle < simulation.cycle - compress && - Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) { - this.timeSkipLastCycle = simulation.cycle - simulation.timeSkip(compress) + // ctx.beginPath(); + // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + // ctx.fillStyle = "#fff"; + // ctx.globalCompositeOperation = "destination-in"; //in or atop + // ctx.fill(); + // ctx.globalCompositeOperation = "source-over"; + // ctx.beginPath(); + // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + // ctx.clip(); - this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})` - this.stroke = "#014" - this.isShielded = false; - this.isDropPowerUp = true; - this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets + // // ctx.beginPath(); + // // ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI); + // // ctx.fillStyle = "#000"; + // // ctx.fill(); + // // ctx.strokeStyle = "#000"; + // // ctx.stroke(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = "#fff"; - ctx.globalCompositeOperation = "destination-in"; //in or atop - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); - ctx.clip(); - - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI); - // ctx.fillStyle = "#000"; - // ctx.fill(); - // ctx.strokeStyle = "#000"; - // ctx.stroke(); - - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); - // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`; - // ctx.fill(); - // ctx.strokeStyle = "#000"; - // ctx.stroke(); - } else { - this.isShielded = true; - this.isDropPowerUp = false; - this.seePlayer.recall = false - this.fill = "transparent" - this.stroke = "transparent" - this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`; - ctx.fill(); - } - } - } - }, + // // ctx.beginPath(); + // // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + // // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`; + // // ctx.fill(); + // // ctx.strokeStyle = "#000"; + // // ctx.stroke(); + // } else { + // this.isShielded = true; + // this.isDropPowerUp = false; + // this.seePlayer.recall = false + // this.fill = "transparent" + // this.stroke = "transparent" + // this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets + // ctx.beginPath(); + // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`; + // ctx.fill(); + // } + // } + // } + // }, beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) { mobs.spawn(x, y, 4, radius, "rgb(255,0,190)"); let me = mob[mob.length - 1]; @@ -3931,7 +3923,7 @@ const spawn = { me.isBoss = true; Matter.Body.setDensity(me, 0.001); //normal is 0.001 me.inertia = Infinity; - me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0.06 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.frictionAir = 0.01 @@ -3974,8 +3966,8 @@ const spawn = { const unit = Vector.sub(player.position, this.position) Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1)); } else { - if (Math.abs(this.velocity.y) < 9) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.02 }); - if (Math.abs(this.velocity.x) < 6.5) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.02, y: this.velocity.y }); + if (Math.abs(this.velocity.y) < 10) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.02 }); + if (Math.abs(this.velocity.x) < 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.02, y: this.velocity.y }); } if (this.isInvulnerable) { @@ -5138,7 +5130,7 @@ const spawn = { me.maxCycles = 110; me.frictionStatic = 0; me.friction = 0; - me.frictionAir = 0.5; + me.frictionAir = 1; // me.homePosition = { x: x, y: y }; spawn.shield(me, x, y, 1); spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) @@ -5153,7 +5145,7 @@ const spawn = { }; me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.do = function() { - // this.armor(); + Matter.Body.rotate(this, 0.003) //gently spin around this.checkStatus(); ctx.beginPath(); //draw cycle timer ctx.moveTo(this.vertices[this.vertices.length - 1].x, this.vertices[this.vertices.length - 1].y) @@ -5186,6 +5178,73 @@ const spawn = { } }; }, + timeSkipBoss(x, y, radius = 50) { + mobs.spawn(x, y, 15, radius, "rgb(150, 150, 255)"); + let me = mob[mob.length - 1]; + me.isBoss = true; + me.eventHorizon = 0; //set in mob loop + me.frictionStatic = 0; + me.friction = 0; + me.frictionAir = 0.004; + me.accelMag = 0.0001 + 0.00003 * simulation.accelScale + spawn.shield(me, x, y, 1); + spawn.spawnOrbitals(me, radius + 50 + 100 * Math.random(), true) + + Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.07 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = me.damageReduction + me.isInvulnerable = false + me.onDeath = function() { + powerUps.spawnBossPowerUp(this.position.x, this.position.y) + // requestAnimationFrame(() => { simulation.timePlayerSkip(120) }); //wrapping in animation frame prevents errors, probably + }; + me.onDamage = function() { + //find side of mob closest to player + //causes lag for foam,laser too many seekers //maybe scale chance with dmg + // const where = Vector.add(this.position, Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.radius + 10)) + // spawn.seeker(where.x, where.y); //give the bullet a rotational velocity as if they were attached to a vertex + }; + me.do = function() { + this.seePlayerByHistory(); + this.attraction(); + this.checkStatus(); + this.eventHorizon = 950 + 170 * Math.sin(simulation.cycle * 0.005) + if (!simulation.isTimeSkipping) { + if (Vector.magnitude(Vector.sub(this.position, m.pos)) < this.eventHorizon) { + this.attraction(); + this.damageReduction = this.startingDamageReduction + this.isInvulnerable = false + if (!(simulation.cycle % 15)) requestAnimationFrame(() => { + simulation.timePlayerSkip(8) + simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations + }); //wrapping in animation frame prevents errors, probably + + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + ctx.fillStyle = "#fff"; + ctx.globalCompositeOperation = "destination-in"; //in or atop + ctx.fill(); + ctx.globalCompositeOperation = "source-over"; + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + // ctx.stroke(); + ctx.clip(); + } else { + this.damageReduction = 0 + this.isInvulnerable = true + //prevents other things from being drawn later on in the draw cycle + requestAnimationFrame(() => { + simulation.camera(); + ctx.beginPath(); //gets rid of already draw shapes + ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI, false); //part you can't see + ctx.fillStyle = color.background; + ctx.fill(); + ctx.restore(); + }) + } + } + }; + }, streamBoss(x, y, radius = 110) { mobs.spawn(x, y, 5, radius, "rgb(245,180,255)"); let me = mob[mob.length - 1]; @@ -5412,10 +5471,14 @@ const spawn = { mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" let me = mob[mob.length - 1]; me.isBoss = true; - me.accelMag = 0.0001 + 0.0002 * Math.sqrt(simulation.accelScale) + me.accelMag = 0.0003 + 0.0002 * Math.sqrt(simulation.accelScale) me.memory = 250; me.laserRange = 500; Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.startingDamageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0 + me.isInvulnerable = true + me.onDeath = function() { powerUps.spawnBossPowerUp(this.position.x, this.position.y) for (let i = 0; i < mob.length; i++) { //wake up tail mobs @@ -5428,9 +5491,7 @@ const spawn = { }; me.canFire = false; me.closestVertex1 = 0; - // me.closestVertex2 = 1; me.cycle = 0 - me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.do = function() { // this.armor(); this.seePlayerByHistory() @@ -5439,7 +5500,7 @@ const spawn = { this.cycle++ if (this.seePlayer.recall && ((this.cycle % 10) === 0)) { if (this.canFire) { - if (this.cycle > 120) { + if (this.cycle > 100) { this.cycle = 0 this.canFire = false // Matter.Body.setAngularVelocity(this, 0.1) @@ -5450,7 +5511,7 @@ const spawn = { } spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 6) Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001 - const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -10) + const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -13) Matter.Body.setVelocity(mob[mob.length - 1], { x: this.velocity.x + velocity.x, y: this.velocity.y + velocity.y @@ -5482,14 +5543,29 @@ const spawn = { // } } } + if (this.isInvulnerable) { + ctx.beginPath(); + let vertices = this.vertices; + ctx.moveTo(vertices[0].x, vertices[0].y); + for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y); + ctx.lineTo(vertices[0].x, vertices[0].y); + ctx.lineWidth = 20; + ctx.strokeStyle = "rgba(255,255,255,0.7)"; + ctx.stroke(); + } }; //extra space to give head room angle -= 0.1 mag -= 10 + let previousTailID = 0 + for (let i = 0; i < nodes; ++i) { angle -= 0.15 + i * 0.008 mag -= 5 spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20); + if (i === 0) mob[mob.length - 1].snakeHeadID = me.id + mob[mob.length - 1].previousTailID = previousTailID + previousTailID = mob[mob.length - 1].id } this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01); @@ -5530,36 +5606,46 @@ const spawn = { mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" let me = mob[mob.length - 1]; me.isBoss = true; - me.accelMag = 0.00077 * simulation.accelScale; + me.accelMag = 0.0004 + 0.0003 * Math.sqrt(simulation.accelScale) me.memory = 250; me.laserRange = 500; Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.startingDamageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0 + me.isInvulnerable = true + me.onDeath = function() { powerUps.spawnBossPowerUp(this.position.x, this.position.y) - for (let i = 0; i < mob.length; i++) { //wake up tail mobs - if (mob[i].isSnakeTail && mob[i].alive) { - mob[i].isSnakeTail = false; - mob[i].do = mob[i].doActive - // mob[i].removeConsBB(); - } - } }; - me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.do = function() { - // this.armor(); this.seePlayerByHistory() this.checkStatus(); this.attraction(); this.harmZone(); + if (this.isInvulnerable) { + ctx.beginPath(); + let vertices = this.vertices; + ctx.moveTo(vertices[0].x, vertices[0].y); + for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y); + ctx.lineTo(vertices[0].x, vertices[0].y); + ctx.lineWidth = 20; + ctx.strokeStyle = "rgba(255,255,255,0.7)"; + ctx.stroke(); + } }; //extra space to give head room angle -= 0.1 mag -= 10 + let previousTailID = 0 for (let i = 0; i < nodes; ++i) { angle -= 0.15 + i * 0.008 mag -= 5 spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20); + if (i === 0) mob[mob.length - 1].snakeHeadID = me.id + mob[mob.length - 1].previousTailID = previousTailID + previousTailID = mob[mob.length - 1].id } + this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01); for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors @@ -5595,23 +5681,23 @@ const spawn = { let me = mob[mob.length - 1]; me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body me.accelMag = 0.0006 * simulation.accelScale; - me.leaveBody = false; + me.leaveBody = Math.random() < 0.33 ? true : false; me.showHealthBar = false; me.isDropPowerUp = false; - // Matter.Body.setDensity(me, 0.00004); //normal is 0.001 + Matter.Body.setDensity(me, 0.003); //normal is 0.001 me.frictionAir = 0.015; me.isSnakeTail = true; me.stroke = "transparent" me.onDeath = function() { - // if (this.isSnakeTail) { //wake up tail mobs - // for (let i = 0; i < mob.length; i++) { - // if (mob[i].isSnakeTail && mob[i].alive) { - // mob[i].isSnakeTail = false; - // mob[i].do = mob[i].doActive - // mob[i].removeConsBB(); - // } - // } - // } + setTimeout(() => { + for (let i = 0, len = mob.length; i < len; i++) { + if (this.id === mob[i].previousTailID && mob[i].alive) mob[i].death() + if (this.snakeHeadID === mob[i].id) { + mob[i].isInvulnerable = false + mob[i].damageReduction = mob[i].startingDamageReduction + } + } + }, 150); }; me.do = function() { this.checkStatus(); @@ -5666,7 +5752,7 @@ const spawn = { me.stroke = "rgb(220,220,255)"; Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion me.shield = true; - me.damageReduction = 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.isUnblockable = true me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo me.collisionFilter.category = cat.mobShield diff --git a/js/tech.js b/js/tech.js index da34755..756e796 100644 --- a/js/tech.js +++ b/js/tech.js @@ -221,7 +221,8 @@ const tech = { }, damageFromTech() { let dmg = 1 //m.fieldDamage - if (tech.isNoDraftPause) dmg *= 1.5 + if (tech.isDeathSkipTime) dmg *= 1.67 + if (tech.isNoDraftPause) dmg *= 1.4 if (tech.isTechDebt) dmg *= Math.max(41 / (tech.totalCount + 21), 4 - 0.15 * tech.totalCount) if (tech.isAxion && tech.isHarmMACHO) dmg *= 1 + 0.75 * (1 - m.harmReduction()) if (tech.OccamDamage) dmg *= tech.OccamDamage @@ -556,7 +557,7 @@ const tech = { { name: "cache", link: `cache`, - description: `${powerUps.orb.ammo()} give 16x more ammo, but
you can't store any more ammo than that`, + description: `${powerUps.orb.ammo()} give 1600% more ammo, but
you can't store any more ammo than that`, // ammo powerups always max out your gun, // but the maximum ammo ti limited // description: `${powerUps.orb.ammo()} give 13x more ammo, but
you can't store any more ammo than that`, @@ -936,7 +937,7 @@ const tech = { }, { name: "reaction inhibitor", - description: "mobs spawn with 11% less health", + description: "mobs spawn with 13% less health", maxCount: 3, count: 0, frequency: 1, @@ -946,7 +947,7 @@ const tech = { }, requires: "", //"any mob death tech", effect: () => { - tech.mobSpawnWithHealth *= 0.89 + tech.mobSpawnWithHealth *= 0.87 //set all mobs at full health to 0.85 for (let i = 0; i < mob.length; i++) { @@ -957,6 +958,24 @@ const tech = { tech.mobSpawnWithHealth = 1; } }, + { + name: "propagator", + description: "increase damage by 67%, but after
mobs die lose 0.5 seconds of time", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isDeathSkipTime = true + }, + remove() { + tech.isDeathSkipTime = false + } + }, { name: "decorrelation", description: "reduce harm by 70% after not activating
your gun or field for 2 seconds", @@ -1772,6 +1791,24 @@ const tech = { m.eyeFillColor = 'transparent' } }, + // { + // name: "spacetime interval", + // description: "increase damage by 93%, but after mobs die
move into the past / future while ON / OFF", + // maxCount: 1, + // count: 0, + // frequency: 4, + // frequencyDefault: 4, + // allowed() { + // return tech.isFlipFlop || tech.isRelay + // }, + // requires: "ON/OFF tech", + // effect() { + // tech.isDeathSkipTime = true + // }, + // remove() { + // tech.isDeathSkipTime = false + // } + // }, { name: "NAND gate", description: "if in the ON state
do 55.5% more damage", @@ -2479,7 +2516,7 @@ const tech = { }, { name: "recycling", - description: "if a mob has died in the last 5 seconds
regain 1% of max health every second", + description: "if a mob has died in the last 5 seconds
regain 0.5% of max health every second", maxCount: 1, count: 0, frequency: 1, @@ -3172,7 +3209,7 @@ const tech = { { name: "paradigm shift", - description: `clicking tech while paused ejects them
10% chance to convert that tech into ${powerUps.orb.research(1)}`, + description: `clicking tech while paused ejects them
16% chance to convert that tech into ${powerUps.orb.research(1)}`, maxCount: 1, count: 0, frequency: 1, @@ -3191,7 +3228,7 @@ const tech = { { name: "eternalism", // description: `increase damage by 60%, but time doesn't pause
while choosing a choosing a field, tech, or gun`, //${powerUps.orb.heal()} or - description: "increase damage by 50%, but
time can't be paused (time dilation still works)", + description: "increase damage by 40%, but
time can't be paused (time dilation still works)", maxCount: 1, count: 0, frequency: 1, @@ -3556,19 +3593,19 @@ const tech = { // return `randomly remove ${this.removePercent * 100}% of your tech
for each removed gain ${this.damagePerRemoved * 100}% damage` // }, descriptionFunction() { - return `randomly remove half your tech
for each removed gain ${this.damagePerRemoved * 100}% damage (~${this.damagePerRemoved * 50 * tech.totalCount}%)` + return `randomly remove half your tech
for each removed gain ${this.damagePerRemoved * 100 }% damage (~${(this.count === 0) ? this.damagePerRemoved * 50 * tech.totalCount : tech.OccamDamage*100}%)` }, maxCount: 1, count: 0, - frequency: 1, + frequency: 199, frequencyDefault: 1, isNonRefundable: true, isBadRandomOption: true, allowed() { return (tech.totalCount > 6) }, - requires: "NOT EXPERIMENT MODE, more than 6 tech", - removePercent: 0.5, + requires: "more than 6 tech", + // removePercent: 0.5, damagePerRemoved: 0.5, effect() { let pool = [] @@ -3577,7 +3614,7 @@ const tech = { } pool = shuffle(pool); //shuffles order of maps let removeCount = 0 - for (let i = 0, len = pool.length * this.removePercent; i < len; i++) removeCount += tech.removeTech(pool[i]) + for (let i = 0, len = pool.length * this.damagePerRemoved; i < len; i++) removeCount += tech.removeTech(pool[i]) tech.OccamDamage = 1 + this.damagePerRemoved * removeCount // tech.OccamDamage = Math.pow(1.25, removeCount) }, @@ -5713,8 +5750,8 @@ const tech = { simulation.updateGunHUD() }, remove() { + b.guns[8].ammoPack = 24 if (this.count) { - b.guns[8].ammoPack = 24 b.guns[8].ammo += this.ammoLost simulation.updateGunHUD() } @@ -6110,7 +6147,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.17 + return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.18 }, requires: "laser, not free-electron", effect() { @@ -6138,13 +6175,13 @@ const tech = { requires: "laser, not pulse, diodes", effect() { tech.laserFieldDrain = 0.007 //base is 0.002 - tech.laserDamage = 0.51; //base is 0.16 + tech.laserDamage = 0.54; //base is 0.18 tech.laserColor = "#83f" tech.laserColorAlpha = "rgba(136, 51, 255,0.5)" }, remove() { tech.laserFieldDrain = 0.002; - tech.laserDamage = 0.17; //used in check on pulse and diode: tech.laserDamage === 0.16 + tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.16 tech.laserColor = "#f00" tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)" } @@ -6217,7 +6254,7 @@ const tech = { { name: "diffuse beam", link: `diffuse beam`, - description: "laser beam is wider and doesn't reflect
increase full beam damage by 200%", + description: "laser beam is wider and doesn't reflect
increase full beam damage by 220%", isGunTech: true, maxCount: 1, count: 0, @@ -6311,7 +6348,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.17 && !tech.isStuckOn + return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.18 && !tech.isStuckOn }, requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier", effect() { @@ -7049,7 +7086,7 @@ const tech = { }, requires: "extruder", effect() { - tech.extruderRange += 60 + tech.extruderRange += 55 }, remove() { tech.extruderRange = 15 @@ -7895,6 +7932,51 @@ const tech = { }, remove() {} }, + { + name: "translate", + description: "translate n-gon into a random language", + maxCount: 1, + count: 0, + frequency: 0, + isJunk: true, + isNonRefundable: true, + allowed() { + return true + }, + requires: "", + effect() { + // generate a container + const gtElem = document.createElement('div') + gtElem.id = "gtElem" + gtElem.style.visibility = 'hidden' // make it invisible + document.body.append(gtElem) + + // generate a script to run after creation + function initGT() { + // create a new translate element + new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem') + // ok now since it's loaded perform a funny hack to make it work + const langSelect = document.getElementsByClassName("goog-te-combo")[0] + // select a random language. It takes a second for all langauges to load, so wait a second. + setTimeout(() => { + langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random()) + // simulate a click + langSelect.dispatchEvent(new Event('change')) + // now make it go away + const bar = document.getElementById(':1.container') + bar.style.display = 'none' + bar.style.visibility = 'hidden' + }, 1000) + + } + + // add the google translate script + const translateScript = document.createElement('script') + translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT' + document.body.append(translateScript) + }, + remove() {} + }, { name: "discount", description: "get 3 random JUNK tech for the price of 1!", @@ -10223,4 +10305,5 @@ const tech = { isClusterExplode: null, isCircleExplode: null, isPetalsExplode: null, + isDeathSkipTime: null } \ No newline at end of file diff --git a/todo.txt b/todo.txt index 8f983c2..904ec56 100644 --- a/todo.txt +++ b/todo.txt @@ -1,14 +1,43 @@ ******************************************************** NEXT PATCH ************************************************** -new reactor boss: timeBoss - after taking some damage it speeds up the passage of time -reactor level has big doors +tech: propagator - 67% damage, lose 1/2 second of time when a mob dies -nonrefundable tech show up in the pause menu -time dilation field - move, jump, and fire 25% faster -JUNK tech: closed timelike curve - spawn 5 field power ups, but every 12 seconds teleport a second into your future +timeSkipBoss is back, maybe it will not cause bugs this time + immune to harm unless player is inside horizon + player loses time when inside horizon + +snake bosses are immune to harm until your remove their tail + +mob shields are 30% stronger +time dilation: retrocausality automatically grabs power ups +eternalism 50->40% damage +paradigm shift 10->16% chance to get a research when ejecting tech +reaction inhibitor 11->13% mob health reduction +recycling 1->0.5% health for 5 seconds + up to 2.5% per mob kill at normal max health + +bug fixes ******************************************************** TODO ******************************************************** +make targeting skip invulnerable mobs + drones, spores, harpoon, missiles?, mines, nail on death + this helps beat snake boss + spores are biggest issue + +let blocking instantly destroy the red orbitals? since they can't be deflected + also mines on reactor level? + also any bullet? + +BUG time skip probably led to player being able to move, and game not being paused for a few seconds while the death screen faded in + also small chance it happened with rewind instead, but unlikely + +make one value to track all the +dmg effects that don't need dynamic calculations + update it with a set damage function + +block manufacturing - molecular assembler tech +Holding r-click will create a slowly increasing in size block, which will be thrown on release + if a mob dies in skiptime it doesn't register? is this only for the ondeath event? so far, but needs more tests @@ -19,23 +48,9 @@ make MEE work with harm reduction how to nerf MEE maybe harm reduction could also reduce energy regen -timeSkipBoss - sends out waves of 60s time skip every 5 seconds? - or 1 cycle skip every other cycle - only active when player is inside range - immune to harm outside range? - simulation.timeSkip(60) - skip every other cycle inside black holes? - maybe run simulation.timeSkip(60) in a map - in labs? - reactor boss + maybe run simulation.timeSkip(60) in a room in labs mob fires laser/bullets that timeSkip player - maybe an effect when in range of the historyBoss - JUNK tech simulation.timeSkip(60) - add CPT graphics to simulation.timeSkip(60) - for player - tech requires eternalism - 2x time while choosing, gain more damage Currently, the mob just deals higher damage on impact, which is annoying although not hard to compete with nor unique By "redesign" I mean replacing instances of the regular mob, since the same code is used for the tiny red projectiles (I think) just add a new mob and remove the old one from the rotation @@ -51,7 +66,6 @@ About to explode: animation to dark red Exploding: several shockwaves from the explosion points and tiny trails given to the shrapnel for a second or two until they deaccelerate - make laser gain damage and energy drain from fire delay tech wording? put it in the gun description @@ -62,8 +76,6 @@ pause time like invariant for other things... charging railgun charging anything? -give retrocausality a short delay before it rewinds, so you can pick up powerups without going back - tech expansion: should also make other fields do things how to make the description work change description based on your current field? @@ -733,23 +745,13 @@ possible names for tech nuclear pasta - hard matter in neutron star nonlocal fine-tuned universe - eternalism https://en.wikipedia.org/wiki/Eternalism_(philosophy_of_time) - axial motor hall effect thrusters spaghettification particle accelerator superluminal signalling NP-complete lenticular lens: is an array of lenses, designed so that when viewed from slightly different angles, different parts of the image underneath are shown. - -a tutorial / lore intro - needs to be optional so it doesn't slow experienced players - put something on the intro map - maybe a button triggers something - -rename ? - health -> integrity, unity - heal -> also integrity, unity + p-zombie plot script: