diff --git a/js/bullets.js b/js/bullets.js index 1ba512f..ef0c900 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -61,6 +61,7 @@ const b = { isModRailNails: null, isModHawking: null, modBabyMissiles: null, + isModIceCrystals: null, modOnHealthChange() { //used with acid mod if (b.isModAcidDmg && mech.health > 0.8) { game.playerDmgColor = "rgba(0,80,80,0.9)" @@ -422,22 +423,6 @@ const b = { b.isModStomp = false; } }, - { - name: "entanglement", - description: "only when your first gun is equipped
reduce harm by 10% for each gun you have", - maxCount: 1, - count: 0, - allowed() { - return true - }, - requires: "", - effect() { - b.isModEntanglement = true - }, - remove() { - b.isModEntanglement = false; - } - }, { name: "Pauli exclusion", description: `unable to collide with mobs for +1 second
activates after being harmed from a collision`, @@ -505,9 +490,25 @@ const b = { b.isModDeathAvoidOnCD = false; } }, + { + name: "entanglement", + description: "10% less harm for each gun in your inventory
when your first gun is equipped", + maxCount: 1, + count: 0, + allowed() { + return true + }, + requires: "", + effect() { + b.isModEntanglement = true + }, + remove() { + b.isModEntanglement = false; + } + }, { name: "piezoelectricity", - description: "colliding with mobs charges your energy", + description: "colliding with mobs charges your energy
10% less harm from mob collisions", maxCount: 1, count: 0, allowed() { @@ -735,8 +736,8 @@ const b = { { - name: "crystal nucleation", - description: "fire crystals formed from the air
your minigun no longer requires ammo", + name: "ice crystal nucleation", + description: "your minigun condenses unlimited ammo
ice bullets made from water vapor slow mobs", maxCount: 1, count: 0, allowed() { @@ -744,6 +745,7 @@ const b = { }, requires: "minigun", effect() { + b.isModIceCrystals = true; for (i = 0, len = b.guns.length; i < len; i++) { //find which gun if (b.guns[i].name === "minigun") { b.guns[i].ammoPack = Infinity @@ -755,6 +757,7 @@ const b = { } }, remove() { + b.isModIceCrystals = false; for (i = 0, len = b.guns.length; i < len; i++) { //find which gun if (b.guns[i].name === "minigun") { b.guns[i].ammoPack = b.guns[i].defaultAmmoPack; @@ -829,6 +832,22 @@ const b = { game.updateGunHUD(); } }, + { + name: "irradiated needles", + description: "fléchette needles are exposed to radiation
needles do 3x damage over 6 seconds", + maxCount: 1, + count: 0, + allowed() { + return b.haveGunCheck("fléchettes") + }, + requires: "fléchettes", + effect() { + b.isModDotFlechette = true; + }, + remove() { + b.isModDotFlechette = false; + } + }, { name: "wave phase velocity", description: "the wave beam propagates faster in solids", @@ -2062,19 +2081,11 @@ const b = { bullet[me].endCycle = game.cycle + 70; bullet[me].dmg = 0.07; bullet[me].frictionAir = mech.crouch ? 0.007 : 0.01; - bullet[me].onDmg = function (who) { - - who.status.push({ //slow - endCycle: game.cycle + 60, - effect() { - - Matter.Body.setVelocity(who, { - x: who.velocity.x * 0.8, - y: who.velocity.y * 0.8 - }); - }, - }) - }; + if (b.isModIceCrystals) { + bullet[me].onDmg = function (who) { + if (!who.shield) mobs.statusSlow(who, 60) + }; + } bullet[me].do = function () { this.force.y += this.mass * 0.0005; }; @@ -2169,7 +2180,6 @@ const b = { const CD = (mech.crouch) ? 45 : 25 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 * b.modFireRate); // cool down @@ -2181,8 +2191,17 @@ const b = { 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 * b.modBulletSize, 1.4 * b.modBulletSize, b.fireAttributes(angle)); + Matter.Body.setDensity(bullet[me], 0.0001); //0.001 is normal bullet[me].endCycle = game.cycle + 180; - bullet[me].dmg = 1.3; + if (b.isModDotFlechette) { + bullet[me].dmg = 0; + bullet[me].onDmg = function (who) { + mobs.statusDot(who, 0.35, 360) // (1.4) * 3 / 12 ticks (6 seconds) + }; + } else { + bullet[me].dmg = 1.4; + } + bullet[me].do = function () { if (this.speed < 10) this.force.y += this.mass * 0.0003; //no gravity until it slows don to improve aiming }; @@ -2245,7 +2264,7 @@ const b = { for (let i = 0; i < q.length; i++) { slowCheck = 0.3; Matter.Body.setPosition(this, Vector.add(this.position, q[i].velocity)) //move with the medium - let dmg = b.dmgScale * 0.5 / Math.sqrt(q[i].mass) + let dmg = b.dmgScale * 0.6 / Math.sqrt(q[i].mass) q[i].damage(dmg); q[i].foundPlayer(); game.drawList.push({ //add dmg to draw queue diff --git a/js/engine.js b/js/engine.js index 9e0e76d..514dcb0 100644 --- a/js/engine.js +++ b/js/engine.js @@ -138,9 +138,12 @@ function collisionChecks(event) { mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles mob[k].foundPlayer(); let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 + if (b.isModPiezo) { + mech.energy = mech.fieldEnergyMax; + dmg *= 0.9 + } mech.damage(dmg); if (mob[k].onHit) mob[k].onHit(k); - if (b.isModPiezo) mech.energy = mech.fieldEnergyMax; if (b.isModAnnihilation && mob[k].dropPowerUp && !mob[k].isShielded) { mob[k].death(); game.drawList.push({ @@ -193,17 +196,19 @@ function collisionChecks(event) { return; } //mob + body collisions - if (obj.classType === "body" && obj.speed > 5) { + if (obj.classType === "body" && obj.speed > 6) { const v = Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)); - if (v > 8) { - let dmg = b.dmgScale * (v * Math.sqrt(obj.mass) * 0.07); + if (v > 9) { + let dmg = b.dmgScale * (v * obj.mass * 0.07); + if (b.isModCrit && !mob[k].seePlayer.recall && !mob[k].shield) dmg *= 5 + if (mob[k].isShielded) dmg *= 0.5 mob[k].damage(dmg, true); if (mob[k].distanceToPlayer2() < 1000000) mob[k].foundPlayer(); game.drawList.push({ //add dmg to draw queue x: pairs[i].activeContacts[0].vertex.x, y: pairs[i].activeContacts[0].vertex.y, - radius: Math.sqrt(dmg) * 40, + radius: Math.log(2 * dmg + 1.1) * 40, color: game.playerDmgColor, time: game.drawTime }); diff --git a/js/level.js b/js/level.js index d4cb228..2a44256 100644 --- a/js/level.js +++ b/js/level.js @@ -14,9 +14,9 @@ const level = { start() { if (level.levelsCleared === 0) { // level.difficultyIncrease(9) - b.giveGuns("minigun") + b.giveGuns("fléchettes") // mech.setField("phase decoherence field") - // b.giveMod("quantum dissipation"); + b.giveMod("irradiated needles"); // b.giveMod("reflective cavity"); // level.intro(); //starting level @@ -129,7 +129,7 @@ const level = { // powerUps.spawn(950, -425, "gun", false); // } - // spawn.nodeBoss(-500, -600, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); + spawn.nodeBoss(-500, -600, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); // spawn.lineBoss(-500, -600, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); // spawn.bodyRect(-135, -50, 50, 50); // spawn.bodyRect(-140, -100, 50, 50); @@ -140,7 +140,7 @@ const level = { // powerUps.spawn(450, -400, "mod", false, 6); // powerUps.spawn(450, -400, "mod", false); // spawn.bodyRect(-45, -100, 40, 50); - spawn.starter(800, -450); + spawn.starter(800, -450, 150); // spawn.cellBoss(400, -750); // spawn.randomLevelBoss(400, -750) diff --git a/js/mobs.js b/js/mobs.js index b20083f..0816df9 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -48,20 +48,57 @@ const mobs = { } } }, - // alert(range) { - // range = range * range; - // for (let i = 0; i < mob.length; i++) { - // if (mob[i].distanceToPlayer2() < range) mob[i].locatePlayer(); - // } - // }, - // startle(amount) { - // for (let i = 0; i < mob.length; i++) { - // if (!mob[i].seePlayer.yes) { - // mob[i].force.x += amount * mob[i].mass * (Math.random() - 0.5); - // mob[i].force.y += amount * mob[i].mass * (Math.random() - 0.5); - // } - // } - // }, + statusSlow(who, cycles = 60) { + //remove other "slow" effects on this mob + let i = who.status.length + while (i--) { + if (who.status[i].type === "slow") who.status.splice(i, 1); + } + //add a new slow effect + who.status.push({ + effect() { + Matter.Body.setVelocity(who, { + x: 0, + y: 0 + }); + Matter.Body.setAngularVelocity(who, 0); + ctx.beginPath(); + ctx.moveTo(who.vertices[0].x, who.vertices[0].y); + for (let j = 1, len = who.vertices.length; j < len; ++j) { + ctx.lineTo(who.vertices[j].x, who.vertices[j].y); + } + ctx.lineTo(who.vertices[0].x, who.vertices[0].y); + ctx.strokeStyle = "rgba(0,100,255,0.5)"; + ctx.lineWidth = 30; + ctx.stroke(); + ctx.fillStyle = who.fill + ctx.fill(); + }, + type: "slow", + endCycle: game.cycle + cycles, + }) + }, + statusDot(who, tickDamage, cycles = 180) { + who.status.push({ + effect() { + if ((game.cycle - this.startCycle) % 30 === 0) { + let dmg = b.dmgScale * tickDamage + who.damage(dmg); + game.drawList.push({ //add dmg to draw queue + x: who.position.x, + y: who.position.y, + radius: Math.log(2 * dmg + 1.1) * 40, + color: game.playerDmgColor, + time: game.drawTime + }); + } + }, + type: "dot", + endCycle: game.cycle + cycles, + startCycle: game.cycle + }) + }, + //********************************************************************************************** //********************************************************************************************** spawn(xPos, yPos, sides, radius, color) { diff --git a/js/player.js b/js/player.js index 4bf9df8..6c46bf6 100644 --- a/js/player.js +++ b/js/player.js @@ -822,20 +822,20 @@ const mech = { mech.fieldCDcycle = mech.cycle + 15; mech.isHolding = false; //bullet-like collisions - mech.holdingTarget.collisionFilter.category = cat.bullet; + mech.holdingTarget.collisionFilter.category = cat.body; //cat.bullet; mech.holdingTarget.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield; //check every second to see if player is away from thrown body, and make solid const solid = function (that) { const dx = that.position.x - player.position.x; const dy = that.position.y - player.position.y; - if (dx * dx + dy * dy > 10000 && that.speed < 3 && that !== mech.holdingTarget) { - that.collisionFilter.category = cat.body; //make solid - that.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; + if (dx * dx + dy * dy > 10000 && that !== mech.holdingTarget) { + // that.collisionFilter.category = cat.body; //make solid + that.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; //can hit player now } else { - setTimeout(solid, 50, that); + setTimeout(solid, 25, that); } }; - setTimeout(solid, 200, mech.holdingTarget); + setTimeout(solid, 150, mech.holdingTarget); //throw speed scales a bit with mass const speed = Math.min(85, Math.min(54 / mech.holdingTarget.mass + 5, 48) * Math.min(mech.throwCharge, mech.throwChargeMax) / 50); diff --git a/js/spawn.js b/js/spawn.js index 44a7bdc..fbc603b 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -142,9 +142,9 @@ const spawn = { Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback me.do = function () { - this.checkStatus() this.seePlayerByLookingAt(); this.attraction(); + this.checkStatus(); }; }, cellBossCulture(x, y, radius = 20, num = 5) { @@ -204,6 +204,7 @@ const spawn = { } } } + this.checkStatus() }; me.onDeath = function () { let count = 0 //count other cells @@ -317,6 +318,7 @@ const spawn = { this.gravity(); this.seePlayerCheck(); this.attraction(); + this.checkStatus(); }; }, grower(x, y, radius = 15) { @@ -328,6 +330,7 @@ const spawn = { this.seePlayerByLookingAt(); this.attraction(); this.grow(); + this.checkStatus(); }; }, springer(x, y, radius = 20 + Math.ceil(Math.random() * 35)) { @@ -376,6 +379,7 @@ const spawn = { me.do = function () { this.gravity(); this.searchSpring(); + this.checkStatus(); }; }, hopper(x, y, radius = 30 + Math.ceil(Math.random() * 30)) { @@ -403,6 +407,7 @@ const spawn = { this.force.x += forceMag * Math.cos(angle); this.force.y += forceMag * Math.sin(angle) - 0.04 * this.mass; //antigravity } + this.checkStatus(); }; }, spinner(x, y, radius = 30 + Math.ceil(Math.random() * 35)) { @@ -457,6 +462,7 @@ const spawn = { } else { this.cdBurst2 = 0; } + this.checkStatus(); }; }, sucker(x, y, radius = 30 + Math.ceil(Math.random() * 70)) { @@ -526,6 +532,7 @@ const spawn = { ctx.fill(); } } + this.checkStatus(); } }, suckerBoss(x, y, radius = 25) { @@ -625,6 +632,7 @@ const spawn = { } this.curl(eventHorizon); } + this.checkStatus(); } }, beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) { @@ -642,6 +650,7 @@ const spawn = { this.repulsion(); //laser beam this.laserBeam(); + this.checkStatus(); }; }, focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) { @@ -705,6 +714,7 @@ const spawn = { this.laserPos = this.position; } }; + this.checkStatus(); } }, laser(x, y, radius = 30) { @@ -721,6 +731,7 @@ const spawn = { this.seePlayerByLookingAt(); this.attraction(); this.laser(); + this.checkStatus(); }; }, laserBoss(x, y, radius = 30) { @@ -762,6 +773,7 @@ const spawn = { ctx.strokeStyle = "rgba(80,0,255,0.07)"; ctx.stroke(); // Draw it // this.laser(this.vertices[2], this.angle + Math.PI / 3); + this.checkStatus(); }; me.laser = function (where, angle) { const vertexCollision = function (v1, v1End, domain) { @@ -869,6 +881,7 @@ const spawn = { this.attraction(); this.gravity(); this.strike(); + this.checkStatus(); }; }, sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 25)) { @@ -885,7 +898,6 @@ const spawn = { me.showHealthBar = false; // me.memory = 420; me.do = function () { - this.seePlayerCheck(); this.attraction(); this.gravity(); @@ -919,6 +931,7 @@ const spawn = { this.canTouchPlayer = false; this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player } + this.checkStatus(); }; }, ghoster(x, y, radius = 40 + Math.ceil(Math.random() * 100)) { @@ -976,6 +989,7 @@ const spawn = { this.canTouchPlayer = false; this.collisionFilter.mask = cat.bullet; //can't touch player or walls } + this.checkStatus(); }; }, // blinker(x, y, radius = 45 + Math.ceil(Math.random() * 70)) { @@ -1046,6 +1060,7 @@ const spawn = { this.hoverOverPlayer(); this.bomb(); this.search(); + this.checkStatus(); }; }, shooter(x, y, radius = 25 + Math.ceil(Math.random() * 50)) { @@ -1067,6 +1082,7 @@ const spawn = { me.do = function () { this.seePlayerByLookingAt(); this.fire(); + this.checkStatus(); }; }, shooterBoss(x, y, radius = 130) { @@ -1100,6 +1116,7 @@ const spawn = { const sub = Vector.sub(this.homePosition, this.position) const dist = Vector.magnitude(sub) if (dist > 50) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002) + this.checkStatus(); }; }, bullet(x, y, radius = 6, sides = 0) { @@ -1145,6 +1162,7 @@ const spawn = { this.gravity(); this.seePlayerCheck(); this.attraction(); + this.checkStatus(); }; }, spawns(x, y, radius = 15 + Math.ceil(Math.random() * 5)) { @@ -1164,6 +1182,7 @@ const spawn = { this.gravity(); this.seePlayerCheck(); this.attraction(); + this.checkStatus(); }; }, exploder(x, y, radius = 25 + Math.ceil(Math.random() * 50)) { @@ -1178,6 +1197,7 @@ const spawn = { this.gravity(); this.seePlayerCheck(); this.attraction(); + this.checkStatus(); }; }, snakeBoss(x, y, radius = 80) { @@ -1196,6 +1216,7 @@ const spawn = { this.seePlayerCheck(); this.attraction(); this.laserBeam(); + this.checkStatus(); }; //snake tail @@ -1237,6 +1258,7 @@ const spawn = { this.gravity(); this.seePlayerCheck(); this.attraction(); + this.checkStatus(); }; }, shield(target, x, y, chance = Math.min(0.02 + game.difficulty * 0.005, 0.2)) { @@ -1274,7 +1296,9 @@ const spawn = { //swap order of shield and mob, so that mob is behind shield graphically mob[mob.length - 1] = mob[mob.length - 2]; mob[mob.length - 2] = me; - me.do = function () {}; + me.do = function () { + this.checkStatus(); + }; } }, bossShield(targets, x, y, radius) { @@ -1314,7 +1338,9 @@ const spawn = { me.showHealthBar = false; mob[mob.length - 1] = mob[mob.length - 1 - nodes]; mob[mob.length - 1 - nodes] = me; - me.do = function () {}; + me.do = function () { + this.checkStatus(); + }; }, //complex constrained mob templates********************************************************************** //******************************************************************************************************* diff --git a/todo.txt b/todo.txt index ca0b045..3efc9d2 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,7 @@ ************** TODO - n-gon ************** -mod - lose your field, gain a gun and some ammo - gain two guns? +mod - lose your field, gain two guns? + lose a random mod, gain a gun? mod - time dilation - Quantum Recovery Expending all your energy while using the field will @@ -24,13 +24,8 @@ mobs - add in a function to the main loops that does injected code for each mob stun - blind, slow, but increased gravity effects mod - flechettes mod for DoT poison damage mod - grenade explosions stun enemies - mod - give crystal minigun a slowing effect and rename it ice crystals mod - vacuum bomb does DoT damage after exploding -mod - get your next recursive mod 3 times - are players aware of what a recursive mod is? - too much of a nova drift rip off? - settings - auto aim at nearest mob settings - custom keys binding