diff --git a/js/bullets.js b/js/bullets.js index 1fa9dac..c7f605e 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -148,19 +148,19 @@ const b = { }, { name: "high explosives", - description: "the radius of explosions are +25% larger", + description: "explosions do +20% more damage
explosive area is +44% larger", maxCount: 3, count: 0, allowed() { return true }, effect: () => { - b.modExplosionRadius += 0.25; + b.modExplosionRadius += 0.2; } }, { name: "electric reactive armour", - description: "explosions drain energy instead of doing harm", + description: "explosions do no harm, but drain energy", maxCount: 1, count: 0, allowed() { @@ -276,7 +276,7 @@ const b = { }, { name: "entanglement", - description: "using your first gun reduces harm
scales by 10% for each gun in your inventory", + description: "when your first gun is equipped
reduce harm by 10% for each gun you have", maxCount: 1, count: 0, allowed() { @@ -377,28 +377,28 @@ const b = { }, { name: "overcharge", - description: "charge energy +33% beyond your maximum", + description: "charge energy +50% beyond your maximum", maxCount: 9, count: 0, allowed() { return true }, effect() { - mech.fieldEnergyMax += 0.33 - mech.fieldMeter += 0.33 + mech.fieldEnergyMax += 0.5 + mech.fieldMeter += 0.5 } }, { name: "supersaturation", - description: "heal +33% beyond your max health", + description: "heal +50% beyond your max health", maxCount: 9, count: 0, allowed() { return true }, effect() { - mech.maxHealth += 0.33 - mech.addHealth(0.33) + mech.maxHealth += 0.50 + mech.addHealth(0.50) } }, { diff --git a/js/level.js b/js/level.js index adf25e4..b4fe94e 100644 --- a/js/level.js +++ b/js/level.js @@ -19,14 +19,14 @@ const level = { // b.giveMod("ground stomp"); // level.intro(); //starting level - level.testingMap(); + // level.testingMap(); // level.bosses(); // level.satellite(); // level.skyscrapers(); // level.aerie(); // level.rooftops(); // level.warehouse(); - // level.highrise(); + level.highrise(); // level.office(); } else { spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns @@ -50,7 +50,7 @@ const level = { // if (level.isBuildRun) num++ for (let i = 0; i < num; i++) { game.difficulty++ - game.dmgScale += 0.13; //damage done by mobs increases each level + game.dmgScale += 0.135; //damage done by mobs increases each level b.dmgScale *= 0.93; //damage done by player decreases each level game.accelScale *= 1.02 //mob acceleration increases each level game.lookFreqScale *= 0.98 //mob cycles between looks decreases each level @@ -61,7 +61,7 @@ const level = { difficultyDecrease(num = 1) { //used in easy mode for game.reset() for (let i = 0; i < num; i++) { game.difficulty-- - game.dmgScale -= 0.13; //damage done by mobs increases each level + game.dmgScale -= 0.135; //damage done by mobs increases each level if (game.dmgScale < 0.1) game.dmgScale = 0.1; b.dmgScale /= 0.93; //damage done by player decreases each level game.accelScale /= 1.02 //mob acceleration increases each level @@ -128,6 +128,8 @@ const level = { // spawn.bodyRect(-45, -100, 40, 50); // spawn.bomber(800, -450); spawn.cellBoss(400, -750); + spawn.cellBoss(400, -750); + spawn.cellBoss(400, -750); // spawn.laser(400, -550); // spawn.starter(1200, -1050); @@ -1207,6 +1209,7 @@ const level = { spawn.mapRect(-4450, -3075, 450, 25); spawn.mapRect(-4025, -3075, 25, 100); spawn.mapRect(-4275, -2785, 100, 25); + if (game.difficulty < 4) spawn.bodyRect(-3760, -2400, 50, 50); //mobs spawn.randomMob(-2500, -2700, 1); @@ -1233,7 +1236,14 @@ const level = { spawn.randomMob(-550, -100, -0.1); spawn.randomBoss(-3250, -2700, 0.2); spawn.randomBoss(-2450, -1100, 0); - if (game.difficulty < 4) spawn.bodyRect(-3760, -2400, 50, 50); + if (game.difficulty > 3) { + const x = -2000 - Math.floor(1600 * Math.random()); + const y = -2700 - Math.floor(600 * Math.random()); + const d = 800; + for (let i = 0; i < 5; i++) { + spawn.cellBoss(x + Math.floor(d * (Math.random() - 0.5)), y + Math.floor(d * (Math.random() - 0.5))); + } + } }, warehouse() { level.defaultZoom = 1300 diff --git a/js/mobs.js b/js/mobs.js index 0fa6a0c..c1bef91 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -727,7 +727,7 @@ const mobs = { //accelerate towards the searchTarget if (!this.seePlayer.recall) { const newTarget = function (that) { - if (Math.random() < 0.025) { + if (Math.random() < 0.0005) { that.searchTarget = player.position; //chance to target player } else { //target random body @@ -945,7 +945,7 @@ const mobs = { if (b.modHealthDrain && dmg !== Infinity) mech.addHealth(Math.min(this.health, dmg) * b.modHealthDrain) this.health -= dmg //this.fill = this.color + this.health + ')'; - this.onDamage(this); //custom damage effects + this.onDamage(dmg); //custom damage effects if (this.health < 0.05) this.death(); } }, @@ -966,7 +966,8 @@ const mobs = { if (this.dropPowerUp) { powerUps.spawnRandomPowerUp(this.position.x, this.position.y, this.mass, radius); if (Math.random() < b.modSpores) { - for (let i = 0, len = Math.floor(4 + this.mass * Math.random()); i < len; i++) { + const len = Math.min(30, Math.floor(4 + this.mass * Math.random())) + for (let i = 0; i < len; i++) { b.spore(this) //spawn drone } } diff --git a/js/powerups.js b/js/powerups.js index c6614a0..d6e1fd8 100644 --- a/js/powerups.js +++ b/js/powerups.js @@ -232,7 +232,7 @@ const powerUps = { if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "gun"); return; } - if (Math.random() < 0.003 * (11 - b.modCount)) { //a new mod has a low chance for each not acquired mod up to 7 + if (Math.random() < 0.003 * (12 - b.modCount)) { //a new mod has a low chance for each not acquired mod up to 7 powerUps.spawn(x, y, "mod"); if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "mod"); return; @@ -247,25 +247,34 @@ const powerUps = { if (mech.fieldMode === 0) { powerUps.spawn(x, y, "field") if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "field") - } else if (Math.random() < 0.65) { + } else if (Math.random() < 0.75) { powerUps.spawn(x, y, "mod") if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "mod") - } else if (Math.random() < 0.06) { + } else if (Math.random() < 0.2) { powerUps.spawn(x, y, "gun") if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "gun") - } else if (Math.random() < 0.15) { + } else if (Math.random() < 0.6) { powerUps.spawn(x, y, "field"); if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "field"); - } else if (mech.health < 0.65) { + } else if (mech.health < 0.7) { powerUps.spawn(x, y, "heal"); powerUps.spawn(x, y, "heal"); powerUps.spawn(x, y, "heal"); - if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "heal"); + powerUps.spawn(x, y, "heal"); + if (Math.random() < b.isModBayesian) { + powerUps.spawn(x, y, "heal"); + powerUps.spawn(x, y, "heal"); + } } else { powerUps.spawn(x, y, "ammo"); powerUps.spawn(x, y, "ammo"); powerUps.spawn(x, y, "ammo"); - if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "ammo"); + powerUps.spawn(x, y, "ammo"); + if (Math.random() < b.isModBayesian) { + powerUps.spawn(x, y, "ammo"); + powerUps.spawn(x, y, "ammo"); + } + } }, chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris diff --git a/js/spawn.js b/js/spawn.js index 5a28a2f..059af3e 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -127,10 +127,11 @@ const spawn = { } } }, - starter(x, y, radius = 30) { + starter(x, y, radius = Math.floor(20 + 20 * Math.random())) { //easy mob for on level 1 mobs.spawn(x, y, 8, radius, "#9ccdc6"); let me = mob[mob.length - 1]; + // console.log(`mass=${me.mass}, radius = ${radius}`) me.accelMag = 0.0005 * game.accelScale; me.memory = 60; me.seeAtDistance2 = 1400000 //1200 vision range @@ -141,70 +142,146 @@ const spawn = { this.attraction(); }; }, - cellBoss(x, y, radius = 30, dropPowerUp = true) { - //easy mob for on level 1 - - mobs.spawn(x, y, 8, radius, "rgb(70,170,140)"); + cellBoss(x, y, radius = 20 + 60 * Math.random()) { + mobs.spawn(x, y, 0, radius, "rgba(0,150,155,0.7)"); let me = mob[mob.length - 1]; me.isCell = true; - me.accelMag = 0.0005 * game.accelScale; + me.accelMag = 0.00025 * game.accelScale; me.memory = 60; - me.spawnFrequency = Math.floor(15 + Math.random() * 8) - me.cellRadiusMax = 1000 - me.cellRadius = 100 - me.seeAtDistance2 = me.cellRadius * me.cellRadius // vision range + me.frictionAir = 0.012 + me.seePlayerFreq = Math.floor(5 + 5 * Math.random()) + me.seeAtDistance2 = 9000000; + me.cellMassMax = 100 + + me.collisionFilter.mask = cat.player | cat.bullet // Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback - - //count other cells - let count = 0 - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].isCell) count++ + me.split = function () { + Matter.Body.scale(this, 0.5, 0.5); + this.radius = Math.sqrt(this.mass * 1100 / Math.PI) + spawn.cellBoss(this.position.x, this.position.y, this.radius); + } + me.onHit = function () { //run this function on hitting player + this.split(); + }; + me.onDamage = function (dmg) { + if (Math.random() * 1.8 < dmg && this.health > dmg) this.split(); } - me.growRate = 4 / count //grow proportional to the number of cells alive when born - me.do = function () { - //grow cell radius - if (this.cellRadius < 700) { - this.cellRadius += this.growRate - this.seeAtDistance2 = this.cellRadius * this.cellRadius - } else { - this.seePlayerByDistOrLOS(); + if (!mech.isBodiesAsleep) { + this.seePlayerByDistAndLOS(); this.attraction(); - if (!(game.cycle % this.spawnFrequency) && this.distanceToPlayer() < this.cellRadius) { - spawn.cellBoss(this.position.x, this.position.y, 30, false); - this.cellRadius = 100 + + if (this.mass < this.cellMassMax) { //grow cell radius + const scale = 1 + 0.00015 * this.cellMassMax / this.mass; + Matter.Body.scale(this, scale, scale); + this.radius = Math.sqrt(this.mass * 1100 / Math.PI) } + if (!(game.cycle % this.seePlayerFreq)) { //move away from other mobs + const repelRange = 70 + const attractRange = 600 + for (let i = 0, len = mob.length; i < len; i++) { + if (mob[i].isCell && mob[i].id !== this.id) { + const sub = Vector.sub(this.position, mob[i].position) + const dist = Vector.magnitude(sub) + if (dist < repelRange) { + this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.002) + } else if (dist > attractRange) { + this.force = Vector.mult(Vector.normalise(sub), -this.mass * 0.0015) + } + } + } + } + // if (!(game.cycle % this.seePlayerFreq)) { //move away from other mobs + // let q = Matter.Query.point(mob, this.position) + // for (let i = 0; i < q.length; i++) { + // if (q[i].id !== this.id) { + // THRUST = 0.005 + // this.force = Vector.mult(Vector.normalise(Vector.sub(this.position, q[i].position)), this.mass * THRUST) + // } + // } + // } } - - - //draw range - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.cellRadius, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(70,170,140,0.3)"; - ctx.fill(); - - //spread out away from other cells - // for (let i = 0, len = mob.length; i < len; i++) { - - // } }; me.onDeath = function () { - if (dropPowerUp) { + let count = 0 //count other cells + for (let i = 0, len = mob.length; i < len; i++) { + if (mob[i].isCell) count++ + } + if (count === 1) { //only drop a power up if this is the last cell powerUps.spawnBossPowerUp(this.position.x, this.position.y) } else { this.dropPowerUp = false; } - //find other cells and have them reset their growth rate - let count = 0 - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].isCell) count++ - } - const growRate = 4 / count //grow proportional to the number of cells alive when born - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].isCell) mob[i].growRate = growRate - } } }, + // cellBoss(x, y, radius = 30) { + // mobs.spawn(x, y, 8, radius, "rgb(70,170,140)"); + // let me = mob[mob.length - 1]; + // me.isCell = true; + // me.accelMag = 0.0003 * game.accelScale; + // me.memory = 60; + // me.spawnFrequency = Math.floor(15 + Math.random() * 8) + // me.cellRadiusMax = 600 + // me.cellRadius = 100 + // me.seeAtDistance2 = me.cellRadius * me.cellRadius // vision range + // // Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback + + // //count other cells + // let count = 0 + // for (let i = 0, len = mob.length; i < len; i++) { + // if (mob[i].isCell) count++ + // } + // me.growRate = 4 / count //grow proportional to the number of cells alive when born + + // me.do = function () { + // //grow cell radius + // if (this.cellRadius < this.cellRadiusMax) { + // this.cellRadius += this.growRate + // this.seeAtDistance2 = this.cellRadius * this.cellRadius + // } + // if (this.cellRadius > this.cellRadiusMax / 2) { + // this.seePlayerByDistOrLOS(); + // this.attraction(); + // //when near player split and hurt player + // if (!(game.cycle % this.spawnFrequency) && this.distanceToPlayer() < this.cellRadius) { + // spawn.cellBoss(this.position.x, this.position.y, 30); + // this.cellRadius = 100 + // // let dmg = 0.1 * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 + // // mech.damage(dmg); + // } + + // //eat blocks and power ups, gain an increases in radius, and split + // //remember what was eaten and release it out on death + // } + + // ctx.beginPath(); //draw range + // ctx.arc(this.position.x, this.position.y, this.cellRadius, 0, 2 * Math.PI); + // ctx.fillStyle = `rgba(70,170,140,${0.7*this.cellRadius/this.cellRadiusMax})` + // ctx.fill(); + + // //flocking behavior? + // // for (let i = 0, len = mob.length; i < len; i++) { + + // // } + // }; + // me.onDeath = function () { + // //find other cells and have them reset their growth rate + // let count = 0 + // for (let i = 0, len = mob.length; i < len; i++) { + // if (mob[i].isCell) count++ + // } + // const growRate = 4 / count //grow proportional to the number of cells alive when born + // for (let i = 0, len = mob.length; i < len; i++) { + // if (mob[i].isCell) mob[i].growRate = growRate + // } + // //only drop a power up if this is the last cell + // if (count === 1) { + // powerUps.spawnBossPowerUp(this.position.x, this.position.y) + // } else { + // this.dropPowerUp = false; + // } + // } + // }, // healer(x, y, radius = 20) { // mobs.spawn(x, y, 3, radius, "rgba(50,255,200,0.4)"); @@ -541,31 +618,6 @@ const spawn = { toMe(body, this.position, this.eventHorizon) toMe(mob, this.position, this.eventHorizon) toMe(bullet, this.position, this.eventHorizon) - - //push everything away - // function push(who, pos, range) { - // for (let i = 0, len = who.length; i < len; ++i) { - // const SUB = Vector.sub(who[i].position, pos) - // const DISTANCE = Vector.magnitude(SUB) - // if (DISTANCE < range) { - // const depth = range - DISTANCE - // const force = Vector.mult(Vector.normalise(SUB), 30 * who[i].mass / depth) - // who[i].force.x += force.x; - // who[i].force.y += force.y; - // } - // } - // } - // push(body, this.position, this.eventHorizon) - // push(mob, this.position, this.eventHorizon) - // push(bullet, this.position, this.eventHorizon) - // push([player], this.position, this.eventHorizon) - // for (let i = 0; i < (game.difficulty - 3); ++i) { - // spawn.sucker(this.position.x + (Math.random() - 0.5) * radius * 2, this.position.y + (Math.random() - 0.5) * radius * 2, 70 * Math.random()); - // Matter.Body.setVelocity(mob[mob.length - 1], { - // x: (Math.random() - 0.5) * 70, - // y: (Math.random() - 0.5) * 70 - // }); - // } } }; me.do = function () { @@ -613,8 +665,11 @@ const spawn = { ctx.fill(); //when player is inside event horizon if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon && !mech.isStealth) { - mech.damage(0.00015 * game.dmgScale); - if (mech.fieldMeter > 0.1) mech.fieldMeter -= 0.0045 + if (mech.fieldMeter > 0.1) { + mech.fieldMeter -= 0.0055 + } else { + mech.damage(0.0003 * game.dmgScale); + } const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); player.force.x -= 1.3 * Math.cos(angle) * player.mass * game.g * (mech.onGround ? 1.7 : 1); player.force.y -= 1.2 * Math.sin(angle) * player.mass * game.g;