diff --git a/js/bullet.js b/js/bullet.js index 4de5348..4fa4ded 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -475,7 +475,7 @@ const b = { friction: 0, frictionAir: 0.025, thrust: mod.isFastSpores ? 0.001 : 0.0004, - dmg: 2.8, //damage done in addition to the damage from momentum + dmg: mod.isMutualism ? 5.6 : 2.8, //2x bonus damage from mod.isMutualism lookFrequency: 97 + Math.floor(117 * Math.random()), classType: "bullet", collisionFilter: { @@ -491,7 +491,18 @@ const b = { onDmg() { this.endCycle = 0; //bullet ends cycle after doing damage }, - onEnd() {}, + onEnd() { + if (mod.isMutualism && this.isMutualismActive) { + if (mod.isEnergyHealth) { + mech.energy += 0.01; + } else { + mech.health += 0.01 + if (mech.health > mech.maxHealth) mech.health = mech.maxHealth; + mod.onHealthChange(); + mech.displayHealth(); + } + } + }, do() { if (!(game.cycle % this.lookFrequency)) { //find mob targets this.closestTarget = null; @@ -535,6 +546,20 @@ const b = { y: SPEED * Math.sin(ANGLE) }); World.add(engine.world, bullet[bIndex]); //add bullet to world + + if (mod.isMutualism) { + if (mod.isEnergyHealth) { + if (mech.energy > 0.02) { + mech.energy -= 0.01; //energy takes an extra 25% damage for balancing purposes + bullet[bIndex].isMutualismActive = true + } + } else if (mech.health > 0.02) { + mech.health -= 0.01 + mod.onHealthChange(); + mech.displayHealth(); + bullet[bIndex].isMutualismActive = true + } + } }, iceIX(speed = 0, spread = 2 * Math.PI) { const me = bullet.length; @@ -1306,42 +1331,72 @@ const b = { name: "flechettes", description: "fire a volley of uranium-235 needles
does damage over 3 seconds", ammo: 0, - ammoPack: 23, - defaultAmmoPack: 23, + ammoPack: 30, + defaultAmmoPack: 30, have: false, isStarterGun: true, isEasyToAim: false, count: 0, //used to track how many shots are in a volley before a big CD lastFireCycle: 0, //use to remember how longs its been since last fire, used to reset count fire() { - const CD = (mech.crouch) ? 50 : 30 - if (this.lastFireCycle + CD < mech.cycle) this.count = 0 //reset count if it cycles past the CD - this.lastFireCycle = mech.cycle - if (this.count > ((mech.crouch) ? 6 : 1)) { - this.count = 0 - mech.fireCDcycle = mech.cycle + Math.floor(CD * mod.fireRate); // cool down - } else { - this.count++ - mech.fireCDcycle = mech.cycle + Math.floor(3 * mod.fireRate); // cool down - } - function makeFlechette(angle = mech.angle) { const me = bullet.length; bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(mech.angle), mech.pos.y + 40 * Math.sin(mech.angle), 45, 1.4, b.fireAttributes(angle)); - // Matter.Body.setDensity(bullet[me], 0.0001); //0.001 is normal + bullet[me].collisionFilter.mask = cat.body; //cat.mobShield | //cat.map | cat.body | + Matter.Body.setDensity(bullet[me], 0.00001); //0.001 is normal bullet[me].endCycle = game.cycle + 180; bullet[me].dmg = 0; - bullet[me].onDmg = function (who) { - if (mod.isDotFlechette) { - mobs.statusDoT(who, 0.33, 360) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) - } else { - mobs.statusDoT(who, 0.33, 180) // (2.3) / 6 ticks (3 seconds) + bullet[me].immuneList = [] + bullet[me].do = function () { + const whom = Matter.Query.collides(this, mob) + if (whom.length && this.speed > 20) { //if touching a mob + who = whom[0].bodyA + if (who) { + + function hit(that) { + who.foundPlayer(); + if (mod.isDotFlechette) { + mobs.statusDoT(who, 0.5, 360) + } else { + mobs.statusDoT(who, 0.5, 180) + } + game.drawList.push({ //add dmg to draw queue + x: that.position.x, + y: that.position.y, + radius: 40, + color: "rgba(0,80,80,0.3)", + time: game.drawTime + }); + } + + if (mod.pierce) { + let immune = false + for (let i = 0; i < this.immuneList.length; i++) { + if (this.immuneList[i] === who.id) immune = true + } + if (!immune) { + this.immuneList.push(who.id) + hit(this) + } + } else { + this.endCycle = 0; + hit(this) + } + } + } else if (Matter.Query.collides(this, map).length) { //stick in walls + this.collisionFilter.mask = 0; + Matter.Body.setAngularVelocity(this, 0) + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); + this.do = function () {} + } else if (this.speed < 30) { + this.force.y += this.mass * 0.0007; //no gravity until it slows down to improve aiming } }; - bullet[me].do = function () { - if (this.speed < 10) this.force.y += this.mass * 0.0003; //no gravity until it slows don to improve aiming - }; + const SPEED = 50 Matter.Body.setVelocity(bullet[me], { x: mech.Vx / 2 + SPEED * Math.cos(angle), @@ -1351,9 +1406,46 @@ const b = { } makeFlechette() if (mod.isFlechetteMultiShot) { - makeFlechette(mech.angle + 0.01 + 0.01 * Math.random()) - makeFlechette(mech.angle - 0.01 - 0.01 * Math.random()) + makeFlechette(mech.angle + 0.02 + 0.005 * Math.random()) + makeFlechette(mech.angle - 0.02 - 0.005 * Math.random()) } + + const CD = (mech.crouch) ? 60 : 30 + if (this.lastFireCycle + CD < mech.cycle) this.count = 0 //reset count if it cycles past the CD + this.lastFireCycle = mech.cycle + if (this.count > ((mech.crouch) ? 7 : 1)) { + this.count = 0 + mech.fireCDcycle = mech.cycle + Math.floor(CD * mod.fireRate); // cool down + + const who = bullet[bullet.length - 1] + Matter.Body.setDensity(who, 0.00001); + // who.onDmg = function (who) { + // if (mod.isDotFlechette) { + // mobs.statusDoT(who, 0.33, 360) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) + // mobs.statusSlow(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) + // } else { + // mobs.statusDoT(who, 0.33, 180) // (2.3) / 6 ticks (3 seconds) + // mobs.statusSlow(who, 60) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) + // } + // this.endCycle = 0; + // }; + + // who.onEnd = function () { + // b.explosion(this.position, 220); //makes bullet do explosive damage at end + // } + // who.do = function () { + // if (this.speed < 10) this.force.y += this.mass * 0.0003; //no gravity until it slows don to improve aiming + // if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { + // this.endCycle = 0; //explode if touching map or blocks + // } + // } + + } else { + this.count++ + mech.fireCDcycle = mech.cycle + Math.floor(3 * mod.fireRate); // cool down + } + + } }, { @@ -1956,7 +2048,7 @@ const b = { }, { name: "spores", - description: "fire a sporangium that discharges spores", + description: "fire a sporangium that discharges spores
spores seek out nearby mobs", ammo: 0, ammoPack: 5, have: false, @@ -2069,7 +2161,6 @@ const b = { b.spore(this) } } - } }, { diff --git a/js/engine.js b/js/engine.js index 2f344cd..dfc4a65 100644 --- a/js/engine.js +++ b/js/engine.js @@ -208,6 +208,7 @@ function collisionChecks(event) { if (mod.isCrit && !mob[k].seePlayer.recall && !mob[k].shield) dmg *= 5 mob[k].foundPlayer(); mob[k].damage(dmg); + // console.log(dmg) obj.onDmg(mob[k]); //some bullets do actions when they hits things, like despawn game.drawList.push({ //add dmg to draw queue x: pairs[i].activeContacts[0].vertex.x, diff --git a/js/game.js b/js/game.js index 9394731..c4eb2e7 100644 --- a/js/game.js +++ b/js/game.js @@ -644,6 +644,21 @@ const game = { } } + if (mod.isMutualism) { + for (let i = 0; i < bullet.length; i++) { + if (bullet[i].isMutualismActive) { + if (mod.isEnergyHealth) { + mech.energy += 0.01; + } else { + mech.health += 0.01 + if (mech.health > mech.maxHealth) mech.health = mech.maxHealth; + mod.onHealthChange(); + mech.displayHealth(); + } + } + } + } + //if player is holding something this remembers it before it gets deleted let holdTarget; if (mech.holdingTarget) { diff --git a/js/level.js b/js/level.js index dff58af..1e15812 100644 --- a/js/level.js +++ b/js/level.js @@ -17,9 +17,9 @@ const level = { // game.enableConstructMode() //used to build maps in testing mode // level.difficultyIncrease(9) // mech.setField("time dilation field") - // mod.giveMod("brushless motor"); + // mod.giveMod("mutualism"); // b.giveGuns("drones") - // b.giveGuns("mine") + // b.giveGuns("spores") // mech.setField("pilot wave") // mech.setField("phase decoherence field") @@ -60,10 +60,10 @@ const level = { // if (level.isBuildRun) num++ for (let i = 0; i < num; i++) { game.difficulty++ - game.dmgScale += 0.205; //damage done by mobs increases each level + game.dmgScale += 0.21; //damage done by mobs increases each level b.dmgScale *= 0.91; //damage done by player decreases each level - game.accelScale *= 1.024 //mob acceleration increases each level - game.lookFreqScale *= 0.976 //mob cycles between looks decreases each level + game.accelScale *= 1.027 //mob acceleration increases each level + game.lookFreqScale *= 0.974 //mob cycles between looks decreases each level game.CDScale *= 0.964 //mob CD time decreases each level } game.healScale = 1 / (1 + game.difficulty * 0.09) //a higher denominator makes for lower heals // mech.health += heal * game.healScale; @@ -71,11 +71,11 @@ const level = { difficultyDecrease(num = 1) { //used in easy mode for game.reset() for (let i = 0; i < num; i++) { game.difficulty-- - game.dmgScale -= 0.205; //damage done by mobs increases each level + game.dmgScale -= 0.21; //damage done by mobs increases each level if (game.dmgScale < 0.1) game.dmgScale = 0.1; b.dmgScale /= 0.91; //damage done by player decreases each level - game.accelScale /= 1.024 //mob acceleration increases each level - game.lookFreqScale /= 0.976 //mob cycles between looks decreases each level + game.accelScale /= 1.027 //mob acceleration increases each level + game.lookFreqScale /= 0.974 //mob cycles between looks decreases each level game.CDScale /= 0.964 //mob CD time decreases each level } if (game.difficulty < 1) game.difficulty = 0; @@ -187,6 +187,8 @@ const level = { // spawn.laserTargetingBoss(1600, -400) // spawn.spawner(1600, -500) spawn.sniper(1700, -120) + // spawn.sniper(1600, -120) + // spawn.sniper(1800, -120) // spawn.cellBossCulture(1600, -500) // spawn.shooter(1600, -500) // spawn.striker(1600, -500) diff --git a/js/mods.js b/js/mods.js index 74ea71e..ddc0279 100644 --- a/js/mods.js +++ b/js/mods.js @@ -374,29 +374,29 @@ const mod = { }, remove() {} }, - { - name: "ablative mines", - description: "rebuild your broken parts as a mine
chance to occur after being harmed", - maxCount: 1, - count: 0, - allowed() { - return true - }, - requires: "", - effect() { - mod.isMineOnDamage = true; - b.mine({ - x: mech.pos.x, - y: mech.pos.y - 80 - }, { - x: 0, - y: 0 - }) - }, - remove() { - mod.isMineOnDamage = false; - } - }, + // { + // name: "ablative mines", + // description: "rebuild your broken parts as a mine
chance to occur after being harmed", + // maxCount: 1, + // count: 0, + // allowed() { + // return true + // }, + // requires: "", + // effect() { + // mod.isMineOnDamage = true; + // b.mine({ + // x: mech.pos.x, + // y: mech.pos.y - 80 + // }, { + // x: 0, + // y: 0 + // }) + // }, + // remove() { + // mod.isMineOnDamage = false; + // } + // }, { name: "ablative drones", description: "rebuild your broken parts as drones
chance to occur after being harmed", @@ -767,7 +767,7 @@ const mod = { }, { name: "catabolism", - description: "gain ammo when you fire while out of ammo
drains 3% of current remaining health", + description: "gain ammo when you fire while out of ammo
drains 3% of current remaining health", maxCount: 1, count: 0, allowed() { @@ -1143,6 +1143,22 @@ const mod = { mod.isDotFlechette = false; } }, + { + name: "piercing needles", + description: "needles penetrate mobs
potentially hitting multiple targets", + maxCount: 1, + count: 0, + allowed() { + return mod.haveGunCheck("flechettes") + }, + requires: "flechettes", + effect() { + mod.pierce = true; + }, + remove() { + mod.pierce = false; + } + }, { name: "wave packet", description: "wave beam emits two oscillating particles
wave particles do 40% less damage", @@ -1421,6 +1437,22 @@ const mod = { mod.isSporeFollow = false } }, + { + name: "mutualism", + description: "spores do 2x damage
spores borrow 1% health until they die", + maxCount: 1, + count: 0, + allowed() { + return mod.haveGunCheck("spores") || mod.sporesOnDeath > 0 || mod.isSporeField + }, + requires: "spores", + effect() { + mod.isMutualism = true + }, + remove() { + mod.isMutualism = false + } + }, { name: "brushless motor", description: "drones accelerate 50% faster", @@ -1785,7 +1817,7 @@ const mod = { isImmuneExplosion: null, isExplodeMob: null, isDroneOnDamage: null, - isMineOnDamage: null, + // isMineOnDamage: null, acidDmg: null, isAcidDmg: null, isAnnihilation: null, diff --git a/js/player.js b/js/player.js index 89b3ffb..b3b41da 100644 --- a/js/player.js +++ b/js/player.js @@ -478,15 +478,15 @@ const mech = { if (Math.random() < 0.5) b.drone() //spawn drone } } - if (mod.isMineOnDamage && dmg > 0.004 + 0.05 * Math.random()) { - b.mine({ - x: mech.pos.x, - y: mech.pos.y - 80 - }, { - x: 0, - y: 0 - }) - } + // if (mod.isMineOnDamage && dmg > 0.004 + 0.05 * Math.random()) { + // b.mine({ + // x: mech.pos.x, + // y: mech.pos.y - 80 + // }, { + // x: 0, + // y: 0 + // }) + // } dmg *= mech.harmReduction() if (mod.isEnergyHealth) { @@ -543,15 +543,14 @@ const mech = { return; } } + mod.onHealthChange(); + mech.displayHealth(); + document.getElementById("dmg").style.transition = "opacity 0s"; + document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); } if (dmg > 0.2 * mech.holdingMassScale) mech.drop(); //drop block if holding - mod.onHealthChange(); - mech.displayHealth(); - document.getElementById("dmg").style.transition = "opacity 0s"; - document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); - const normalFPS = function () { if (mech.defaultFPSCycle < mech.cycle) { //back to default values game.fpsCap = game.fpsCapDefault @@ -698,10 +697,10 @@ const mech = { fieldMode: 0, //basic field mode before upgrades maxEnergy: 1, //can be increased by a mod holdingTarget: null, - fieldShieldingScale: 1, timeSkipLastCycle: 0, // these values are set on reset by setHoldDefaults() fieldRange: 155, + fieldShieldingScale: 1, energy: 0, fieldRegen: 0, fieldMode: 0, @@ -1220,9 +1219,10 @@ const mech = { }, { name: "standing wave harmonics", - description: "three oscillating shields are permanently active
energy regenerates while field is active", + description: "three oscillating shields are permanently active
reduce harm by 33%", isEasyToAim: true, effect: () => { + mech.fieldHarmReduction = 0.67; mech.fieldBlockCD = 0; mech.hold = function () { if (mech.isHolding) { @@ -1510,11 +1510,10 @@ const mech = { }, { name: "plasma torch", - description: "use energy to emit damaging plasma
reduce harm by 20%", + description: "use energy to emit short range plasma
plasma damages and pushes mobs", isEasyToAim: false, effect: () => { mech.fieldMeterColor = "#f0f" - mech.fieldHarmReduction = 0.80; mech.hold = function () { if (mech.isHolding) { diff --git a/js/powerup.js b/js/powerup.js index 2295d71..11f46aa 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -389,20 +389,22 @@ const powerUps = { } }, spawnBossPowerUp(x, y) { //boss spawns field and gun mod upgrades - if (game.difficultyMode > 1 || Math.random() < 0.66) { //easy and normal have only a 66% chance for a power up - spawnPowerUps() - if (game.difficultyMode > 2 && level.levelsCleared % 2 == 0) spawnPowerUps() //why? has an extra power up on even numbered levels - } else { - if (mech.health < 0.65 && !mod.isEnergyHealth) { - powerUps.spawn(x, y, "heal"); - powerUps.spawn(x, y, "heal"); - if (Math.random() < mod.bayesian) { + if (level.levelsCleared < 20 || level.levelsCleared % 2 == 0) { //drop only on even levels above level 20 + if (game.difficultyMode > 1 || Math.random() < 0.66) { //easy and normal have only a 66% chance for a power up + spawnPowerUps() + if (game.difficultyMode > 2 && level.levelsCleared % 2 == 0) spawnPowerUps() //why? has an extra power up on even numbered levels + } else { + if (mech.health < 0.65 && !mod.isEnergyHealth) { powerUps.spawn(x, y, "heal"); powerUps.spawn(x, y, "heal"); + if (Math.random() < mod.bayesian) { + powerUps.spawn(x, y, "heal"); + powerUps.spawn(x, y, "heal"); + } + } else if (!mod.bayesian) { + powerUps.spawn(x, y, "ammo"); + powerUps.spawn(x, y, "ammo"); } - } else if (!mod.bayesian) { - powerUps.spawn(x, y, "ammo"); - powerUps.spawn(x, y, "ammo"); } } diff --git a/js/spawn.js b/js/spawn.js index f01158f..4d107be 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -83,8 +83,7 @@ const spawn = { }, randomLevelBoss(x, y) { // other bosses: suckerBoss, laserBoss, tetherBoss, snakeBoss //all need a particular level to work so they are not included - // "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", - const options = ["laserTargetingBoss"] // , "timeSkipBoss" + const options = ["shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss"] // , "timeSkipBoss" spawn[options[Math.floor(Math.random() * options.length)]](x, y) }, //mob templates ********************************************************************************************* @@ -893,17 +892,17 @@ const spawn = { }; } }, - laserTargetingBoss(x, y, radius = 70) { + laserTargetingBoss(x, y, radius = 65) { const color = "#05f" mobs.spawn(x, y, 3, radius, color); 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 Matter.Body.rotate(me, Math.random() * Math.PI * 2); - me.accelMag = 0.0006 * game.accelScale; + me.accelMag = 0.0005 * game.accelScale; me.seePlayerFreq = Math.floor(25 * game.lookFreqScale); me.memory = 600; me.restitution = 1; - me.frictionAir = 0.06; + me.frictionAir = 0.05; me.frictionStatic = 0; me.friction = 0; @@ -913,7 +912,7 @@ const spawn = { x: 0, y: 0 } - Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger + Matter.Body.setDensity(me, 0.025); //extra dense //normal is 0.001 //makes effective life much larger spawn.shield(me, x, y, 1); me.onHit = function () { //run this function on hitting player diff --git a/todo.txt b/todo.txt index 2e7d2cb..f70def1 100644 --- a/todo.txt +++ b/todo.txt @@ -1,19 +1,21 @@ -harmonic field now has no cooldown after blocking -negative mass field accelerates slower, but with a higher top speed -negative mass field harm reduction is now 60% and always on -mod degenerate matter increases the damage reduction from 60% to 80% - -falling damage and damage from blocks have been removed -(I'm trying it out, let me know if you want it back) +above level 20 boss power ups only drop on even levels +removed mod ablative mines (was buggy, and too similar to ablative drones) +flechettes get stuck in walls +flechettes do no damage to mobs on hit +flechettes do more damage over time, and have more ammo +mod - flechettes pierce mobs +mod - mutualism: each spore does 2x damage but they borrow 1% life from player ************** TODO - n-gon ************** +shrink font on small screens (so you can see 5 options on power ups) + +graphic idea: bezier curve that moves smoothly from mob to mob + loops around player + add air control check box set mech.airSpeedLimit to 0? to disable -on damage mines mod needs a nerf - spawns 2 mines every time... (from on dmg effects) - give rail gun projectile a trail only draw above speed 5 track previous positions? @@ -32,13 +34,6 @@ movement fluidity wall grab? maybe remove falling damage and block damage? -rays can have width, how to use this? - Matter.Query.ray(bodies, startPoint, endPoint, [rayWidth]) - wide lasers? - -new type of mob vision that uses ray query with thickness - maybe use for bosses - bug - mines spawn extra mines when fired at thin map wall while jumping what about a neutron bomb mod, that causes the bomb to activate right after you fire and slowly move forward with no gravity