From 746e86cc4a1bd3f6d88a85155df5d0f7c8aee211 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sun, 31 Jul 2022 07:09:57 -0700 Subject: [PATCH] beetlemania mob: beetleBoss mob: flutter balance: all mobs at every level are about 2%-3% harder to kill --- js/level.js | 22 +++--- js/mob.js | 16 ++++ js/player.js | 2 +- js/spawn.js | 215 +++++++++++++++++++++++++++++++++++++++++++++++---- js/tech.js | 12 +-- todo.txt | 24 +++--- 6 files changed, 245 insertions(+), 46 deletions(-) diff --git a/js/level.js b/js/level.js index 868f44e..e8381e2 100644 --- a/js/level.js +++ b/js/level.js @@ -16,7 +16,7 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.enableConstructMode() //used to build maps in testing mode - // level.difficultyIncrease(6 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(8 * 4) //30 is near max on hard //60 is near max on why // simulation.isHorizontalFlipped = true // m.maxHealth = m.health = 100 // powerUps.research.changeRerolls(100000) @@ -24,7 +24,7 @@ const level = { // powerUps.research.changeRerolls(100) // tech.tech[297].frequency = 100 // b.guns[0].ammo = 10000 - // m.setField("molecular assembler") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass + // m.setField("time dilation") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass // b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // tech.giveTech("infrared diode"); // tech.giveTech("active cooling"); @@ -37,8 +37,8 @@ const level = { // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research"); // spawn.starter(1900, -500, 200) // spawn.starter(1900, -500, 50) - // spawn.revolutionBoss(1900, -500) - // for (let i = 0; i < 10; ++i) spawn.starter(1900 + 300 * Math.random(), -500 + 300 * Math.random()) + // spawn.beetleBoss(1900, -400) + // for (let i = 0; i < 10; ++i) spawn.flutter(1900 + 300 * Math.random(), -500 + 300 * Math.random()) // level.testing(); //not in rotation, used for testing // for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); // for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); @@ -148,7 +148,7 @@ const level = { difficultyIncrease(num = 1) { for (let i = 0; i < num; i++) { simulation.difficulty++ - m.dmgScale *= 0.925; //damage done by player decreases each level + m.dmgScale *= 0.922; //damage done by player decreases each level if (simulation.accelScale < 6) simulation.accelScale *= 1.025 //mob acceleration increases each level if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level } @@ -159,7 +159,7 @@ const level = { difficultyDecrease(num = 1) { //used in easy mode for simulation.reset() for (let i = 0; i < num; i++) { simulation.difficulty-- - m.dmgScale /= 0.925; //damage done by player decreases each level + m.dmgScale /= 0.922; //damage done by player decreases each level if (simulation.accelScale > 1) simulation.accelScale /= 1.025 //mob acceleration increases each level if (simulation.CDScale < 1) simulation.CDScale /= 0.965 //mob CD time decreases each level } @@ -254,8 +254,10 @@ const level = { level.levels = shuffle(level.levels); //shuffles order of maps } // level.levels.splice(Math.floor(level.levels.length * (0.4 + 0.6 * Math.random())), 0, "reservoir"); //add level to the back half of the randomized levels list - level.levels.splice(Math.floor(Math.seededRandom((level.levels.length) * 0.6, level.levels.length)), 0, "reservoir"); //add level to the back half of the randomized levels list - level.levels.splice(Math.floor(Math.seededRandom((level.levels.length) * 0.6, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list + level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, "reservoir"); //add level to the back half of the randomized levels list + level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list + // level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.2, level.levels.length * 0.5)), 0, "reactor"); //add level to the back half of the randomized levels list + // level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.7, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list level.levels.splice(0, 2); //remove 2 levels from the start of the array if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech level.levels.unshift("intro"); //add level to the start of the randomized levels list @@ -2733,7 +2735,7 @@ const level = { spawn.mapRect(475, -25, 25, 50); //edge shelf }, testing() { - const hazard = level.hazard(6000, -1000, 5, 1000, 0.4) //laser + // const hazard = level.hazard(6000, -1000, 5, 1000, 0.4) //laser const button = level.button(1000, 0) spawn.bodyRect(1000, -50, 50, 50); @@ -2747,7 +2749,7 @@ const level = { level.enter.draw(); }; level.customTopLayer = () => { - hazard.opticalQuery(); + // hazard.opticalQuery(); button.query(); button.draw(); ctx.fillStyle = "rgba(0,0,0,0.1)" diff --git a/js/mob.js b/js/mob.js index 1c349a1..54f277f 100644 --- a/js/mob.js +++ b/js/mob.js @@ -589,6 +589,22 @@ const mobs = { ctx.setLineDash([]); } }, + wing(a, radius = 250, ellipticity = 0.4) { + const minorRadius = radius * ellipticity + const perp = { x: Math.cos(a), y: Math.sin(a) } // + const where = Vector.add(this.position, Vector.mult(perp, radius + 0.8 * this.radius)) + + ctx.beginPath(); + ctx.ellipse(where.x, where.y, radius, minorRadius, a, 0, 2 * Math.PI) + ctx.fill(); + + //check for wing -> player damage + const hitPlayer = Matter.Query.ray([player], this.position, Vector.add(this.position, Vector.mult(perp, radius * 2.05)), minorRadius) + if (hitPlayer.length && m.immuneCycle < m.cycle) { + m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage + m.damage(0.00008 * radius * simulation.dmgScale); + } + }, searchSpring() { //draw the two dots on the end of the springs ctx.beginPath(); diff --git a/js/player.js b/js/player.js index d404f1b..63a4665 100644 --- a/js/player.js +++ b/js/player.js @@ -2884,7 +2884,7 @@ const m = { //show sneak attack status // if (m.cycle > m.lastKillCycle + 240) { // if (m.sneakAttackCharge > 0) { - if (m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) { + if (m.sneakAttackCycle + Math.min(120, 0.7 * (m.cycle - m.enterCloakCycle)) > m.cycle) { ctx.strokeStyle = "rgba(0,0,0,0.5)" //m.fieldMeterColor; //"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, 28, 0, 2 * Math.PI); diff --git a/js/spawn.js b/js/spawn.js index 10420fb..adb3294 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -5,7 +5,8 @@ const spawn = { 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" + "snakeBoss", "snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "shieldingBoss", "timeSkipBoss", + "beetleBoss" ], bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed bossTypeSpawnIndex: 0, //increases as the boss type cycles @@ -24,6 +25,7 @@ const spawn = { "slasher", "slasher", "slasher", "stabber", "stabber", "stabber", "springer", "springer", "springer", + "flutter", "flutter", "shooter", "shooter", "grenadier", "grenadier", "striker", "striker", @@ -33,7 +35,7 @@ const spawn = { ], mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed mobTypeSpawnIndex: 0, //increases as the mob type cycles - allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher"], + allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter"], setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level spawn.pickList.splice(0, 1); const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length] @@ -2068,8 +2070,9 @@ const spawn = { let targets = [] //track who is in the node boss, for shields mobs.spawn(x, y, 6, radius, "#b386e8"); let me = mob[mob.length - 1]; - Matter.Body.setDensity(me, 0.0032); //extra dense //normal is 0.001 //makes effective life much larger and damage on collision + Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 //makes effective life much larger and damage on collision me.isBoss = true; + me.damageReduction = 0.13 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) //normal is 1, most bosses have 0.25 targets.push(me.id) //add to shield protection me.friction = 0; @@ -2110,7 +2113,6 @@ const spawn = { Composite.add(engine.world, cons[cons.length - 1]); cons[len2].length = 100 + 1.5 * radius; me.cons2 = cons[len2]; - me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) //normal is 1, most bosses have 0.25 me.do = function() { // this.armor(); this.gravity(); @@ -2134,7 +2136,7 @@ const spawn = { for (let i = 0; i < nodes; ++i) { spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12); Matter.Body.setDensity(mob[mob.length - 1], 0.003); //extra dense //normal is 0.001 //makes effective life much larger - mob[mob.length - 1].damageReduction = 0.5 + mob[mob.length - 1].damageReduction = 0.12 targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields } @@ -2690,6 +2692,190 @@ const spawn = { } } }, + flutter(x, y, radius = 20 + 6 * Math.random()) { + mobs.spawn(x, y, 7, radius, '#16576b'); + let me = mob[mob.length - 1]; + me.isBoss = true; + Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger + // me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + + 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); + me.accelMag = 0.0006 + 0.0006 * Math.sqrt(simulation.accelScale); + me.frictionAir = 0.05; + // me.seePlayerFreq = 40 + Math.floor(13 * Math.random()) + me.memory = 240; + me.restitution = 1; + me.frictionStatic = 0; + me.friction = 0; + me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1); + me.fireDir = { x: 0, y: 0 } + spawn.shield(me, x, y); + + // me.onDeath = function() {}; + me.flapRate = 0.3 + Math.floor(3 * Math.random()) / 10 + 100 * me.accelMag + me.flapRadius = 100 + 75 * Math.random() + radius * 2 + me.do = function() { + this.seePlayerByHistory() + this.checkStatus(); + if (this.seePlayer.recall) { + this.force.x += Math.cos(this.angle) * this.accelMag * this.mass + this.force.y += Math.sin(this.angle) * this.accelMag * this.mass + + //set direction to turn to fire + if (!(simulation.cycle % this.seePlayerFreq)) { + this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); + + //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles + const mod = (a, n) => { + return a - Math.floor(a / n) * n + } + const sub = Vector.sub(m.pos, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different + const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI + if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random(); + } + + //rotate towards fireDir + const angle = this.angle + Math.PI / 2; + c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; + const threshold = 0.4; + const turn = 0.00003 * this.inertia + if (c > threshold) { + this.torque += turn; + } else if (c < -threshold) { + this.torque -= turn; + } + const flapArc = 0.7 //don't go past 1.57 for normal flaps + + ctx.fillStyle = `hsla(${160+40*Math.random()}, 100%, ${25 + 25*Math.random()*Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)"; + this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) + this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) + } + }; + }, + beetleBoss(x, y, radius = 60) { + mobs.spawn(x, y, 7, radius, '#16576b'); + 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 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = me.damageReduction + me.isInvulnerable = false + me.nextHealthThreshold = 0.75 + me.invulnerableCount = 0 + + 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); + me.accelMag = 0.0006 + 0.0006 * Math.sqrt(simulation.accelScale); + me.frictionAir = 0.05; + me.seePlayerFreq = 30 + me.memory = 420; + me.restitution = 1; + me.frictionStatic = 0; + me.friction = 0; + me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1); + me.fireDir = { x: 0, y: 0 } + spawn.shield(me, x, y); + + // for (let i = 0, len = 4 + 0.2 * simulation.difficulty; i < len; ++i) { + // const phase = i / len * 2 * Math.PI + // const where = Vector.add(me.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5)) + // spawn.flutter(where.x, where.y) + // } + + me.onDeath = function() { + powerUps.spawnBossPowerUp(this.position.x, this.position.y) + + len = 0.2 * simulation.difficulty + if (len > 3) { + for (let i = 0; i < len; ++i) { + const phase = i / len * 2 * Math.PI + const where = Vector.add(this.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5)) + spawn.flutter(where.x, where.y) + } + } + }; + me.onDamage = function() { + if (this.health < this.nextHealthThreshold) { + this.health = this.nextHealthThreshold - 0.01 + this.nextHealthThreshold = Math.floor(this.health * 4) / 4 + this.invulnerableCount = 180 + Math.floor(60 * Math.random()) + this.isInvulnerable = true + this.damageReduction = 0 + this.frictionAir = 0 + } + }; + me.do = function() { + this.seePlayerByHistory() + this.checkStatus(); + if (this.isInvulnerable) { + this.invulnerableCount-- + if (this.invulnerableCount < 0) { + this.isInvulnerable = false + this.damageReduction = this.startingDamageReduction + this.frictionAir = 0.05 + } + // //draw wings as if they are protecting + // const wingShield = (a, size) => { + // ctx.beginPath(); + // const perp = { x: Math.cos(a), y: Math.sin(a) } // + // const where = Vector.add(this.position, Vector.mult(perp, 0.2 * this.radius)) + // ctx.ellipse(where.x, where.y, size, size * 0.8, a, 0, 2 * Math.PI) + // ctx.fillStyle = this.fill = `hsla(${160+40*Math.random()}, 100%, ${25 + 25*Math.random()*Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)"; + // ctx.fill(); + // } + // wingShield(this.angle + Math.PI / 2, radius * 1.3) + // wingShield(this.angle - Math.PI / 2, radius * 1.3) + + //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(); + } else if (this.seePlayer.recall) { + // const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass) + // const force = Vector.mult({ x: Math.cos(this.angle), y: Math.sin(this.angle) }, this.accelMag * this.mass) + // this.force.x += force.x; + // this.force.y += force.y; + this.force.x += Math.cos(this.angle) * this.accelMag * this.mass + this.force.y += Math.sin(this.angle) * this.accelMag * this.mass + + //set direction to turn to fire + if (!(simulation.cycle % this.seePlayerFreq)) { + this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); + + //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles + //check by comparing different between angles. Give this a nudge if angles are 180 degree different + const mod = (a, n) => { + return a - Math.floor(a / n) * n + } + const sub = Vector.sub(m.pos, this.position) + const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI + if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random(); + } + + //rotate towards fireDir + const angle = this.angle + Math.PI / 2; + c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; + const threshold = 0.4; + const turn = 0.00003 * this.inertia + if (c > threshold) { + this.torque += turn; + } else if (c < -threshold) { + this.torque -= turn; + } + const flapRate = 0.5 + const flapArc = 0.7 //don't go past 1.57 for normal flaps + ctx.fillStyle = this.fill = `hsla(${160+40*Math.random()}, 100%, ${25 + 25*Math.random()*Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)"; + this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * flapRate), 250, 0.5) + this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * flapRate), 250, 0.5) + } + }; + }, laserTargetingBoss(x, y, radius = 80) { const color = "#07f" mobs.spawn(x, y, 3, radius, color); @@ -3846,6 +4032,10 @@ const spawn = { me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.startingDamageReduction = me.damageReduction me.isInvulnerable = false + me.nextHealthThreshold = 0.75 + me.invulnerableCount = 0 + + me.cycle = 0 me.inertia = Infinity; me.frictionAir = 0.01 me.restitution = 1 @@ -3889,9 +4079,6 @@ const spawn = { if (mob[i].isMine && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.explodeRange) mob[i].isExploding = true } }; - me.cycle = 0 - me.nextHealthThreshold = 0.75 - me.invulnerableCount = 0 // console.log(me.mass) //100 me.do = function() { me.seePlayer.recall = 1 @@ -4718,14 +4905,14 @@ const spawn = { }, bodyB: me, stiffness: 0.00004, - damping: 0.1 + damping: 0.2 }); Composite.add(engine.world, me.constraint); }, 2000); //add in a delay in case the level gets flipped left right me.isBoss = true; - Matter.Body.setDensity(me, 0.008 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + 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.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front me.isVerticesChange = true @@ -4738,9 +4925,7 @@ const spawn = { me.lookTorque = 0.000006 * (Math.random() > 0.5 ? -1 : 1); me.fireDir = { x: 0, y: 0 }; setTimeout(() => { - // spawn.spawnOrbitals(me, radius + 200 + 50 * Math.random(), 1); for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1); - }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital me.onDeath = function() { if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y) @@ -5051,6 +5236,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 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.accelMag = 0.0001 * simulation.accelScale; me.fireFreq = Math.floor(330 * simulation.CDScale) @@ -5062,13 +5249,11 @@ const spawn = { spawn.shield(me, x, y, 1); spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) - Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger me.onDeath = function() { if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y) // 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 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.do = function() { // this.armor(); this.seePlayerCheck(); diff --git a/js/tech.js b/js/tech.js index f84c784..c5c094d 100644 --- a/js/tech.js +++ b/js/tech.js @@ -317,9 +317,9 @@ const tech = { // isExperimentHide: true, isBadRandomOption: true, allowed() { - return !tech.isSuperDeterminism + return true }, - requires: "not superdeterminism", + requires: "", effect() { powerUps.spawn(m.pos.x, m.pos.y, "gun"); // this.count-- @@ -3043,9 +3043,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return !tech.isResearchReality //tech.isResearchBoss || tech.isMetaAnalysis || tech.isRerollBots || tech.isDeathAvoid || tech.isRerollDamage || build.isExperimentSelection + return !tech.isResearchReality && !tech.isSuperDeterminism //tech.isResearchBoss || tech.isMetaAnalysis || tech.isRerollBots || tech.isDeathAvoid || tech.isRerollDamage || build.isExperimentSelection }, - requires: "not Ψ(t) collapse", //"abiogenesis, meta-analysis, bot fabrication, anthropic principle, or Bayesian statistics, not Ψ(t) collapse", + requires: "not Ψ(t) collapse, superdeterminism", //"abiogenesis, meta-analysis, bot fabrication, anthropic principle, or Bayesian statistics, not Ψ(t) collapse", effect() { tech.isJunkResearch = true; }, @@ -3061,9 +3061,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return true + return !tech.isSuperDeterminism }, - requires: "", + requires: "not superdeterminism", effect() { tech.isBrainstorm = true tech.isBrainstormActive = false diff --git a/todo.txt b/todo.txt index 2d0622a..8ab7dbc 100644 --- a/todo.txt +++ b/todo.txt @@ -1,23 +1,19 @@ ******************************************************** NEXT PATCH ************************************************** -tech: ricochet - nails bounce off mobs and hit other mobs with extra damage per ricochet +mob: beetleBoss +mob: flutter -tech: dye laser - 20% efficiency and 20% damage -laser diode renamed infrared diode - 40 -> 50% efficiency but you can't see the laser beam -laser-bots acquire new targets much faster -iridescence 88 -> 100% damage, a tiny bit harder to hit center of mobs - stacks up to 3 -> 9 - -dynamic equilibrium scales damage with defense - goes up to 9x stacks -neutronium 25 -> 20% slower movement - -revolutionBoss laser swords are much slower and shorter - but they do more damage +balance: all mobs at every level are about 2%-3% harder to kill *********************************************************** TODO ***************************************************** +wings + put in mob as a method? + add parameter for ellipticity + give snakeBoss wings? + + + mob mechanics bullets hit player and stay attached for 4-5 seconds, slowing player hopperBullets?