From b8e7bf7d3d28e0a6a47820397c0295ab17f06c3f Mon Sep 17 00:00:00 2001 From: landgreen Date: Thu, 4 Aug 2022 08:55:15 -0700 Subject: [PATCH] elephant's toothpaste elephant's toothpaste: mines make foam sentry fires about 40% faster but each shot slightly reduces the total duration (duration = 17s - 1/10 s per shot) foam can move through blocks a bit faster laser reflection damage is increased about 15% -> 8% damage loss per reflection beetleBoss pushes player away and spawns baby flutter mobs fire rate affects block throwing charge rate --- js/bullet.js | 125 +++++++++++++++++++++++++++---------------------- js/level.js | 20 ++++---- js/mob.js | 2 +- js/player.js | 19 ++++++-- js/spawn.js | 128 +++++++++++++++++++++++++++++++++------------------ js/tech.js | 62 ++++++++++++++++--------- todo.txt | 21 +++++++-- 7 files changed, 237 insertions(+), 140 deletions(-) diff --git a/js/bullet.js b/js/bullet.js index 8ace739..bb826bc 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -1439,7 +1439,7 @@ const b = { minDmgSpeed: 4, lookFrequency: Math.floor(7 + Math.random() * 3), density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed - drain: tech.isRailEnergyGain ? 0.002 : 0.006, + drain: tech.isRailEnergy ? 0.002 : 0.006, beforeDmg(who) { if (tech.isShieldPierce && who.isShielded) { //disable shields who.isShielded = false @@ -1695,7 +1695,7 @@ const b = { friction: 1, frictionAir: 0.4, thrustMag: 0.1, - drain: tech.isRailEnergyGain ? 0.002 : 0.006, + drain: tech.isRailEnergy ? 0.002 : 0.006, turnRate: isReturn ? 0.1 : 0.03, //0.015 drawStringControlMagnitude: 3000 + 5000 * Math.random(), drawStringFlip: (Math.round(Math.random()) ? 1 : -1), @@ -2247,7 +2247,7 @@ const b = { x: where.x + 3000 * Math.cos(m.angle), y: where.y + 3000 * Math.sin(m.angle) }, dmg = tech.laserDamage, reflections = tech.laserReflections, isThickBeam = false, push = 1) { - const reflectivity = 1 - 1 / (reflections * 1.5) + const reflectivity = 1 - 1 / (reflections * 3) let damage = m.dmgScale * dmg let best = { x: 1, @@ -2528,10 +2528,56 @@ const b = { isArmed: false, endCycle: Infinity, lookFrequency: 0, - range: 700, + range: 700 - 300 * tech.isFoamMine, beforeDmg() {}, onEnd() { - if (this.isArmed) b.targetedNail(this.position, tech.isMineSentry ? 7 : 22, 40 + 10 * Math.random(), 1200, true, 2.2) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) { + if (tech.isFoamMine) { + for (let i = 0; i < 14; i++) { + const radius = 13 + 8 * Math.random() + const velocity = { x: 5.5 * Math.random(), y: 0 } + b.foam(this.position, Vector.rotate(velocity, this.angle + 1.57 + 3 * (Math.random() - 0.5)), radius) //6.28 * Math.random() + } + + let count = 0 + let cycle = () => { + if (count < 40) { + if (!simulation.paused && !simulation.isChoosing) { //!(simulation.cycle % 1) && + count++ + + const targets = [] //target nearby mobs + for (let i = 0, len = mob.length; i < len; i++) { + if ( + Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.range + mob[i].radius + 300 && + !mob[i].isBadTarget && //|| mob[i].isMobBullet + Matter.Query.ray(map, this.position, mob[i].position).length === 0 && + !mob[i].isInvulnerable + ) { + // targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, dist / 50))) //predict where the mob will be in a few cycles + targets.push(mob[i]) //predict where the mob will be in a few cycles + } + } + if (targets.length > 0) { // aim near a random target in array + const index = Math.floor(Math.random() * targets.length) //pick random target from list + const radius = 7 + 10 * Math.random() + const SPEED = 23 + 6 * Math.random() - radius * 0.3 + 0.5 * targets[index].speed + const predict = Vector.mult(targets[index].velocity, Vector.magnitude(Vector.sub(this.position, targets[index].position)) / 60) + const where = Vector.add(targets[index].position, predict) + const velocity = Vector.mult(Vector.normalise(Vector.sub(where, this.position)), SPEED) + b.foam(this.position, Vector.rotate(velocity, 0.2 * (Math.random() - 0.5)), radius) + } else { + const radius = 7 + 10 * Math.random() + const velocity = { x: 10 + 8 * Math.random(), y: 0 } + b.foam(this.position, Vector.rotate(velocity, this.angle + 1.57 + 2.8 * (Math.random() - 0.5)), radius) //6.28 * Math.random() + } + } + requestAnimationFrame(cycle); + } + } + requestAnimationFrame(cycle) + + } else if (this.isArmed && !tech.isMineSentry) { + b.targetedNail(this.position, tech.isMineSentry ? 7 : 22, 40 + 10 * Math.random(), 1200, true, 2.2) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) { + } }, do() { this.force.y += this.mass * 0.002; //extra gravity @@ -2556,14 +2602,13 @@ const b = { this.arm(); //sometimes the mine can't attach to map and it just needs to be reset - const that = this - setTimeout(function() { - if (Matter.Query.collides(that, map).length === 0 || Matter.Query.point(map, that.position).length > 0) { - that.endCycle = 0 // if not touching map explode - that.isArmed = false - b.mine(that.position, that.velocity, that.angle) + setTimeout(() => { + if (Matter.Query.collides(this, map).length === 0 || Matter.Query.point(map, this.position).length > 0) { + this.endCycle = 0 // if not touching map explode + this.isArmed = false + b.mine(this.position, this.velocity, this.angle) } - }, 100, that); + }, 100); break } //move until you are touching the wall @@ -2599,17 +2644,18 @@ const b = { for (let i = 0, len = mob.length; i < len; ++i) { if ( !mob[i].isBadTarget && - Vector.magnitude(Vector.sub(this.position, mob[i].position)) < 700 + mob[i].radius + random && + Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.range + mob[i].radius + random && Matter.Query.ray(map, this.position, mob[i].position).length === 0 && Matter.Query.ray(body, this.position, mob[i].position).length === 0 ) { - if (tech.isStun) b.AoEStunEffect(this.position, 700 + mob[i].radius + random); //AoEStunEffect(where, range, cycles = 90 + 60 * Math.random()) { + if (tech.isStun) b.AoEStunEffect(this.position, this.range + mob[i].radius + random); //AoEStunEffect(where, range, cycles = 90 + 60 * Math.random()) { if (tech.isMineSentry) { - this.lookFrequency = 8 + Math.floor(3 * Math.random()) + this.lookFrequency = 6 this.endCycle = simulation.cycle + 1020 this.do = function() { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (!(simulation.cycle % this.lookFrequency)) { //find mob targets + this.endCycle -= 5 b.targetedNail(this.position, 1, 45 + 5 * Math.random(), 1100, false, 2.3) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) { if (!(simulation.cycle % (this.lookFrequency * 6))) { simulation.drawList.push({ @@ -3734,9 +3780,9 @@ const b = { Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.target.velocity), this.target.position)) } if (this.target.isBoss) { - if (this.target.speed > 7.5) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.98)) + if (this.target.speed > 6.5) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.975)) } else { - if (this.target.speed > 3.5) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.95)) + if (this.target.speed > 2.5) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.94)) } Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9); @@ -3746,35 +3792,6 @@ const b = { const SCALE = 1 - 0.004 / tech.isBulletsLastLonger //shrink if mob is shielded Matter.Body.scale(this, SCALE, SCALE); this.radius *= SCALE; - - // if (true && !(simulation.cycle % 20)) { - // let electricity = (who) => { - // who.damage(2 * m.dmgScale, true) - // const unit = Vector.normalise(Vector.sub(this.position, who.position)) - // //draw electricity - // const step = 80 - // ctx.beginPath(); - // let x = this.position.x - 20 * unit.x; - // let y = this.position.y - 20 * unit.y; - // ctx.moveTo(x, y); - // for (let i = 0; i < 3; i++) { - // x += step * (-unit.x + 1.5 * (Math.random() - 0.5)) - // y += step * (-unit.y + 1.5 * (Math.random() - 0.5)) - // ctx.lineTo(x, y); - // } - // ctx.lineWidth = 3; - // ctx.strokeStyle = "#f0f"; - // ctx.stroke(); - // } - - // //find mobs that are close - // for (let i = 0, len = mob.length; i < len; ++i) { - // if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) - mob[i].radius < 5000 && !mob[i].isBadTarget) { - // electricity(mob[0]) - // } - // } - // } - } else { this.target.damage(m.dmgScale * this.damage); } @@ -3808,23 +3825,23 @@ const b = { } } this.target = null - } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map or blocks - const slow = 0.85 + } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map + const slow = 0.87 Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow }); - const SCALE = 0.96 + const SCALE = 0.97 Matter.Body.scale(this, SCALE, SCALE); this.radius *= SCALE; // } else if (Matter.Query.collides(this, body).length > 0) { - } else if (Matter.Query.point(body, this.position).length > 0) { - const slow = 0.9 + } else if (Matter.Query.point(body, this.position).length > 0) { //slow when touching blocks + const slow = 0.94 Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow }); - const SCALE = 0.96 + const SCALE = 0.99 Matter.Body.scale(this, SCALE, SCALE); this.radius *= SCALE; } else { @@ -6617,7 +6634,7 @@ const b = { charge: 0, railDo() { if (this.charge > 0) { - const DRAIN = (tech.isRailEnergyGain ? 0.0005 : 0.002) + const DRAIN = (tech.isRailEnergy ? 0.0005 : 0.002) //exit railgun charging without firing if (m.energy < DRAIN) { // m.energy += 0.025 + this.charge * 22 * this.drain @@ -6756,7 +6773,7 @@ const b = { this.charge = this.charge * smoothRate + 1 - smoothRate if (m.energy > DRAIN) m.energy -= DRAIN - // m.energy += (this.charge - previousCharge) * ((tech.isRailEnergyGain ? 0.5 : -0.3)) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen + // m.energy += (this.charge - previousCharge) * ((tech.isRailEnergy ? 0.5 : -0.3)) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen //draw magnetic field const X = m.pos.x diff --git a/js/level.js b/js/level.js index dd46a4b..246c79d 100644 --- a/js/level.js +++ b/js/level.js @@ -16,20 +16,20 @@ 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(2 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(9 * 4) //30 is near max on hard //60 is near max on why // simulation.isHorizontalFlipped = true // m.maxHealth = m.health = 100 + // tech.isRerollDamage = true // powerUps.research.changeRerolls(100000) // m.immuneCycle = Infinity //you can't take damage - // powerUps.research.changeRerolls(100) // tech.tech[297].frequency = 100 // b.guns[0].ammo = 10000 - // m.setField("time dilation") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass - // b.giveGuns("shotgun") //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"); - // tech.giveTech("pulse") + // m.setField("perfect diamagnetism") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass + // b.giveGuns("mine") //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("sentry"); + // tech.giveTech("laser-mines"); + // tech.giveTech("elephant's toothpaste") // for (let i = 0; i < 1; ++i) tech.giveTech("slow light") // for (let i = 0; i < 1; ++i) tech.giveTech("free-electron laser") // m.damage(0.1); @@ -37,8 +37,8 @@ const level = { // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research"); + // spawn.flutter(1900, -500, 10) // spawn.starter(1900, -500, 200) - // spawn.starter(1900, -500, 50) // spawn.dragonFlyBoss(1900, -400) // spawn.beetleBoss(1900, -400) // for (let i = 0; i < 2; ++i) spawn.flutter(1900 + 300 * Math.random(), -500 + 300 * Math.random()) @@ -4586,7 +4586,7 @@ const level = { spawn.randomMob(3600, 1725, 0.9); spawn.randomMob(4100, 1225, 0.9); spawn.randomMob(2825, 400, 0.9); - if (simulation.difficulty > 1) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "blinkBoss", "streamBoss", "historyBoss", "orbitalBoss", "grenadierBoss", "blockBoss", "revolutionBoss", "slashBoss"]); + if (simulation.difficulty > 1) spawn.randomLevelBoss(6000, 2300, ["dragonFlyBoss", "beetleBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "blinkBoss", "streamBoss", "historyBoss", "orbitalBoss", "grenadierBoss", "blockBoss", "revolutionBoss", "slashBoss"]); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(7725, 2275) @@ -5144,7 +5144,7 @@ const level = { spawn.randomMob(3975, -3900, 0.5); spawn.randomMob(1725, 125, 0.5); if (simulation.difficulty > 1) { - if (Math.random() < 0.33) { + if (Math.random() < 0.5) { spawn.randomLevelBoss(4250, -250); spawn.debris(-250, 50, 1650, 2); //16 debris per level spawn.debris(2475, 0, 750, 2); //16 debris per level diff --git a/js/mob.js b/js/mob.js index 3e6a57e..aa51a78 100644 --- a/js/mob.js +++ b/js/mob.js @@ -589,7 +589,7 @@ const mobs = { ctx.setLineDash([]); } }, - wing(a, radius = 250, ellipticity = 0.4, dmg = 0.0004) { + wing(a, radius = 250, ellipticity = 0.4, dmg = 0.0006) { 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)) diff --git a/js/player.js b/js/player.js index 63a4665..fd05fc8 100644 --- a/js/player.js +++ b/js/player.js @@ -1124,9 +1124,9 @@ const m = { if (m.energy > 0.001) { if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle if (tech.isCapacitor && m.throwCharge < 4) m.throwCharge = 4 - m.throwCharge += 0.5 / m.holdingTarget.mass + m.throwCharge += 0.5 / m.holdingTarget.mass / b.fireCDscale - if (m.throwCharge < 6) m.energy -= 0.001; // m.throwCharge caps at 5 + if (m.throwCharge < 6) m.energy -= 0.001 / b.fireCDscale; // m.throwCharge caps at 5 //trajectory path prediction if (tech.isTokamak) { @@ -2073,10 +2073,19 @@ const m = { } } } else if (simulation.molecularMode === 1) { - m.energy -= 0.35; - b.missile({ x: m.pos.x, y: m.pos.y - 40 }, -Math.PI / 2 + 0.5 * (Math.random() - 0.5), 0, 1) + m.energy -= 0.33; + const direction = { + x: Math.cos(m.angle), + y: Math.sin(m.angle) + } + const push = Vector.mult(Vector.perp(direction), 0.08) + b.missile({ x: m.pos.x + 30 * direction.x, y: m.pos.y + 30 * direction.y }, m.angle, -15) + bullet[bullet.length - 1].force.x += push.x * (Math.random() - 0.5) + bullet[bullet.length - 1].force.y += 0.005 + push.y * (Math.random() - 0.5) + + // b.missile({ x: m.pos.x, y: m.pos.y - 40 }, -Math.PI / 2 + 0.5 * (Math.random() - 0.5), 0, 1) } else if (simulation.molecularMode === 2) { - m.energy -= 0.05; + m.energy -= 0.045; b.iceIX(1) } else if (simulation.molecularMode === 3) { if (tech.isDroneRadioactive) { diff --git a/js/spawn.js b/js/spawn.js index e7a2572..ecfa377 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1614,7 +1614,7 @@ const spawn = { // me.isBadTarget = true; me.isMobBullet = true; me.showHealthBar = false; - me.timeLeft = 1500 + Math.floor(600 * Math.random()); + me.timeLeft = 1200 + Math.floor(600 * Math.random()); me.isRandomMove = Math.random() < 0.3 //most chase player, some don't me.accelMag = 0.01; //jump height @@ -1649,7 +1649,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.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0.06 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.accelMag = 0.05; //jump height me.g = 0.003; //required if using this.gravity me.frictionAir = 0.01; @@ -2696,12 +2696,12 @@ const spawn = { mobs.spawn(x, y, 7, radius, '#16576b'); let me = mob[mob.length - 1]; me.isBoss = true; - Matter.Body.setDensity(me, 0.0016); //extra dense //normal is 0.001 //makes effective life much larger + 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.accelMag = 0.0006 + 0.0007 * Math.sqrt(simulation.accelScale); me.frictionAir = 0.05; // me.seePlayerFreq = 40 + Math.floor(13 * Math.random()) me.memory = 240; @@ -2714,7 +2714,7 @@ const spawn = { // me.onDeath = function() {}; me.flapRate = 0.3 + Math.floor(3 * Math.random()) / 10 + 100 * me.accelMag - me.flapRadius = 75 + 50 * Math.random() + radius * 2 + me.flapRadius = 75 + radius * 3 me.do = function() { this.seePlayerByHistory() this.checkStatus(); @@ -2753,7 +2753,7 @@ const spawn = { } }; }, - beetleBoss(x, y, radius = 60) { + beetleBoss(x, y, radius = 50) { mobs.spawn(x, y, 7, radius, '#16576b'); let me = mob[mob.length - 1]; me.isBoss = true; @@ -2764,14 +2764,14 @@ const spawn = { me.nextHealthThreshold = 0.75 me.invulnerableCount = 0 - me.flapRate = 0.25 + me.flapRate = 0.2 me.wingSize = 0 - me.wingGoal = 250 + me.wingGoal = 250 + simulation.difficulty 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.0005 + 0.0005 * Math.sqrt(simulation.accelScale); + me.accelMag = 0.00045 + 0.0005 * Math.sqrt(simulation.accelScale); me.frictionAir = 0.05; - me.seePlayerFreq = 30 + me.seePlayerFreq = 20 me.memory = 420; me.restitution = 1; me.frictionStatic = 0; @@ -2789,58 +2789,94 @@ const spawn = { // } // } - if (Math.random() < 0.3) { - const len = 0.1 * simulation.difficulty //spawn some baby flutters + // if (Math.random() < 0.3) { + // const len = 0.1 * simulation.difficulty //spawn some baby flutters + // let i = 0 + // let spawnFlutters = () => { + // if (i < len) { + // if (!(simulation.cycle % 30) && !simulation.paused && !simulation.isChoosing) { + // 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) + // i++ + // } + // requestAnimationFrame(spawnFlutters); + // } + // } + // requestAnimationFrame(spawnFlutters); + // me.isAlreadyHadBabies = true + // } + + me.pushAway = function(magX = 0.13, magY = 0.05) { + for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally + if (Vector.magnitudeSquared(Vector.sub(body[i].position, this.position)) < 4000000) { //2000 + body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1) + body[i].force.y -= magY * body[i].mass + } + } + for (let i = 0, len = bullet.length; i < len; ++i) { //push blocks away horizontally + if (Vector.magnitudeSquared(Vector.sub(bullet[i].position, this.position)) < 4000000) { //2000 + bullet[i].force.x += magX * bullet[i].mass * (bullet[i].position.x > this.position.x ? 1 : -1) + bullet[i].force.y -= magY * bullet[i].mass + } + } + for (let i = 0, len = powerUp.length; i < len; ++i) { //push blocks away horizontally + if (Vector.magnitudeSquared(Vector.sub(powerUp[i].position, this.position)) < 4000000) { //2000 + powerUp[i].force.x += magX * powerUp[i].mass * (powerUp[i].position.x > this.position.x ? 1 : -1) + powerUp[i].force.y -= magY * powerUp[i].mass + } + } + if (Vector.magnitudeSquared(Vector.sub(player.position, this.position)) < 4000000) { //2000 + player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1) + player.force.y -= magY * player.mass + } + } + + me.babies = function(len) { + const delay = Math.max(3, Math.floor(15 - len / 2)) let i = 0 let spawnFlutters = () => { if (i < len) { - if (!(simulation.cycle % 30) && !simulation.paused && !simulation.isChoosing) { - 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) + if (!(simulation.cycle % delay) && !simulation.paused && !simulation.isChoosing) { + // 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)) + const unit = Vector.normalise(Vector.sub(player.position, this.position)) + const velocity = Vector.mult(unit, 10 + 10 * Math.random()) + const where = Vector.add(this.position, Vector.mult(unit, radius * 1.2)) + spawn.allowShields = false + spawn.flutter(where.x, where.y, Math.floor(7 + 8 * Math.random())) + const who = mob[mob.length - 1] + Matter.Body.setDensity(who, 0.01); //extra dense //normal is 0.001 //makes effective life much larger + Matter.Body.setVelocity(who, velocity); + Matter.Body.setAngle(who, Math.atan2(velocity.y, velocity.x)) + + this.alertNearByMobs(); + spawn.allowShields = true i++ } requestAnimationFrame(spawnFlutters); } } requestAnimationFrame(spawnFlutters); - me.isAlreadyHadBabies = true } - - + // me.babies(0.05 * simulation.difficulty + 1) me.onDeath = function() { powerUps.spawnBossPowerUp(this.position.x, this.position.y) - - const len = 0.1 * simulation.difficulty //spawn some baby flutters - if (len > 3 && !this.isAlreadyHadBabies) { - let i = 0 - let spawnFlutters = () => { - if (i < len) { - if (!(simulation.cycle % 20) && !simulation.paused && !simulation.isChoosing) { - 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) - i++ - } - requestAnimationFrame(spawnFlutters); - } - } - requestAnimationFrame(spawnFlutters); - } + me.babies(0.05 * simulation.difficulty + 1) }; me.onDamage = function() { - if (this.health < this.nextHealthThreshold) { + if (this.health < this.nextHealthThreshold && this.alive) { this.health = this.nextHealthThreshold - 0.01 this.nextHealthThreshold = Math.floor(this.health * 4) / 4 - this.invulnerableCount = 180 + Math.floor(60 * Math.random()) + this.invulnerableCount = 90 + Math.floor(30 * Math.random()) this.isInvulnerable = true this.damageReduction = 0 this.frictionAir = 0 this.wingGoal = 0 this.wingSize = 0 - this.flapRate += 0.1 - this.accelMag *= 1.25 + this.flapRate += 0.13 + this.accelMag *= 1.4 } }; me.do = function() { @@ -2853,6 +2889,8 @@ const spawn = { this.damageReduction = this.startingDamageReduction this.frictionAir = 0.05 this.wingGoal = 250 + this.pushAway(Math.sqrt(this.flapRate) * 0.13, Math.sqrt(this.flapRate) * 0.06) //this.flapRate = 0.2, +0.13x3 -> 0.6 + me.babies(0.05 * simulation.difficulty + 1) } // //draw wings as if they are protecting // const wingShield = (a, size) => { @@ -2908,10 +2946,10 @@ const spawn = { this.torque -= turn; } const flapArc = 0.7 //don't go past 1.57 for normal flaps - this.wingSize = 0.98 * this.wingSize + 0.02 * this.wingGoal + this.wingSize = 0.97 * this.wingSize + 0.03 * this.wingGoal 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 * this.flapRate), this.wingSize, 0.5, 0.0008) - this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0008) + this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0012) + this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0012) } else { this.wingSize = 0.96 * this.wingSize + 0 //shrink while stunned } @@ -4175,7 +4213,7 @@ const spawn = { me.isMobBullet = true; me.isUnstable = true; //dies when blocked me.showHealthBar = false; - me.explodeRange = 200 + 150 * Math.random() + me.explodeRange = 210 + 140 * Math.random() me.isExploding = false me.countDown = Math.ceil(4 * Math.random()) me.isInvulnerable = true //not actually invulnerable, just prevents block + ice-9 interaction @@ -4199,7 +4237,7 @@ const spawn = { this.death(); //hit player if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange && m.immuneCycle < m.cycle) { - m.damage(0.01 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1)); + m.damage(0.015 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1)); m.energy -= 0.15 * (tech.isRadioactiveResistance ? 0.25 : 1) if (m.energy < 0) m.energy = 0 } diff --git a/js/tech.js b/js/tech.js index f55feb3..afaf4c9 100644 --- a/js/tech.js +++ b/js/tech.js @@ -498,7 +498,7 @@ const tech = { for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun"); }, remove() { - tech.isGunCycle = false; + if (!this.count) tech.isGunCycle = false; // only set to false if you don't have this tech // if (tech.isGunCycle) { // for (let i = 0; i < 8; i++) { // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun @@ -3880,7 +3880,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isLaserMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 + return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 }, requires: "nails, nail gun, rivets, shotgun", effect() { @@ -3900,7 +3900,7 @@ const tech = { frequencyDefault: 2, allowed() { // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines")) - return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !tech.isLaserMine) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot)) + return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot)) }, // requires: "nail gun, not rotary cannon, rivets, or needles", @@ -4052,7 +4052,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !tech.isLaserMine) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot)) + return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot)) }, requires: "nail gun, nails, rivets, mine, not ceramic needles", effect() { @@ -4065,7 +4065,7 @@ const tech = { { name: "6s half-life", link: `6s half-life`, - description: "nails are made of plutonium-238
+100% damage over 6 seconds", + description: "nails, needles, rivets are made of plutonium-238
radioactive damage lasts +3 seconds", isGunTech: true, maxCount: 1, count: 0, @@ -4085,7 +4085,7 @@ const tech = { { name: "1s half-life", link: `1s half-life`, - description: "nails are made of lithium-8
damage occurs after 1 second", + description: "nails, needles, rivets are made of lithium-8
+300% radioactive damage for 1 second
", isGunTech: true, maxCount: 1, count: 0, @@ -5144,6 +5144,25 @@ const tech = { } } }, + { + name: "elephant's toothpaste", + description: "mines catalyze a reaction
that yields foam bubbles", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.haveGunCheck("mine") && !tech.isMineSentry + }, + requires: "mines, not sentry", + effect() { + tech.isFoamMine = true; + }, + remove() { + tech.isFoamMine = false; + } + }, { name: "laser-mines", link: `laser-mines`, @@ -5173,9 +5192,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("mine") + return tech.haveGunCheck("mine") && !tech.isFoamMine }, - requires: "mines", + requires: "mines, not elephant's toothpaste", effect() { tech.isMineSentry = true; }, @@ -5285,7 +5304,7 @@ const tech = { }, { name: "siphonaptera", - description: "shotgun and sporangium hatch fleas", //
spore tech applies to fleas + description: "sporangium and shotgun hatch fleas", //
spore tech applies to fleas isGunTech: true, maxCount: 1, count: 0, @@ -5621,7 +5640,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return !tech.isBulletTeleport && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall) + return !tech.isBulletTeleport && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine) }, requires: "foam, not uncertainty", effect() { @@ -5640,7 +5659,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (!tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall)) || (tech.haveGunCheck("matter wave") && !tech.isLongitudinal) + return (!tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)) || (tech.haveGunCheck("matter wave") && !tech.isLongitudinal) }, requires: "foam, matter wave, not electrostatic induction, not phonon", effect() { @@ -5659,7 +5678,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea + return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine }, requires: "foam, worms", effect() { @@ -5678,7 +5697,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall + return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine }, requires: "foam", effect() { @@ -5699,7 +5718,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall + return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine }, requires: "foam", effect() { @@ -5882,7 +5901,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isGrapple && !tech.isRailEnergyGain + return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy }, requires: "grappling hook, not alternator", effect() { @@ -5905,10 +5924,10 @@ const tech = { }, requires: "harpoon, not bulk modulus", effect() { - tech.isRailEnergyGain = true; + tech.isRailEnergy = true; }, remove() { - tech.isRailEnergyGain = false; + tech.isRailEnergy = false; } }, { @@ -6170,7 +6189,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isLaserLens + return tech.haveGunCheck("laser") && tech.isLaserLens }, requires: "lens", effect() { @@ -6259,7 +6278,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isWideLaser + return tech.haveGunCheck("laser") && tech.isWideLaser }, requires: "laser gun, diffuse beam", effect() { @@ -6648,7 +6667,7 @@ const tech = { }, { name: "dynamic equilibrium", - descriptionFunction() { return `increase damage by your defense times
5% of your last ${tech.isEnergyHealth ? "energy" : "health"} loss   (+${(100*tech.lastHitDamage * m.lastHit * (2 - m.harmReduction())).toFixed(0)}% damage)` }, // = +${10*m.harmReduction()}% + descriptionFunction() { return `increase damage by your defense and
5% of your last ${tech.isEnergyHealth ? "energy" : "health"} loss   (+${(100*tech.lastHitDamage * m.lastHit * (2 - m.harmReduction())).toFixed(0)}% damage)` }, // = +${10*m.harmReduction()}% // descriptionFunction() { return `increase damage by your last ${tech.isEnergyHealth ? "energy" : "health"} loss
(${(tech.lastHitDamage).toFixed(0)}%)(${(100*m.lastHit).toFixed(0)} ${tech.isEnergyHealth ? "energy" : "health"})(${2 - m.harmReduction()} defense) = ${(100*tech.lastHitDamage * m.lastHit * (2 - m.harmReduction())).toFixed(0)}% damage ` }, // = +${10*m.harmReduction()}% isFieldTech: true, maxCount: 9, @@ -10335,7 +10354,7 @@ const tech = { isPulseLaser: null, isRadioactive: null, radioactiveDamage: null, - isRailEnergyGain: null, + isRailEnergy: null, isMineSentry: null, isIncendiary: null, overfillDrain: null, @@ -10360,6 +10379,7 @@ const tech = { isMissileBig: null, isMissileBiggest: null, isLaserMine: null, + isFoamMine: null, isAmmoFoamSize: null, isIceIX: null, isDupDamage: null, diff --git a/todo.txt b/todo.txt index 1d32582..e719017 100644 --- a/todo.txt +++ b/todo.txt @@ -1,14 +1,27 @@ ******************************************************** NEXT PATCH ************************************************** -snakeBoss is now dragonFlyBoss - snakeSpitBoss till exists, don't worry +elephant's toothpaste: mines make foam -flutter and beetle mobs changes +sentry fires about 40% faster + but each shot slightly reduces the total duration + (duration = 17s - 1/10 s per shot) -Noether violation has 50% less forward recoil for shotgun +foam can move through blocks a bit faster +laser reflection damage is increased + about 15% -> 8% damage loss per reflection +beetleBoss pushes player away and spawns baby flutter mobs +fire rate affects block throwing charge rate *********************************************************** TODO ***************************************************** +bug blocks and power ups falling through map + always foam gun (4-5 times) + might be about tech pressure vessel + happens rarely, doesn't repeat + normally after level 6 + +seed isn't working right from shared URL + mob mechanics bullets hit player and stay attached for 4-5 seconds, slowing player hopperBullets?