From a7ad085deb0bc8fc0ffe7339e6d32e297ec0910d Mon Sep 17 00:00:00 2001 From: landgreen Date: Thu, 7 May 2020 04:52:38 -0700 Subject: [PATCH] neutron bomb acute stress mod removes 1/3 (was 1/2) of your energy zoom works with i and o now cell boss has double the chance to spilt on damage. After it splits, each daughter cell has the mother's reduced health new gun neutron bomb, persistent AoE damage (might still have issues sticking to objects properly) new mob neutron bomb stuns mobs --- index.html | 2 +- js/bullets.js | 267 ++++++++++++++++++++++++++++++++++++-------------- js/game.js | 4 +- js/level.js | 10 +- js/mobs.js | 5 +- js/player.js | 2 +- js/spawn.js | 29 +++++- todo.txt | 26 ++++- 8 files changed, 254 insertions(+), 91 deletions(-) diff --git a/index.html b/index.html index a8c08a6..e9d2bb7 100644 --- a/index.html +++ b/index.html @@ -149,7 +149,7 @@ ZOOM - + / - + - / + or i / o PAUSE diff --git a/js/bullets.js b/js/bullets.js index 87068b9..ae58008 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -86,6 +86,7 @@ const b = { isModHarmReduce: null, modNailsDeathMob: null, isModSlowFPS: null, + isModNeutronStun: null, modOnHealthChange() { //used with acid mod if (b.isModAcidDmg && mech.health > 0.8) { b.modAcidDmg = 0.5 @@ -237,7 +238,7 @@ const b = { }, { name: "acute stress response", - description: "increase damage by 33%
but, after a mob dies lose 1/2 your energy", + description: "increase damage by 33%
but, after a mob dies lose 1/3 your energy", maxCount: 1, count: 0, allowed() { @@ -885,6 +886,22 @@ const b = { //nothing to undo } }, + { + name: "Lorentzian topology", + description: "your bullets last +33% longer", + maxCount: 3, + count: 0, + allowed() { + return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" || b.haveGunCheck("spores") || b.haveGunCheck("drones") || b.haveGunCheck("super balls") || b.haveGunCheck("foam") || b.haveGunCheck("wave beam") || b.haveGunCheck("ice IX") || b.haveGunCheck("neutron bomb") + }, + requires: "drones, spores, super balls, foam
wave beam, ice IX, neutron bomb", + effect() { + b.isModBulletsLastLonger += 0.33 + }, + remove() { + b.isModBulletsLastLonger = 1; + } + }, { name: "depleted uranium rounds", description: `your bullets are +16% larger
increased mass and physical damage`, @@ -1212,6 +1229,22 @@ const b = { b.isModVacuumShield = false; } }, + { + name: "inertial confinement", + description: "neutron bomb's initial detonation
stuns nearby mobs for +1 seconds", + maxCount: 3, + count: 0, + allowed() { + return b.haveGunCheck("neutron bomb") + }, + requires: "neutron bomb", + effect() { + b.isModNeutronStun += 60; + }, + remove() { + b.isModNeutronStun = 0; + } + }, { name: "mine reclamation", description: "retrieve ammo from all undetonated mines
and 20% of mines after detonation", @@ -1276,22 +1309,6 @@ const b = { b.isModSporeFollow = false } }, - { - name: "Lorentzian topology", - description: "your bullets last +33% longer", - maxCount: 3, - count: 0, - allowed() { - return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" || b.haveGunCheck("spores") || b.haveGunCheck("drones") || b.haveGunCheck("super balls") || b.haveGunCheck("foam") || b.haveGunCheck("wave beam") || b.haveGunCheck("ice IX") - }, - requires: "drones, spores, super balls,
foam, wave beam, or ice IX", - effect() { - b.isModBulletsLastLonger += 0.33 - }, - remove() { - b.isModBulletsLastLonger = 1; - } - }, { name: "redundant systems", description: "drone collisions no longer reduce their lifespan", @@ -3260,109 +3277,213 @@ const b = { }, { name: "neutron bomb", - description: "fire a bomb that emits neutron radiation
detonation occurs after any collision", + description: "toss a chunk of Cf-252 that emits neutrons
damages and drains energy in area of effect", ammo: 0, - ammoPack: 4, + ammoPack: 6, have: false, isStarterGun: false, isEasyToAim: true, fire() { const me = bullet.length; const dir = mech.angle; - bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 10, 6, b.fireAttributes(dir, false)); - b.fireProps(mech.crouch ? 30 : 20, mech.crouch ? 28 : 14, dir, me); //cd , speed + bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 10, 4, b.fireAttributes(dir, false)); + b.fireProps(mech.crouch ? 30 : 15, mech.crouch ? 28 : 18, dir, me); //cd , speed Matter.Body.setDensity(bullet[me], 0.000001); bullet[me].endCycle = Infinity; bullet[me].frictionAir = 0; - bullet[me].friction = 0.5; + bullet[me].friction = 1; + bullet[me].frictionStatic = 1; bullet[me].restitution = 0; bullet[me].minDmgSpeed = 0; bullet[me].damageRadius = 100; - bullet[me].maxDamageRadius = 600 + bullet[me].maxDamageRadius = 450 + 150 * Math.random() + bullet[me].stuckTo = null; + bullet[me].stuckToRelativePosition = null; bullet[me].onDmg = function () {}; - + bullet[me].stuck = function () {}; bullet[me].do = function () { - this.force.y += this.mass * 0.001; - if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length || Matter.Query.collides(this, mob).length) { - //have the bullet stick to mobs and blocks? - //stun mobs in range - // for (let i = 0, len = mob.length; i < len; i++) { - // const dx = this.position.x - mob[i].position.x; - // const dy = this.position.y - mob[i].position.y; - // if (dx * dx + dy * dy < this.maxDamageRadius * this.maxDamageRadius) { - // mobs.statusStun(mob[i], 60) - // } - // } - - //push away blocks when firing - for (let i = 0, len = body.length; i < len; ++i) { - const SUB = Vector.sub(body[i].position, this.position) - const DISTANCE = Vector.magnitude(SUB) - if (DISTANCE < this.maxDamageRadius) { - const FORCE = Vector.mult(Vector.normalise(SUB), 0.01 * body[i].mass) - body[i].force.x += FORCE.x; - body[i].force.y += FORCE.y - body[i].mass * (game.g * 2); //kick up a bit to give them some arc - } - } - //stun mobs, but don't push away - for (let i = 0, len = mob.length; i < len; ++i) { - if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.maxDamageRadius) { - mobs.statusStun(mob[i], 60) - } - } - - //use a constraint? - Matter.Sleeping.set(this, true) //freeze in place - this.collisionFilter.mask = 0; - Matter.Body.setVelocity(this, { + function onCollide(that) { + that.collisionFilter.mask = 0; //non collide with everything + Matter.Body.setVelocity(that, { x: 0, y: 0 }); - const SCALE = 0.01 - Matter.Body.scale(this, SCALE, SCALE); - this.do = this.radiationMode; + // that.frictionAir = 1; + that.do = that.radiationMode; + + if (b.isModNeutronStun) { + //push blocks + const dist = that.maxDamageRadius * 0.9 + for (let i = 0, len = body.length; i < len; ++i) { + const SUB = Vector.sub(body[i].position, that.position) + const DISTANCE = Vector.magnitude(SUB) + if (DISTANCE < dist) { + const FORCE = Vector.mult(Vector.normalise(SUB), 0.04 * body[i].mass) + body[i].force.x += FORCE.x; + body[i].force.y += FORCE.y - body[i].mass * game.g * 5; //kick up a bit to give them some arc + } + } + //stun mobs + for (let i = 0, len = mob.length; i < len; ++i) { + if (Vector.magnitude(Vector.sub(mob[i].position, that.position)) < dist) { + mobs.statusStun(mob[i], b.isModNeutronStun) + } + } + } } + + + const mobCollisions = Matter.Query.collides(this, mob) + if (mobCollisions.length) { + onCollide(this) + this.stuckTo = mobCollisions[0].bodyA + + if (this.stuckTo.isVerticesChange) { + this.stuckToRelativePosition = { + x: 0, + y: 0 + } + } else { + //find the relative position for when the mob is at angle zero by undoing the mobs rotation + this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle) + } + this.stuck = function () { + if (this.stuckTo && this.stuckTo.alive) { + const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector + Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) + Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck + } else { + this.collisionFilter.mask = cat.map; //non collide with everything but map + this.stuck = function () { + this.force.y += this.mass * 0.001; + } + } + } + } else { + const bodyCollisions = Matter.Query.collides(this, body) + if (bodyCollisions.length) { + onCollide(this) + this.stuckTo = bodyCollisions[0].bodyA + //find the relative position for when the mob is at angle zero by undoing the mobs rotation + this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle) + this.stuck = function () { + if (this.stuckTo) { + const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector + Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) + // Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck + } + } + } else { + if (Matter.Query.collides(this, map).length) { + onCollide(this) + + // this.stuck = function () { + // Matter.Body.setVelocity(this, { + // x: 0, + // y: 0 + // }); + // } + } else { //if colliding with nothing just fall + this.force.y += this.mass * 0.001; + } + } + } + + + + // if (Matter.Query.collides(this, map).length || bodyCollisions.length || mobCollisions.length) { + // if (mobCollisions.length) { + // this.isStuck = true; + // this.stuckTo = mobCollisions[0].bodyA + // this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), this.stuckTo.angle) + // } else if (bodyCollisions.length) { + // this.isStuck = true; + // this.stuckTo = bodyCollisions[0].bodyA + // this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), this.stuckTo.angle) + // } + + // if (b.isModNeutronStun) { + // //push blocks + // const dist = this.maxDamageRadius * 0.9 + // for (let i = 0, len = body.length; i < len; ++i) { + // const SUB = Vector.sub(body[i].position, this.position) + // const DISTANCE = Vector.magnitude(SUB) + // if (DISTANCE < dist) { + // const FORCE = Vector.mult(Vector.normalise(SUB), 0.04 * body[i].mass) + // body[i].force.x += FORCE.x; + // body[i].force.y += FORCE.y - body[i].mass * game.g * 5; //kick up a bit to give them some arc + // } + // } + // //stun mobs + // for (let i = 0, len = mob.length; i < len; ++i) { + // if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < dist) { + // mobs.statusStun(mob[i], b.isModNeutronStun) + // } + // } + // } + + // this.collisionFilter.mask = cat.map; //non collide with everything + // Matter.Body.setVelocity(this, { + // x: 0, + // y: 0 + // }); + // // this.frictionAir = 1; + // this.do = this.radiationMode; + // } else { + // this.force.y += this.mass * 0.001; + // } }; bullet[me].radiationMode = function () { - // if (this.endCycle - 360 < game.cycle) { - // this.damageRadius = this.damageRadius * 0.992 - // } else { - // this.damageRadius = this.damageRadius * 0.98 + 0.02 * this.maxDamageRadius - // this.damageRadius = Math.max(0, this.damageRadius + 2 * (Math.random() - 0.5)) + this.stuck(); //runs different code based on what the bullet is stuck to + // if (this.isStuck) { + // if (this.stuckTo.alive || this.stuckTo.classType === "body") { + // const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) + // Matter.Body.setPosition(this, Vector.add(rotate, this.stuckTo.position)) + // // Matter.Body.setPosition(this, Vector.add(this.stuckToRelativePosition, this.stuckTo.position)) + // Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck + // } else { + // this.isStuck = false; + // // this.force.y += this.mass * 0.5; + // } // } + if (!mech.isBodiesAsleep) { - this.damageRadius = this.damageRadius * 0.9 + 0.1 * this.maxDamageRadius //smooth radius towards max - this.maxDamageRadius = this.maxDamageRadius * 0.999 - 0.7 //slowly shrink max radius + this.damageRadius = this.damageRadius * 0.85 + 0.15 * this.maxDamageRadius //smooth radius towards max + this.maxDamageRadius -= 0.8 / b.isModBulletsLastLonger //+ 0.5 * Math.sin(game.cycle * 0.1) //slowly shrink max radius } if (this.damageRadius < 15) { this.endCycle = 0; } else { //aoe damage to player if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) { - const DRAIN = 0.003 + const DRAIN = 0.0015 if (mech.energy > DRAIN) { mech.energy -= DRAIN } else { mech.energy = 0; - mech.damage(0.001) + mech.damage(0.00015) } } //aoe damage to mobs for (let i = 0, len = mob.length; i < len; i++) { if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.damageRadius) { if (mob[i].shield) { - mob[i].damage(5 * b.dmgScale * 0.02); + mob[i].damage(5 * b.dmgScale * 0.025); } else { - mob[i].damage(b.dmgScale * 0.02); + mob[i].damage(b.dmgScale * 0.025); } - mob[i].locatePlayer(); } } + + //draw it differently for the initial detonation to make the stun seem logical. + //make draw some electricity? + ctx.beginPath(); ctx.arc(this.position.x, this.position.y, this.damageRadius, 0, 2 * Math.PI); ctx.globalCompositeOperation = "lighter" - ctx.fillStyle = `rgba(0,100,120,${0.3+0.05*Math.random()})`; + // ctx.fillStyle = `hsla(189,60%,50%,${0.35+0.06*Math.random()})`; + ctx.fillStyle = `rgba(20,130,160,${0.35+0.06*Math.random()})`; ctx.fill(); ctx.globalCompositeOperation = "source-over" } diff --git a/js/game.js b/js/game.js index 89bd949..69729ad 100644 --- a/js/game.js +++ b/js/game.js @@ -263,12 +263,12 @@ const game = { // mech.drop(); }, keyPress() { //runs on key down event - if (keys[189]) { + if (keys[189] || keys[79]) { // - key game.isAutoZoom = false; game.zoomScale /= 0.9; game.setZoom(); - } else if (keys[187]) { + } else if (keys[187] || keys[73]) { // = key game.isAutoZoom = false; game.zoomScale *= 0.9; diff --git a/js/level.js b/js/level.js index b3e1a4f..a0edbfc 100644 --- a/js/level.js +++ b/js/level.js @@ -21,7 +21,7 @@ const level = { // b.giveMod("renormalization"); // b.giveMod("impact shear"); // b.giveMod("clock gating"); - b.giveGuns("neutron bomb") + // b.giveGuns("neutron bomb") // mech.setField("pilot wave") // mech.setField("perfect diamagnetism") @@ -102,7 +102,7 @@ const level = { //****************************************************************************************************************** testing() { - level.difficultyIncrease(9); + level.difficultyIncrease(14); //hard mode level 7 spawn.setSpawnList(); spawn.setSpawnList(); level.defaultZoom = 1500 @@ -157,8 +157,10 @@ const level = { // spawn.bomberBoss(2900, -500) // spawn.shooterBoss(1200, -500) - // spawn.spawns(1200, -500) - spawn.hopper(1600, -500) + // spawn.spinner(1200, -500) + // spawn.grower(1600, -500) + spawn.cellBossCulture(1600, -500) + // spawn.shooter(1600, -500) // spawn.shield(mob[mob.length - 1], 1200, -500, 1); // spawn.nodeBoss(1200, -500, "spiker") diff --git a/js/mobs.js b/js/mobs.js index 0d9aa61..3372100 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -972,7 +972,7 @@ const mobs = { this.removeConsBB(); this.alive = false; //triggers mob removal in mob[i].replace(i) if (this.dropPowerUp) { - if (b.isModEnergyLoss) mech.energy /= 2; + if (b.isModEnergyLoss) mech.energy /= 3; powerUps.spawnRandomPowerUp(this.position.x, this.position.y, this.mass, radius); mech.lastKillCycle = mech.cycle; //tracks the last time a kill was made, mostly used in game.checks() if (Math.random() < b.modSporesOnDeath) { @@ -1034,7 +1034,8 @@ const mobs = { //if there are too many bodies don't turn into blocks to help performance if (this.leaveBody && body.length < 60 && this.mass < 100) { const len = body.length; - body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, this.vertices); + const v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure + body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v); Matter.Body.setVelocity(body[len], this.velocity); Matter.Body.setAngularVelocity(body[len], this.angularVelocity); body[len].collisionFilter.category = cat.body; diff --git a/js/player.js b/js/player.js index 01cfdc6..fcfff3a 100644 --- a/js/player.js +++ b/js/player.js @@ -1871,8 +1871,8 @@ const mech = { mech.lookForPickUp(); const DRAIN = 0.0004 + 0.0002 * player.speed + ((!b.modRenormalization && mech.fireCDcycle > mech.cycle) ? 0.005 : 0.0017) - mech.energy -= DRAIN; if (mech.energy > DRAIN) { + mech.energy -= DRAIN; // if (mech.energy < 0.001) { // mech.fieldCDcycle = mech.cycle + 120; // mech.energy = 0; diff --git a/js/spawn.js b/js/spawn.js index 4b661ac..7f9aa0d 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -160,6 +160,7 @@ const spawn = { me.isCell = true; me.accelMag = 0.00015 * game.accelScale; me.memory = 40; + me.isVerticesChange = true me.frictionAir = 0.012 me.seePlayerFreq = Math.floor(11 + 7 * Math.random()) me.seeAtDistance2 = 1400000; @@ -173,12 +174,14 @@ const spawn = { Matter.Body.scale(this, 0.4, 0.4); this.radius = Math.sqrt(this.mass * k / Math.PI) spawn.cellBoss(this.position.x, this.position.y, this.radius); + mob[mob.length - 1].health = this.health } me.onHit = function () { //run this function on hitting player + this.health = 1; this.split(); }; me.onDamage = function (dmg) { - if (Math.random() < 0.17 * dmg * Math.sqrt(this.mass) && this.health > dmg) this.split(); + if (Math.random() < 0.33 * dmg * Math.sqrt(this.mass) && this.health > dmg) this.split(); } me.do = function () { if (!mech.isBodiesAsleep) { @@ -326,9 +329,13 @@ const spawn = { grower(x, y, radius = 15) { mobs.spawn(x, y, 7, radius, "hsl(144, 15%, 50%)"); let me = mob[mob.length - 1]; + me.isVerticesChange = true me.big = false; //required for grow me.accelMag = 0.00045 * game.accelScale; me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.player //can't touch other mobs + // me.onDeath = function () { //helps collisions functions work better after vertex have been changed + // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) + // } me.do = function () { this.seePlayerByLookingAt(); this.checkStatus(); @@ -907,6 +914,7 @@ const spawn = { x: x, y: y } + me.count = 0; me.frictionAir = 0.03; // me.torque -= me.inertia * 0.002 Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger @@ -928,7 +936,10 @@ const spawn = { break } } - if (!slowed) Matter.Body.setAngle(me, game.cycle * this.rotateVelocity) + if (!slowed) { + this.count++ + Matter.Body.setAngle(me, this.count * this.rotateVelocity) + } // this.torque -= this.inertia * 0.0000025 / (4 + this.health); Matter.Body.setVelocity(this, { @@ -1029,6 +1040,7 @@ const spawn = { if (radius > 80) radius = 65; mobs.spawn(x, y, 6, radius, "rgb(220,50,205)"); //can't have sides above 6 or collision events don't work (probably because of a convex problem) let me = mob[mob.length - 1]; + me.isVerticesChange = true me.accelMag = 0.0006 * game.accelScale; // me.g = 0.0002; //required if using 'gravity' me.delay = 360 * game.CDScale; @@ -1046,6 +1058,7 @@ const spawn = { const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), this.radius * this.spikeLength) this.vertices[this.spikeVertex].x = this.position.x + spike.x this.vertices[this.spikeVertex].y = this.position.y + spike.y + this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) } }; me.do = function () { @@ -1339,7 +1352,10 @@ const spawn = { shooter(x, y, radius = 25 + Math.ceil(Math.random() * 50)) { mobs.spawn(x, y, 3, radius, "rgb(255,100,150)"); let me = mob[mob.length - 1]; - me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front + me.vertices = Matter.Vertices.clockwiseSort(Matter.Vertices.rotate(me.vertices, Math.PI, me.position)); //make the pointy side of triangle the front + me.isVerticesChange = true + // Matter.Body.rotate(me, Math.PI) + me.memory = 120; me.fireFreq = 0.007 + Math.random() * 0.005; me.noseLength = 0; @@ -1351,6 +1367,9 @@ const spawn = { x: 0, y: 0 }; + me.onDeath = function () { //helps collisions functions work better after vertex have been changed + this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) + } // spawn.shield(me, x, y); me.do = function () { this.seePlayerByLookingAt(); @@ -1359,10 +1378,10 @@ const spawn = { }; }, shooterBoss(x, y, radius = 130) { - //boss spawns on skyscraper level mobs.spawn(x, y, 3, radius, "rgb(255,70,180)"); let me = mob[mob.length - 1]; me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front + me.isVerticesChange = true me.memory = 240; me.homePosition = { x: x, @@ -1381,7 +1400,9 @@ const spawn = { Matter.Body.setDensity(me, 0.02 + 0.0008 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger me.onDeath = function () { 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.do = function () { this.seePlayerByLookingAt(); this.checkStatus(); diff --git a/todo.txt b/todo.txt index 99492e0..fc5d2bb 100644 --- a/todo.txt +++ b/todo.txt @@ -1,15 +1,31 @@ +acute stress mod removes 1/3 (was 1/2) of your energy +zoom works with i and o now +cell boss has double the chance to spilt on damage. +After it splits, each daughter cell has the mother's reduced health + +new gun neutron bomb, persistent AoE damage + (might still have issues sticking to objects properly) +new mob neutron bomb stuns mobs + ************** TODO - n-gon ************** -frozen mobs take +33% damage +extend neutron mob sticking code to foam gun and mines? -a lasting AoE damage gun - reuse sporangium code - maybe mod for vacuum bomb where it does aoe damage before it explodes +phase field is kinda annoying + large vision range, + faster animation (instant?) + shrink vision range slowly over time, not with energy + also shrink when firing or moving? + +mod - frozen mobs take +33% damage bot that punches nearby mobs bot could have a regeneration phase, and a punching phase indicate phase by the size, shape of bot +mod heal to full at the end of each level + heal mods no longer drop? + possible names for mods Hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other. @@ -64,6 +80,8 @@ scrap drops that can be used to buy things in a shop scrap could be yellow shop could appear every 4 levels +mob - stuns, or slows player + boss mob - let it die multiple times and come back to life on death event spawns a new version of self, but with a decrementing counter