diff --git a/img/MACHO.webp b/img/MACHO.webp index 8570ee0..0875e67 100644 Binary files a/img/MACHO.webp and b/img/MACHO.webp differ diff --git a/img/control theory.webp b/img/control theory.webp new file mode 100644 index 0000000..2843288 Binary files /dev/null and b/img/control theory.webp differ diff --git a/img/dark energy.webp b/img/dark energy.webp new file mode 100644 index 0000000..faca967 Binary files /dev/null and b/img/dark energy.webp differ diff --git a/img/dark matter.webp b/img/dark matter.webp new file mode 100644 index 0000000..8570ee0 Binary files /dev/null and b/img/dark matter.webp differ diff --git a/img/slow light.webp b/img/delayed-choice.webp similarity index 100% rename from img/slow light.webp rename to img/delayed-choice.webp diff --git a/img/inertial confinement.webp b/img/inertial confinement.webp new file mode 100644 index 0000000..068f0c0 Binary files /dev/null and b/img/inertial confinement.webp differ diff --git a/img/instability.webp b/img/instability.webp new file mode 100644 index 0000000..fdcbf8f Binary files /dev/null and b/img/instability.webp differ diff --git a/img/stability.webp b/img/stability.webp new file mode 100644 index 0000000..f9a7dab Binary files /dev/null and b/img/stability.webp differ diff --git a/img/stellarator.webp b/img/stellarator.webp new file mode 100644 index 0000000..49fe2ef Binary files /dev/null and b/img/stellarator.webp differ diff --git a/js/level.js b/js/level.js index 4f5082b..72913db 100644 --- a/js/level.js +++ b/js/level.js @@ -26,7 +26,7 @@ const level = { // tech.tech[297].frequency = 100 // tech.addJunkTechToPool(0.5) // m.couplingChange(10) - // m.setField("time dilation") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook + // m.setField("negative mass") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook // m.energy = 0 // powerUps.research.count = 3 // tech.isHookWire = true @@ -43,9 +43,9 @@ const level = { // b.guns[8].ammo = 100000000 // requestAnimationFrame(() => { tech.giveTech("optical amplifier") }); // tech.giveTech("1st ionization energy") - // for (let i = 0; i < 1; ++i) tech.giveTech("negative feedback") - // for (let i = 0; i < 2; ++i) tech.giveTech("delayed-choice") - // for (let i = 0; i < 1; ++i) tech.giveTech("pulse") + // for (let i = 0; i < 1; ++i) tech.giveTech("tokamak") + // for (let i = 0; i < 1; ++i) tech.giveTech("inertial confinement") + // for (let i = 0; i < 1; ++i) tech.giveTech("stellarator") // for (let i = 0; i < 1; ++i) tech.giveTech("mass-energy equivalence") // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) }); // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("1st ionization energy") }); @@ -54,11 +54,11 @@ const level = { // for (let i = 0; i < 1; ++i) tech.giveTech("compression engine") // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 1; i++) powerUps.directSpawn(-50, -70, "difficulty", false); - // for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); // spawn.mapRect(575, -700, 25, 425); //block mob line of site on testing - // level.arena(); - - // for (let i = 0; i < 1; ++i) spawn.snakeSpitBoss(1400, -500) + level.testing(); + + // for (let i = 0; i < 1; ++i) spawn.snakeBoss(1400, -500) + // for (let i = 0; i < 2; i++) powerUps.directSpawn(800, -100, "coupling"); // Matter.Body.setPosition(player, { x: -200, y: -3330 }); // for (let i = 0; i < 4; ++i) spawn.sucker(1300, -500 + 100 * Math.random()) // spawn.hopper(1900, -500) @@ -68,11 +68,10 @@ const level = { // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // for (let i = 0; i < 40; ++i) tech.giveTech() - level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** + // level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** // for (let i = 0; i < 1; ++i) spawn.laserLayerBoss(1900, -500) // for (let i = 0; i < 2; i++) spawn.ghoster(level.exit.x, level.exit.y) //ghosters need to spawn after the map loads - // spawn.bodyRect(2425, -120, 200, 200); // console.log(body[body.length - 1].mass) // simulation.isAutoZoom = false; //look in close // simulation.zoomScale *= 0.5; @@ -134,7 +133,7 @@ const level = { } } } - if (tech.isMACHO) spawn.MACHO() + if (tech.isDarkMatter) spawn.darkMatter() for (let i = 0; i < tech.wimpCount; i++) { spawn.WIMP() mob[mob.length - 1].isDecoupling = true //so you can find it to remove @@ -151,6 +150,7 @@ const level = { newLevelOrPhase() { //runs on each new level but also on final boss phases //used for generalist and pigeonhole principle tech.cancelTechCount = 0 + tech.tokamakHealCount = 0 tech.buffedGun++ if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0; if (tech.isGunCycle && b.activeGun !== null && b.inventory.length) { @@ -12651,7 +12651,7 @@ const level = { Promise.resolve().then(() => { // Clear all WIMPS and their research for (let i = 0; i < mob.length; i++) { - if (mob[i] && !mob[i].isMACHO) { + if (mob[i] && !mob[i].isDarkMatter) { mob[i].isWIMP = true; } } @@ -13302,7 +13302,7 @@ const level = { if (simulation.cycle % 4 === 0) { let newMobPositions = []; for (const i of mob) { - if (!(i.isMACHO || i.isWIMP || i.isObstacle)) newMobPositions.push({ + if (!(i.isDarkMatter || i.isWIMP || i.isObstacle)) newMobPositions.push({ x: i.position.x, y: i.position.y }); @@ -13572,7 +13572,7 @@ const level = { level.setPosToSpawn(x, y); trapPlayer(x, y); for (let i = 0; i < mob.length; i++) { - if (mob[i].isMACHO) { + if (mob[i].isDarkMatter) { setPos(mob[i], { x, y diff --git a/js/player.js b/js/player.js index 2df51df..d650503 100644 --- a/js/player.js +++ b/js/player.js @@ -547,10 +547,11 @@ const m = { lastCalculatedDefense: 0, //used to decided if defense bar needs to be redrawn (in simulation.checks) defense() { let dmg = 1 + if (tech.isMaxHealthDefense && m.health === m.maxHealth) dmg *= 0.3 if (tech.isDiaphragm) dmg *= 0.55 + 0.35 * Math.sin(m.cycle * 0.0075); if (tech.isZeno) dmg *= 0.15 if (tech.isFieldHarmReduction) dmg *= 0.6 - if (tech.isHarmMACHO) dmg *= tech.isMoveMACHO ? 0.3 : 0.4 + if (tech.isHarmDarkMatter) dmg *= (tech.isMoveDarkMatter || tech.isNotDarkMatter) ? 0.25 : 0.4 if (tech.isImmortal) dmg *= 0.7 if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.973 ** m.coupling if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.3 @@ -2364,6 +2365,30 @@ const m = { ctx.lineTo(m.holdingTarget.vertices[i + 1].x, m.holdingTarget.vertices[i + 1].y); ctx.fill(); } + if (tech.isTokamakFly && m.throwCharge > 4 && m.energy > 0.01) { + player.force.y -= 0.5 * player.mass * simulation.g; //add some reduced gravity + // const mass = (player.mass + 10) / 3 * simulation.g //this makes it so you fly slower with larger blocks + let isDrain = false + const thrust = player.mass * simulation.g * Math.pow(5 / player.mass, 0.1) + if (input.down) { + isDrain = true + player.force.y += 0.9 * thrust; + } else if (input.up) { + isDrain = true + player.force.y -= 0.9 * thrust + } + if (!m.onGround) { + if (input.left) { + isDrain = true + player.force.x -= 0.4 * thrust + } else if (input.right) { + isDrain = true + player.force.x += 0.4 * thrust + } + if (isDrain) m.energy -= 0.0017; + } + + } } else { //draw charge const x = m.pos.x + 15 * Math.cos(m.angle); @@ -2425,6 +2450,12 @@ const m = { } } b.pulse(60 * Math.pow(m.holdingTarget.mass, 0.25), m.angle) + if (tech.isTokamakHeal && tech.tokamakHealCount < 5) { + tech.tokamakHealCount++ + let massScale = Math.min(65 * Math.sqrt(m.maxHealth), 14 * Math.pow(m.holdingTarget.mass, 0.4)) + if (powerUps.healGiveMaxEnergy) massScale = powerUps["heal"].size() + powerUps.spawn(m.pos.x, m.pos.y, "heal", true, null, massScale * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1))) // spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { + } } else { //normal throw //bullet-like collisions m.holdingTarget.collisionFilter.category = cat.bullet @@ -2962,7 +2993,7 @@ const m = { drainCD: 0, effect: () => { m.fieldBlockCD = 0; - m.blockingRecoil = 1.5 //4 is normal + m.blockingRecoil = 1 //4 is normal m.fieldRange = 185 m.fieldShieldingScale = 1.6 * Math.pow(0.5, (tech.harmonics - 2)) // m.fieldHarmReduction = 0.66; //33% reduction diff --git a/js/powerup.js b/js/powerup.js index 0074835..0e29941 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -668,7 +668,7 @@ const powerUps = { }); } else if (overHeal > 0.13) { //if leftover heals spawn a new spammer heal power up requestAnimationFrame(() => { - powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { + powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, Math.min(1, overHeal) * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { }); } if (tech.isHealBrake) { diff --git a/js/spawn.js b/js/spawn.js index 1a94832..b771cc4 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -116,13 +116,15 @@ const spawn = { secondaryBossChance(x, y) { if (simulation.difficultyMode > 2 && level.levelsCleared > 2) { spawn.randomLevelBoss(x, y); + powerUps.directSpawn(x - 30, y, "ammo"); + powerUps.directSpawn(x + 30, y, "ammo"); } else { return false } }, //mob templates ********************************************************************************************* //*********************************************************************************************************** - MACHO(x = m.pos.x, y = m.pos.y) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the player + darkMatter(x = m.pos.x, y = m.pos.y) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the player mobs.spawn(x, y, 3, 0.1, "transparent"); let me = mob[mob.length - 1]; me.stroke = "transparent" @@ -135,13 +137,14 @@ const spawn = { me.collisionFilter.category = 0; me.collisionFilter.mask = 0; //cat.player //| cat.body me.chaseSpeed = 3.3 - me.isMACHO = true; + me.isDarkMatter = true; me.frictionAir = 0.006 me.onDeath = function () { - tech.isHarmMACHO = false; + tech.isHarmDarkMatter = false; } me.do = function () { if (!simulation.isTimeSkipping) { + const scale = (tech.isMoveDarkMatter || tech.isNotDarkMatter) ? 1.6 : 1 const sine = Math.sin(simulation.cycle * 0.015) this.radius = 111 * tech.isDarkStar + 370 * (1 + 0.1 * sine) //chase player @@ -163,7 +166,7 @@ const spawn = { // } // } - if (tech.isMoveMACHO && m.crouch && input.down) { + if (tech.isMoveDarkMatter && m.crouch && input.down) { Matter.Body.setVelocity(this, Vector.add(Vector.mult(this.velocity, 0.97), Vector.mult(player.velocity, 0.03))) Matter.Body.setPosition(this, Vector.add(Vector.mult(this.position, 0.95), Vector.mult(player.position, 0.05))) } @@ -171,18 +174,34 @@ const spawn = { this.force.x += force.x this.force.y += force.y - - if (mag < this.radius) { //buff to player when inside radius - tech.isHarmMACHO = true; - //draw halo - ctx.strokeStyle = "rgba(80,120,200,0.2)" //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` - ctx.beginPath(); - ctx.arc(m.pos.x, m.pos.y, 36, 0, 2 * Math.PI); - ctx.lineWidth = 10; - ctx.stroke(); + if (tech.isNotDarkMatter) { + if (mag < this.radius) { //buff to player when inside radius + tech.isHarmDarkMatter = false; + } else { + tech.isHarmDarkMatter = true; + //draw halo + ctx.strokeStyle = "rgba(80,120,200,0.2)" //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, 36, 0, 2 * Math.PI); + ctx.lineWidth = 10; + ctx.stroke(); + if (tech.isDarkEnergy) m.energy += 0.0017 * scale + } } else { - tech.isHarmMACHO = false; + if (mag < this.radius) { //buff to player when inside radius + tech.isHarmDarkMatter = true; + //draw halo + ctx.strokeStyle = "rgba(80,120,200,0.2)" //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, 36, 0, 2 * Math.PI); + ctx.lineWidth = 10; + ctx.stroke(); + if (tech.isDarkEnergy) m.energy += 0.0017 * scale + } else { + tech.isHarmDarkMatter = false; + } } + //draw outline ctx.beginPath(); ctx.arc(this.position.x, this.position.y, this.radius + 15, 0, 2 * Math.PI); @@ -196,7 +215,7 @@ const spawn = { for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i].alive && !mob[i].isShielded) { if (Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius < this.radius) { - const dmg = 0.025 * m.dmgScale * (tech.isMoveMACHO ? 1.5 : 1) + const dmg = 0.03 * m.dmgScale * scale mob[i].damage(dmg); simulation.drawList.push({ //add dmg to draw queue x: mob[i].position.x, @@ -1428,7 +1447,7 @@ const spawn = { me.seeAtDistance2 = 1400000; me.cellMassMax = 70 me.collisionFilter.mask = cat.player | cat.bullet | cat.body// | cat.map - Matter.Body.setDensity(me, 0.00012 + 0.00001 * simulation.difficulty) // normal density is 0.001 + Matter.Body.setDensity(me, 0.00012 + 0.000008 * simulation.difficulty) // normal density is 0.001 me.damageReduction = 0.17 const k = 642 //k=r^2/m @@ -1691,7 +1710,7 @@ const spawn = { } else if (!m.isCloak) { me.foundPlayer(); } - me.damageReduction = 0.2 + me.damageReduction = 0.21 me.isInvulnerable = true me.startingDamageReduction = me.damageReduction me.damageReduction = 0 @@ -1769,7 +1788,7 @@ const spawn = { me.foundPlayer(); } - me.damageReduction = 0.22 + me.damageReduction = 0.23 me.isInvulnerable = true me.startingDamageReduction = me.damageReduction me.damageReduction = 0 @@ -2146,7 +2165,7 @@ const spawn = { mobs.spawn(x, y, 5, radius, "rgb(0,200,180)"); let me = mob[mob.length - 1]; me.isBoss = true; - me.damageReduction = 0.09 + me.damageReduction = 0.12 me.accelMag = 0.05; //jump height me.g = 0.003; //required if using this.gravity me.frictionAir = 0.01; @@ -2470,7 +2489,7 @@ const spawn = { // toMe(bullet, this.position, this.eventHorizon)) } }; - me.damageReduction = 0.25 + me.damageReduction = 0.27 me.do = function () { //keep it slow, to stop issues from explosion knock backs if (this.speed > 1) { @@ -2662,7 +2681,7 @@ const spawn = { let me = mob[mob.length - 1]; me.babyList = [] //list of mobs that are apart of this boss Matter.Body.setDensity(me, 0.0015); //extra dense //normal is 0.001 //makes effective life much larger and damage on collision - me.damageReduction = 0.13 //normal is 1, most bosses have 0.25 + me.damageReduction = 0.14 //normal is 1, most bosses have 0.25 me.isBoss = true; me.friction = 0; @@ -2978,7 +2997,7 @@ const spawn = { me.laserRange = 350; me.seeAtDistance2 = 2000000; me.isBoss = true; - me.damageReduction = 0.35 // me.damageReductionGoal + me.damageReduction = 0.38 // me.damageReductionGoal me.showHealthBar = false; //drawn in this.awake me.delayLimit = 60 + Math.floor(30 * Math.random()); @@ -3403,7 +3422,7 @@ const spawn = { let me = mob[mob.length - 1]; me.isBoss = true; Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.07 + me.damageReduction = 0.08 me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.nextHealthThreshold = 0.75 @@ -3594,7 +3613,7 @@ const spawn = { let me = mob[mob.length - 1]; me.isBoss = true; Matter.Body.setDensity(me, 0.004); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.1 + me.damageReduction = 0.12 me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front Matter.Body.rotate(me, Math.random() * Math.PI * 2); @@ -3686,7 +3705,7 @@ const spawn = { mobs.spawn(x, y, 3, radius, "rgb(0,235,255)"); let me = mob[mob.length - 1]; me.isBoss = true; - me.damageReduction = 0.25 + me.damageReduction = 0.27 me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front Matter.Body.rotate(me, Math.random() * Math.PI * 2); @@ -3792,7 +3811,7 @@ const spawn = { Matter.Body.rotate(me, Math.PI * 0.1); Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger me.isBoss = true; - me.damageReduction = 0.034 + me.damageReduction = 0.038 me.frictionStatic = 0; me.friction = 0; @@ -3850,6 +3869,156 @@ const spawn = { this.checkStatus(); }; }, + snakeBoss(x, y) { + mobs.spawn(x, y, 0, 30, `rgba(255,0,200)`); //"rgb(221,102,119)" + let me = mob[mob.length - 1]; + me.stroke = "transparent"; //used for drawGhost + // Matter.Body.setStatic(me, true); //make static, breaks game on player collision + Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger + me.isBoss = true; + me.damageReduction = 0.02 + me.startingDamageReduction = me.damageReduction + me.isInvulnerable = false + me.nextHealthThreshold = 0.75 + me.invulnerableCount = 0 + + me.history = [] + for (let i = 0; i < 15; i++) { + me.history.push({ x: me.position.x + i, y: me.position.y }) + } + me.frictionStatic = 0; + me.friction = 0; + me.memory = 240 + me.seePlayerFreq = 55 + me.delay = 6 + 4 * simulation.CDScale; + me.nextBlinkCycle = me.delay; + me.radius = 30 + me.JumpDistance = me.radius * 2 + // spawn.shield(me, x, y, 1); + me.collisionFilter.mask = cat.bullet | cat.map //| cat.body //cat.player | + me.onDamage = function () { + if (this.health < this.nextHealthThreshold) { + this.health = this.nextHealthThreshold - 0.01 + this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25 + this.invulnerableCount = 90 + this.isInvulnerable = true + this.damageReduction = 0 + this.laserDelay = 130 + const where = this.history[0] + for (let i = 0; i < 10; i++) { + this.history.unshift(where) + } + } + }; + me.onDeath = function () { + powerUps.spawnBossPowerUp(this.position.x, this.position.y) + } + me.do = function () { + const color = `rgba(255,0,200,${0.3 + 0.07 * Math.random()})` + + //check for player in between each segment + for (let i = 0; i < this.history.length - 1; i++) { + if (Matter.Query.ray([player], this.history[i], this.history[i + 1], 10).length > 0) { + m.damage(0.004 * simulation.dmgScale); + simulation.drawList.push({ //add dmg to draw queue + x: m.pos.x, + y: m.pos.y, + radius: 30, + color: color, + time: 10 + }); + break + } + } + + if (this.nextBlinkCycle < simulation.cycle) { //teleport towards the player + this.nextBlinkCycle = simulation.cycle + this.delay; + //custom see player by history code + let move = (target = this.seePlayer.position) => { + const dist = Vector.sub(target, this.position); + Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), this.JumpDistance)); + Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setAngle(this, 0); + Matter.Body.setAngularVelocity(this, 0) + //track previous locations for the tail + this.history.push({ x: this.position.x, y: this.position.y }) //add newest to end + this.history.shift() //remove first (oldest) + } + //look for close powers up in line of sight + let close = { + dist2: Infinity, + targetPos: null + } + for (let i = 0; i < powerUp.length; i++) { + if (Matter.Query.ray(map, this.position, powerUp[i].position).length === 0) { + const dist = Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) + if (dist < close.dist2) { + close = { + dist2: dist, + // targetPos: { x: powerUp[i].position.x, y: powerUp[i].position.y } + target: powerUp[i] + } + } + } + } + if (close.dist2 < 5000 * 5000) { + //chase power ups + move(close.target.position) + //check if close to power up and eat it + if (close.dist2 < 200 * 200) { + //eat power up + } + + } else if (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && !m.isCloak) { + this.seePlayer.yes = true; + this.locatePlayer(); + if (!this.seePlayer.yes) this.seePlayer.yes = true; + move() + } else if (this.seePlayer.recall) { + this.lostPlayer(); + if (!m.isCloak) { + for (let i = 0; i < 50; i++) { //if lost player lock onto a player location in history + let history = m.history[(m.cycle - 10 * i) % 600] + if (Matter.Query.ray(map, this.position, history.position).length === 0) { + this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep + this.seePlayer.position.x = history.position.x; + this.seePlayer.position.y = history.position.y; + this.seePlayer.yes = true; + move() + break + } + } + } + } + + } + this.checkStatus(); + if (this.isInvulnerable) { + this.invulnerableCount-- + if (this.invulnerableCount < 0) { + this.isInvulnerable = false + this.damageReduction = this.startingDamageReduction + } + //draw invulnerable + 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 = 13 + 5 * Math.random(); + ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`; + ctx.stroke(); + } + //draw history + ctx.beginPath(); + for (let i = 0, len = this.history.length; i < len; i++) { + ctx.lineTo(this.history[i].x, this.history[i].y) + } + ctx.lineWidth = this.radius * 2; + ctx.strokeStyle = color //"rgba(0,235,255,0.5)"; + ctx.stroke(); + }; + }, pulsarBoss(x, y, radius = 90, isNonCollide = false) { mobs.spawn(x, y, 3, radius, "#a0f"); let me = mob[mob.length - 1]; @@ -3890,7 +4059,7 @@ const spawn = { me.do = function () { if (player.speed > 5) this.do = this.fire //don't attack until player moves } - me.damageReduction = 0.25 + me.damageReduction = 0.29 me.fire = function () { // this.armor(); this.checkStatus(); @@ -4263,7 +4432,7 @@ const spawn = { powerUps.spawnBossPowerUp(this.position.x, this.position.y) }; Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.33 + me.damageReduction = 0.36 me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.nextHealthThreshold = 0.75 @@ -4725,7 +4894,7 @@ const spawn = { // spawn.shield(me, x, y, 1); Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.12 + me.damageReduction = 0.13 me.isBoss = true; me.onDamage = function () { }; me.onDeath = function () { @@ -4820,8 +4989,8 @@ const spawn = { me.frictionAir = 0; me.restitution = 1 // spawn.spawnOrbitals(me, radius + 50 + 125 * Math.random(), 1) - Matter.Body.setDensity(me, 0.002 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.09 + Matter.Body.setDensity(me, 0.002 + 0.00005 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.11 me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.nextHealthThreshold = 0.75 @@ -5274,7 +5443,7 @@ const spawn = { let me = mob[mob.length - 1]; Matter.Body.rotate(me, 2 * Math.PI * Math.random()); me.isBoss = true; - me.damageReduction = 0.1 + me.damageReduction = 0.11 me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.frictionAir = 0.02 @@ -5722,7 +5891,7 @@ const spawn = { let me = mob[mob.length - 1]; Matter.Body.setDensity(me, 0.001); //extra dense //normal is 0.001 //makes effective life much larger me.isBoss = true; - me.damageReduction = 0.15 + me.damageReduction = 0.17 me.accelMag = 0.0017 * Math.sqrt(simulation.accelScale); me.frictionAir = 0.01; @@ -6030,7 +6199,7 @@ const spawn = { let me = mob[mob.length - 1]; me.isBoss = true; - Matter.Body.setDensity(me, 0.0025 + 0.00013 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + Matter.Body.setDensity(me, 0.0025 + 0.00009 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger me.stroke = "transparent"; //used for drawGhost me.seeAtDistance2 = 1500000; @@ -6057,7 +6226,7 @@ const spawn = { me.onDeath = function () { powerUps.spawnBossPowerUp(this.position.x, this.position.y) }; - me.damageReduction = 0.2 + me.damageReduction = 0.22 me.do = function () { // this.armor(); this.seePlayerCheckByDistance(); @@ -6114,8 +6283,8 @@ const spawn = { }, 2000); //add in a delay in case the level gets flipped left right me.isBoss = true; - Matter.Body.setDensity(me, 0.01 + 0.0004 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.2 + Matter.Body.setDensity(me, 0.01 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.22 me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front me.isVerticesChange = true @@ -6472,8 +6641,8 @@ const spawn = { mobs.spawn(x, y, 6, radius, "rgb(150,150,255)"); let me = mob[mob.length - 1]; me.isBoss = true; - Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.2 + Matter.Body.setDensity(me, 0.0022 + 0.00015 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.22 me.accelMag = 0.0001 * simulation.accelScale; me.fireFreq = Math.floor(330 * simulation.CDScale) @@ -6684,7 +6853,7 @@ const spawn = { spawn.spawnOrbitals(me, radius + 50, 1); spawn.spawnOrbitals(me, radius + 125, 1); spawn.spawnOrbitals(me, radius + 200, 1); - Matter.Body.setDensity(me, 0.004 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + Matter.Body.setDensity(me, 0.004 + 0.00015 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger me.onDeath = function () { //helps collisions functions work better after vertex have been changed setTimeout(() => { //fix mob in place, but allow rotation for (let i = 0, len = 6; i < len; i++) { @@ -6713,7 +6882,7 @@ const spawn = { }); } }; - me.damageReduction = 0.25 + me.damageReduction = 0.27 me.do = function () { // this.armor(); if (this.grenadeLimiter > 1) this.grenadeLimiter-- @@ -6875,7 +7044,7 @@ const spawn = { me.onDamage = function () { this.cycle = 0 }; - me.damageReduction = 0.35 + me.damageReduction = 0.39 me.do = function () { Matter.Body.rotate(this, 0.003) //gently spin around this.checkStatus(); @@ -7011,7 +7180,7 @@ const spawn = { // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed }; me.onDamage = function () { }; - me.damageReduction = 0.25 + me.damageReduction = 0.28 me.do = function () { // this.armor(); this.seePlayerCheck(); @@ -7393,7 +7562,7 @@ const spawn = { mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)"); let me = mob[mob.length - 1]; me.collisionFilter.mask = cat.bullet | cat.player | cat.body //| cat.mob - me.damageReduction = 0.028 + me.damageReduction = 0.031 Matter.Body.setDensity(me, 0.0001); //normal is 0.001 // me.accelMag = 0.0007 * simulation.accelScale; @@ -7432,8 +7601,8 @@ const spawn = { mobs.spawn(x, y, 8, radius, "rgb(0,60,80)"); let me = mob[mob.length - 1]; me.isBoss = true; - Matter.Body.setDensity(me, 0.0005 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.25 + Matter.Body.setDensity(me, 0.0006 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.27 me.startingDamageReduction = me.damageReduction me.isInvulnerable = false me.nextHealthThreshold = 0.75 @@ -7682,8 +7851,8 @@ const spawn = { mobs.spawn(x, y, nodes, radius, "rgb(255,0,150)"); let me = mob[mob.length - 1]; me.isBoss = true; - Matter.Body.setDensity(me, 0.0017 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.1 + Matter.Body.setDensity(me, 0.0018 + 0.00015 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.11 me.stroke = "transparent"; //used for drawGhost me.seeAtDistance2 = 2000000; diff --git a/js/tech.js b/js/tech.js index d10f69e..0879a0b 100644 --- a/js/tech.js +++ b/js/tech.js @@ -73,7 +73,7 @@ const tech = { }, junkChance: 0, addJunkTechToPool(percent) { //percent is number between 0-1 - simulation.makeTextLog(`+${(100 * percent).toFixed(0)}% JUNKtech chance (${100 * tech.junkChance.toFixed(0)} total chance)`) + simulation.makeTextLog(`+${(100 * percent).toFixed(0)}% JUNKtech chance (${(100 * tech.junkChance).toFixed(0)} total chance)`) // tech.junkChance += (1 - tech.junkChance) * percent tech.junkChance += percent if (tech.junkChance < 0.001 || tech.junkChance === undefined) tech.junkChance = 0 @@ -207,12 +207,14 @@ const tech = { damage: 1, //used for tech changes to player damage that don't have complex conditions damageFromTech() { let dmg = tech.damage * m.fieldDamage + if (tech.isMaxHealthDamage && m.health === m.maxHealth) dmg *= 1.5 + if (tech.isNoDefenseDamage && m.defense() === 1) dmg *= 2 if (tech.isImmunityDamage && m.immuneCycle > m.cycle) dmg *= 4 if (tech.isPowerUpDamage) dmg *= 1 + 0.05 * powerUp.length if (tech.isDamageCooldown) dmg *= m.lastKillCycle + tech.isDamageCooldownTime > m.cycle ? 0.5 : 4 if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 2 if (tech.isDivisor && b.activeGun !== undefined && b.activeGun !== null && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.8 - if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.85 : 2 + if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.9 : 2 if (tech.isDilate) dmg *= 1.9 + 1.1 * Math.sin(m.cycle * 0.01) if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.3 * b.inventory.length if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage @@ -227,12 +229,12 @@ const tech = { if (tech.isRerollDamage) dmg *= 1 + Math.max(0, 0.05 * powerUps.research.count) if (tech.isBotDamage) dmg *= 1 + 0.04 * b.totalBots() if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage - if (tech.isLowEnergyDamage) dmg *= 1 + Math.max(0, 1 - m.energy) + if (tech.isLowEnergyDamage) dmg *= 1 + 0.5 * Math.max(0, m.maxEnergy - m.energy) if (tech.energyDamage) dmg *= 1 + m.energy * 0.23 * tech.energyDamage; if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.01 if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 if (tech.isSpeedDamage) dmg *= 1 + Math.min(1, (tech.speedAdded + player.speed) * 0.0193) - if (tech.isAxion && tech.isHarmMACHO) dmg *= (tech.isMoveMACHO ? 3 : 2) + if (tech.isAxion && tech.isHarmDarkMatter) dmg *= ((tech.isMoveDarkMatter || tech.isNotDarkMatter) ? 3.2 : 2) if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3; if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit // if (tech.isLowHealthDmg) dmg *= 1 + 0.6 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health)) @@ -874,8 +876,6 @@ const tech = { { name: "Pareto efficiency", descriptionFunction() { - // return `for each gun randomly
gain 5x or 0.2x ammo per ${powerUps.orb.ammo(1)}` - // return `randomly adjust your guns by
5x or 0.2x ammo per ${powerUps.orb.ammo(1)}` return `for each of your guns
randomly get 5x or 0.2x ammo per ${powerUps.orb.ammo(1)}` }, maxCount: 1, @@ -898,16 +898,6 @@ const tech = { simulation.makeTextLog(`${(b.guns[index].ammoPack).toFixed(1)} ${(b.guns[index].ammoPack * scale).toFixed(1)} average ammo per ${powerUps.orb.ammo(1)} for ${b.guns[index].name}`, Infinity) b.guns[index].ammoPack *= scale } - - // let options = [] - // for (let i = 0; i < b.guns.length - 1; i++) options.push(i) - // options = shuffle(options) - // for (let i = 0; i < options.length; i++) { - // const index = options[i] - // const scale = (i < options.length / 2) ? 4 : 0.25 - // simulation.makeTextLog(`${(b.guns[index].ammoPack).toFixed(1)} ${(b.guns[index].ammoPack * scale).toFixed(1)} average ammo per ${powerUps.orb.ammo(1)} for ${b.guns[index].name}`, Infinity) - // b.guns[index].ammoPack *= scale - // } }, remove() { } }, @@ -932,7 +922,7 @@ const tech = { { name: "cache", link: `cache`, - description: `15x ammo per ${powerUps.orb.ammo()}, but
you can't store any more ammo than that`, + description: `17x ammo per ${powerUps.orb.ammo()}, but
you can't store additional ammo`, maxCount: 1, count: 0, frequency: 1, @@ -942,7 +932,7 @@ const tech = { }, requires: "not non-renewables", effect() { - tech.ammoCap = 15; + tech.ammoCap = 17; powerUps.ammo.effect() }, remove() { @@ -1115,12 +1105,13 @@ const tech = { }, requires: "", effect() { - tech.isFarAwayDmg = true; //used in mob.damage() + tech.isFarAwayDmg = true; }, remove() { tech.isFarAwayDmg = false; } }, + { name: "microstates", link: `microstates`, @@ -2416,8 +2407,11 @@ const tech = { } }, { - name: "MACHO", - description: "a massive compact halo object follows you
0.4x damage taken inside the MACHO", + name: "dark matter", + //a MAssive Compact Halo Object follows you
+ descriptionFunction() { + return `dark matter slowly gravitates towards you
0.4x damage taken ${tech.isNotDarkMatter ? "outside" : "inside"} dark matter` + }, maxCount: 1, count: 0, frequency: 1, @@ -2427,46 +2421,30 @@ const tech = { }, requires: "", effect() { - tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO - spawn.MACHO() + tech.isDarkMatter = true; //this harm reduction comes from the particle toggling tech.isHarmDarkMatter + spawn.darkMatter() }, remove() { - tech.isMACHO = false; - tech.isHarmMACHO = false; + tech.isDarkMatter = false; + tech.isHarmDarkMatter = false; for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].isMACHO) mob[i].alive = false; + if (mob[i].isDarkMatter) mob[i].alive = false; } } }, - { - name: "entropic gravity", - description: "crouching pulls the MACHO towards you
1.5x for all MACHO effects", - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.isMACHO - }, - requires: "MACHO", - effect() { - tech.isMoveMACHO = true - }, - remove() { - tech.isMoveMACHO = false - } - }, { name: "axion", - description: "while inside the MACHO
2x damage", + descriptionFunction() { + return `while ${tech.isNotDarkMatter ? "outside" : "inside"} dark matter
2x damage` + }, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return tech.isMACHO + return tech.isDarkMatter }, - requires: "MACHO", + requires: "dark matter", effect() { tech.isAxion = true }, @@ -2475,16 +2453,72 @@ const tech = { } }, { - name: "dark star", - description: `mobs inside the MACHO are damaged
1.3x MACHO radius`, + name: "dark energy", + descriptionFunction() { + return `while ${tech.isNotDarkMatter ? "outside" : "inside"} dark matter
generate 10 energy per second` + }, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return tech.isMACHO + return tech.isDarkMatter }, - requires: "MACHO", + requires: "dark matter", + effect() { + tech.isDarkEnergy = true + }, + remove() { + tech.isDarkEnergy = false + } + }, + { + name: "MACHO", + description: "dark matter's effects are only active outside it's range
1.6x to all dark matter effects
", + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isDarkMatter && !tech.isMoveDarkMatter && !tech.isDarkStar + }, + requires: "dark matter, not entropic gravity, dark star", + effect() { + tech.isNotDarkMatter = true + }, + remove() { + tech.isNotDarkMatter = false + } + }, + { + name: "entropic gravity", + description: "crouching pulls dark matter towards you
1.6x to all dark matter effects", + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isDarkMatter && !tech.isNotDarkMatter + }, + requires: "dark matter, not MACHO", + effect() { + tech.isMoveDarkMatter = true + }, + remove() { + tech.isMoveDarkMatter = false + } + }, + { + name: "dark star", + description: `mobs inside dark matter are damaged
1.3x dark matter radius`, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isDarkMatter && !tech.isNotDarkMatter + }, + requires: "dark matter, not MACHO", effect() { tech.isDarkStar = true }, @@ -2552,7 +2586,7 @@ const tech = { }, { name: "Pauli exclusion", - description: `for 6 seconds after mob collisions
become invulnerable and inhibit energy regen`, + description: `for 8 seconds after mob collisions
become invulnerable and inhibit energy regen`, maxCount: 9, count: 0, frequency: 1, @@ -2562,7 +2596,7 @@ const tech = { }, requires: "", effect() { - m.collisionImmuneCycles += 360; + m.collisionImmuneCycles += 480; if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage }, remove() { @@ -2729,27 +2763,21 @@ const tech = { { name: "Gibbs free energy", descriptionFunction() { - return `use ${powerUps.orb.research(2)}
1.01x damage per energy below 100 (${(1 + Math.max(0, 1 - m.energy)).toFixed(2)}x)` + return `1.005x damage for each missing energy
(${(1 + 0.5 * Math.max(0, m.maxEnergy - m.energy)).toFixed(2)}x)` }, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return powerUps.research.count > 1 || build.isExperimentSelection + return true }, requires: "", effect() { tech.isLowEnergyDamage = true; - for (let i = 0; i < 2; i++) { - if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) - } }, remove() { tech.isLowEnergyDamage = false; - if (this.count > 0) { - powerUps.research.changeRerolls(2) - } } }, { @@ -2780,7 +2808,7 @@ const tech = { }, { name: "Maxwells demon", - description: "energy above max decays 30x slower
+5% JUNKtech chance", + description: "energy above maximum decays 30x slower
+5% JUNKtech chance", maxCount: 1, count: 0, frequency: 2, @@ -2868,7 +2896,7 @@ const tech = { }, { name: "waste heat recovery", - description: "if a mob has died in the last 5 seconds
generate 0.05x max energy every second", + description: "if a mob has died in the last 5 seconds
generate 0.05x maximum energy every second", maxCount: 1, count: 0, frequency: 1, @@ -2887,7 +2915,7 @@ const tech = { { name: "recycling", descriptionFunction() { - return `if a mob has died in the last 5 seconds
recover 0.005x max ${tech.isEnergyHealth ? "energy" : "health"} every second` + return `if a mob has died in the last 5 seconds
recover 0.005x maximum ${tech.isEnergyHealth ? "energy" : "health"} every second` }, description: "", maxCount: 1, @@ -2924,6 +2952,66 @@ const tech = { tech.isHarmReduceNoKill = false; } }, + { + name: "stability", + descriptionFunction() { + return `0.3x damage taken
while your health is at maximum` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isMaxHealthDefense = true; + }, + remove() { + tech.isMaxHealthDefense = false; + } + }, + { + name: "instability", + descriptionFunction() { + return `2x damage while your damage taken is 1.00x
(damage taken = ${(m.defense()).toFixed(2)}x)` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isNoDefenseDamage = true; + }, + remove() { + tech.isNoDefenseDamage = false; + } + }, + { + name: "control theory", + descriptionFunction() { + return `1.5x damage
while your health is at maximum` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isMaxHealthDamage = true; + }, + remove() { + tech.isMaxHealthDamage = false; + } + }, { name: "homeostasis", descriptionFunction() { @@ -3059,7 +3147,7 @@ const tech = { allowed() { return m.maxHealth > 1; }, - requires: "max health above 100", + requires: "maximum health above 100", effect() { tech.isAcidDmg = true; }, @@ -3070,7 +3158,7 @@ const tech = { { name: "induction brake", descriptionFunction() { - return `after using ${powerUps.orb.heal()} slow nearby mobs for 17 seconds` + return `after using ${powerUps.orb.heal()}
slow nearby mobs for 17 seconds` }, maxCount: 1, count: 0, @@ -3133,7 +3221,7 @@ const tech = { { name: "quenching", descriptionFunction() { - return `${powerUps.orb.heal()} overhealing results in 2x health loss
and 2x max health increase` + return `${powerUps.orb.heal()} overhealing results in 2x health loss
and 2x maximum health increase` }, maxCount: 1, count: 0, @@ -5029,7 +5117,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0)) + return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.isNeedleIce || (m.coupling && (m.fieldMode === 2 || m.fieldMode === 0)) }, requires: "a freeze effect", effect() { @@ -5067,7 +5155,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0))) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob + return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.isNeedleIce || (m.coupling && (m.fieldMode === 2 || m.fieldMode === 0))) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob }, requires: "a localized freeze effect, no other mob death tech", effect() { @@ -5086,7 +5174,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0)) || tech.iceIXOnDeath || tech.isIceShot + return (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isNeedleIce || (m.coupling && (m.fieldMode === 2 || m.fieldMode === 0)) || tech.iceIXOnDeath || tech.isIceShot }, requires: "ice IX", effect() { @@ -5105,7 +5193,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0)) || tech.iceIXOnDeath || tech.isIceShot + return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isNeedleIce || (m.coupling && (m.fieldMode === 2 || m.fieldMode === 0)) || tech.iceIXOnDeath || tech.isIceShot }, requires: "a localized freeze effect", effect() { @@ -5130,7 +5218,7 @@ const tech = { // }, // requires: "perfect diamagnetism", allowed() { - return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0))) + return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.isNeedleIce || (m.coupling && (m.fieldMode === 2 || m.fieldMode === 0))) }, requires: "a localized freeze effect", effect() { @@ -7423,7 +7511,7 @@ const tech = { //************************************************** { name: "spherical harmonics", - description: "1.5x standing wave deflection energy efficiency
shield deflection radius holds it's max range", //standing wave oscillates in a 3rd dimension
+ description: "1.5x standing wave deflection energy efficiency
shield deflection radius is stable", //standing wave oscillates in a 3rd dimension
isFieldTech: true, maxCount: 9, count: 0, @@ -7513,9 +7601,13 @@ const tech = { } }, { + + // descriptionFunction() { + // return `use ${powerUps.orb.research(2)}
1.01x damage per energy below maximum (${(1 + Math.max(0, m.maxEnergy - m.energy)).toFixed(2)}x)` + // }, name: "electronegativity", descriptionFunction() { - return `1.0023x damage per energy
(${(1 + 0.23 * m.maxEnergy).toFixed(2)}x damage at max energy)` + return `1.0023x damage per energy
(${(1 + 0.23 * m.energy).toFixed(2)} at current energy, ${(1 + 0.23 * m.maxEnergy).toFixed(2)}x at maximum energy)` }, // description: "+1% damage per 8 stored energy", isFieldTech: true, @@ -7653,7 +7745,7 @@ const tech = { { name: "dynamic equilibrium", descriptionFunction() { - return `increase damage by your last ${tech.isEnergyHealth ? "energy" : "health"} loss
style ="float: right;">(${(1 + tech.lastHitDamage * m.lastHit).toFixed(2)}x damage)` + return `increase damage by your last ${tech.isEnergyHealth ? "energy" : "health"} loss
(${(1 + tech.lastHitDamage * m.lastHit).toFixed(2)}x damage)` }, isFieldTech: true, maxCount: 9, @@ -7701,7 +7793,7 @@ const tech = { }, { name: "aerostat", - description: `2x damage while off the ground
0.85x damage while on the ground`, + description: `2x damage while off the ground
0.9x damage while on the ground`, isFieldTech: true, maxCount: 1, count: 0, @@ -8022,7 +8114,7 @@ const tech = { }, { name: "tokamak", - description: "throwing a block converts it into energy
and a pulsed fusion explosion", + description: "tokamak converts thrown blocks into energy
and a pulsed fusion explosion", isFieldTech: true, maxCount: 1, count: 0, @@ -8039,6 +8131,47 @@ const tech = { tech.isTokamak = false; } }, + { + name: "stellarator", + descriptionFunction() { + return `the first 5 blocks detonated by tokamak
spawn ${powerUps.orb.heal(1)} proportional to block size` + }, + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 3, + frequencyDefault: 3, + allowed() { + return tech.isTokamak && (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) + }, + requires: "tokamak", + effect() { + tech.isTokamakHeal = true; + tech.tokamakHealCount = 0 + }, + remove() { + tech.isTokamakHeal = false; + } + }, + { + name: "inertial confinement", + description: "while holding a block charged with tokamak
you can use energy to fly", //and invulnerable? + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 3, + frequencyDefault: 3, + allowed() { + return tech.isTokamak && (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) + }, + requires: "tokamak", + effect() { + tech.isTokamakFly = true; + }, + remove() { + tech.isTokamakFly = false; + } + }, { name: "degenerate matter", description: "if your field is active
0.1x damage taken", @@ -11764,7 +11897,6 @@ const tech = { isDroneRespawn: null, deathSpawns: null, isMobBlockFling: null, - // blockingIce: null, isPhaseVelocity: null, waveBeamSpeed: null, wavePacketAmplitude: null, @@ -11772,14 +11904,18 @@ const tech = { iceIXOnDeath: null, wimpCount: null, isAddBlockMass: null, - isMACHO: null, - isHarmMACHO: null, - isMoveMACHO: null, + isDarkMatter: null, + isHarmDarkMatter: null, + isMoveDarkMatter: null, + isNotDarkMatter: null, isSneakAttack: null, isFallingDamage: null, harmonics: null, isStandingWaveExpand: null, isTokamak: null, + isTokamakHeal: null, + tokamakHealCount: null, + isTokamakFly: null, deflectEnergy: null, superBallDelay: null, isBlockExplode: null, @@ -11829,6 +11965,7 @@ const tech = { isRewindField: null, isCrouchRegen: null, isAxion: null, + isDarkEnergy: null, isDarkStar: null, isWormholeMapIgnore: null, isLessDamageReduction: null, @@ -11909,4 +12046,7 @@ const tech = { interestRate: null, isImmunityDamage: null, isMobDeathImmunity: null, + isMaxHealthDefense: null, + isNoDefenseDamage: null, + isMaxHealthDamage: null, } \ No newline at end of file diff --git a/style.css b/style.css index e63679f..347b57b 100644 --- a/style.css +++ b/style.css @@ -311,7 +311,7 @@ summary { .sort-button { border: 1px #333 solid; - border-radius: 0.5em; + border-radius: 0.4em; background-color: #fff; font-size: 0.5em; /* padding: 0.3em; */ @@ -872,11 +872,17 @@ summary { text-shadow: 0px 0px 7px #000; } -.color-MACHO { +.color-dark-matter { color: #246; text-shadow: 0px 0px 7px #246; } +.color-tokamak { + color: #5c3ab8; + font-weight: 100; + text-shadow: 0px -5px 9px rgb(255, 0, 204); +} + .color-dup { font-variant: small-caps; letter-spacing: 1px; diff --git a/todo.txt b/todo.txt index 947e8a8..bf37b72 100644 --- a/todo.txt +++ b/todo.txt @@ -1,37 +1,22 @@ ******************************************************** NEXT PATCH ************************************************** -new community levels: (you can enable community maps in the settings) - rings by thatLittleFrog - flappyGon by Digin - trial by Cirryn and Tarantula Hawk - arena level updated by Whyisthisnotavalable +renamed MACHO -> dark matter +tech: MACHO - dark matter is active when you are outside not inside it's range, 1.5 to dark matter effects +tech: dark energy - inside dark matter regen 10 energy +tech: stability - 0.3x damage taken if health equals maxHealth +tech: instability - 2x damage if damage taken is 1x +tech: control theory - 1.5x damage if health equals maxHealth +tech: inertial confinement - while charging tokamak you can fly, but energy drains +tech: stellarator - after firing a block with tokamak, spawn up to 5 heals -difficulty scaling: 0.84->0.85x player damage per level -research spawn per level is no longer in the difficulty settings - instead players get 1 research for only the first few levels -cell boss has less health at high difficulty +boss health nerf: almost every boss has ~0.8x less health + secondary bosses also spawn 2 ammo +aerostat 0.85->0.9 damage on the ground +Pauli exclusion 6->8 seconds of invulnerable after getting hit +Gibbs free energy 2->0 research cost, 1.01->1.05 damage scales with energy below 100->maxEnergy +cache 15->17x ammo -converted JUNK tech to additive, instead of the multiplicative - makes the first JUNK you take do the same, but if you take too much you can get to 100% -right aligned some text in tech descriptions -added some circles to the in-game console messages - -renamed slow light -> delayed-choice - a single 0.4 second delayed 0.7x damage laser beam - also now works with reflection -plasma torch field gets 1.5x damage by default -molecular assembler coupling 0.8->0.6 energy per second -nail-bot upgrade 5->4x fire rate -foam-bot upgrade 3->2.5x size and fire rate -sound-bot upgrade 2.5->2x fire rate, damage, 1->2x wave packet length -boom-bot upgrade reduced range, bot acceleration -orbital-bot upgrade 1.5->2x radius -perimeter defense 0.95->0.96x damage taken per bot -network effect 1.05->1.04x damage per bot -tech: working mass - cleaned up physics and logic a bit -negative feedback scales with health below maxHealth, not health below 100 - 1.007->1.006x damage per missing health -homeostasis scales with missing health, not health below 100 - limit of 0.2x at 0 health +several bug fixes ******************************************************* DESIGN ****************************************************** @@ -59,57 +44,19 @@ list of powerful synergies *********************************************************** TODO ***************************************************** -figure out how to put controls in background on initial level - mouse smooth makes the text position jitter when it moves sub pixels - hide the jitter with artificial jitter to make it seem intentional - make it look like the instructions are on a fuzzy TV screen - when player presses move buttons highlight the box/letter for those buttons - -a few bosses have too much health - probably the ones that scale with simulation.difficulty - Matter.Body.setDensity(me, 0.00012 + 0.00001 * simulation.difficulty) // normal density is 0.001 - - -make player mass an adjustable var in the skin - does this mess with jump height or air control? -increase mass and movement speed at the same time - increase jump differently because it scales extra with mass - m.defaultMass = 4.5 - m.definePlayerMass() - possible player.mass bad interactions - grapple - -tech: - if health === maxHealth take 0.6x damage - do 1.5x damage? - -JUNK tech - player takes damage from block collisions - is this gonna contribute to lag? - -tech: anthropic principle - cost 1 research to let you not die once per level - another tech that allows it to trigger multiple times - -tokamak synergy tech - tech: stellarator - after firing a block with tokamak, heal (scale heal amount with block mass?) - tech: inertial confinement - while charging tokamak you can fly, and invulnerable - but energy drains - -bullets should trigger shrinking platforms level element? - -level element - player activated elevators - could be fast and throw player - could just rise up slow (slow might have a bad jerky animation) - -tech: super balls split after 3 seconds - but they lost 50% less time - -buff plasma torch - buff plasma tech? - buff plasma field defense? - buff plasma damage? - -rework energy and health HUD - make both diegetic? - should health be red or green? +snakeBoss - boss with a tail that grows longer + improve behavior for when it can't see player + wander around looking for power ups + what if it gets lost? + eat power ups + eject them after you die + get longer after eating + eat mobs? + eat blocks? + modes: recolor tail based on modes + hunting power ups -> small + fast : blue cyan + hunting player -> attack? : red/pink + slow high defense : white white laser what to name? not much in wikipedia @@ -119,23 +66,42 @@ white laser tech.laserColor = "#fff" tech.laserColorAlpha = "rgba(255, 255, 255, 0.5)" -bug Newton's 1st law image not showing up on github server - shows up on n-gon, and landgreen github, but webp file isn't loading onto server? - try name change, - wait and see if next patch fixes it - tech: atomic pile - lose 1 health if you are above the maximum energy generate energy for each nearby mob? do damage? plasma torch tech? -boss mob - several squares that move like the snake in the game snake/light cycles - moves towards player (is smell history pathing good enough?) - doesn't have inertia/force? or it obeys normal physics kinda? - gets longer when - you hit it with bullets? - it gets near a power up? - it gets near mobs +make some explosions have less knock back? + annoying with flame test, boom bot? + +figure out how to put instructions for controls in background on initial level + mouse smooth makes the text position jitter when it moves sub pixels + hide the jitter with artificial jitter to make it seem intentional + make it look like the instructions are on a fuzzy TV screen + when player presses move buttons highlight the box/letter for those buttons + +make player mass an adjustable var in the skin + does this mess with jump height or air control? +increase mass and movement speed at the same time + increase jump differently because it scales extra with mass + m.defaultMass = 4.5 + m.definePlayerMass() + possible player.mass bad interactions + grapple + +JUNK tech - player takes damage from block collisions + is this gonna contribute to lag? + +bullets should trigger shrinking platforms level element? + +level element - player activated elevators + could be fast and throw player + could just rise up slow (slow might have a bad jerky animation) + +rework energy and health HUD + make both diegetic? + how? not sure there is a good way to do this... + should health be red or green? Boss mob - takes a snapshot of the positions of all mobs, player, blocks, power ups. Then 3 seconds later it teleports everything back to those spots. after snap shot is stored draw outline of body positions for a second to show the change @@ -1328,6 +1294,8 @@ possible names for tech Casimir effect - attractive force between two close conductive plates difference engine - early calculator/computer cyanoacrylate - superglue use for a slowing effect? + hysteresis - the dependence of the state of a system on its history + superposition - something with waves overlapping ******************************************************** IMAGES ********************************************************