diff --git a/.DS_Store b/.DS_Store index 461e335..2bf9398 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/js/bullet.js b/js/bullet.js index 0e117bd..73f5c09 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -2109,10 +2109,10 @@ const b = { onEnd() {}, do() { if (this.endCycle < simulation.cycle + 1) this.isWave = false - if (Matter.Query.point(map, this.position).length) { //check if inside map + if (Matter.Query.point(map, this.position).length) { //check if inside map //|| Matter.Query.point(body, this.position).length this.isBranch = true; this.do = () => { 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: