From f3343722819fd0a2e843b8f5eacbf50d2def0942 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sat, 19 Sep 2020 09:11:55 -0700 Subject: [PATCH] cloaking field mod: waste heat recovery is removed mod - fracture analysis only applies to stunned mobs (not unaware mobs) phase field is removed new field: metamaterial cloaking mod: phase decoherence - intangible to mobs while cloaked, but passing through mobs drains energy mod: flashbang - stun mobs as you exit cloak --- js/bullet.js | 52 +++------ js/engine.js | 12 +- js/game.js | 4 +- js/level.js | 94 +++++++++++---- js/mob.js | 39 +++---- js/mods.js | 115 +++++++++++-------- js/player.js | 316 +++++++++++++++++++++++++++++++++++---------------- js/spawn.js | 31 +++-- style.css | 5 + todo.txt | 53 +++++---- 10 files changed, 454 insertions(+), 267 deletions(-) diff --git a/js/bullet.js b/js/bullet.js index 4519c0b..330d332 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -770,11 +770,11 @@ const b = { powerUp.splice(i, 1); if (mod.isDroneGrab) { this.isImproved = true; - const SCALE = 2 + const SCALE = 3.5 Matter.Body.scale(this, SCALE, SCALE); this.lookFrequency = 30; - this.endCycle = Infinity - this.dmg *= 1.5; + this.endCycle += 2000 + // this.dmg *= 1.25; this.frictionAir = 0 } break; @@ -1061,7 +1061,7 @@ const b = { }, onEnd() {}, do() { - if (this.lastLookCycle < game.cycle) { + if (this.lastLookCycle < game.cycle && !mech.isCloak) { this.lastLookCycle = game.cycle + 80 - this.isUpgraded * 50 let target for (let i = 0, len = mob.length; i < len; i++) { @@ -1117,7 +1117,7 @@ const b = { }, onEnd() {}, do() { - if (this.cd < game.cycle && !(game.cycle % this.lookFrequency) && !mech.isStealth) { + if (this.cd < game.cycle && !(game.cycle % this.lookFrequency) && !mech.isCloak) { let target for (let i = 0, len = mob.length; i < len; i++) { const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)); @@ -1186,7 +1186,7 @@ const b = { y: this.velocity.y * 0.95 }); //find targets - if (!(game.cycle % this.lookFrequency) && !mech.isStealth) { + if (!(game.cycle % this.lookFrequency) && !mech.isCloak) { this.lockedOn = null; let closeDist = this.range; for (let i = 0, len = mob.length; i < len; ++i) { @@ -1301,7 +1301,7 @@ const b = { } else if (distanceToPlayer < 250) { //close to player Matter.Body.setVelocity(this, Vector.add(Vector.mult(this.velocity, 0.90), Vector.mult(player.velocity, 0.17))); //add player's velocity //find targets - if (!(game.cycle % this.lookFrequency) && !mech.isStealth) { + if (!(game.cycle % this.lookFrequency) && !mech.isCloak) { this.lockedOn = null; let closeDist = this.range; for (let i = 0, len = mob.length; i < len; ++i) { @@ -1382,7 +1382,6 @@ const b = { const unit = Vector.normalise(sub) const DRAIN = 0.002 if (DIST < mod.isPlasmaRange * 500 && mech.energy > DRAIN) { - console.log('fire') mech.energy -= DRAIN; if (mech.energy < 0) { mech.fieldCDcycle = mech.cycle + 120; @@ -1788,7 +1787,7 @@ const b = { } if (!immune) { this.immuneList.push(who.id) - if (!mech.isStealth) who.foundPlayer(); + who.foundPlayer(); if (mod.isFastDot) { mobs.statusDoT(who, 3.9, 30) } else { @@ -1804,7 +1803,7 @@ const b = { } } else { this.endCycle = 0; - if (!mech.isStealth) who.foundPlayer(); + who.foundPlayer(); if (mod.isFastDot) { mobs.statusDoT(who, 3.78, 30) } else { @@ -1903,7 +1902,7 @@ const b = { for (let i = 0; i < q.length; i++) { let dmg = b.dmgScale * 0.36 / Math.sqrt(q[i].mass) * (mod.waveHelix === 1 ? 1 : 0.66) //1 - 0.4 = 0.6 for helix mod 40% damage reduction q[i].damage(dmg); - if (!mech.isStealth) q[i].foundPlayer(); + q[i].foundPlayer(); game.drawList.push({ //add dmg to draw queue x: this.position.x, y: this.position.y, @@ -1936,7 +1935,7 @@ const b = { Matter.Body.setPosition(this, Vector.add(this.position, q[i].velocity)) //move with the medium let dmg = b.dmgScale * 0.36 / Math.sqrt(q[i].mass) * (mod.waveHelix === 1 ? 1 : 0.66) //1 - 0.4 = 0.6 for helix mod 40% damage reduction q[i].damage(dmg); - if (!mech.isStealth) q[i].foundPlayer(); + q[i].foundPlayer(); game.drawList.push({ //add dmg to draw queue x: this.position.x, y: this.position.y, @@ -2973,34 +2972,9 @@ const b = { nextFireCycle: 0, //use to remember how longs its been since last fire, used to reset count holdDamage: 1, holdCount: 0, + healthLost: 0, fire() { - if (mod.isLaserHealth) { - if (this.nextFireCycle === mech.cycle) { //ramp up damage - this.holdDamage += 0.01 - if (this.holdDamage > 4) this.holdDamage = 4 - this.holdCount += this.holdDamage - if (this.holdCount > 180) { - this.holdCount = 0; - const size = 15 - let dmg = (mod.largerHeals * (size / 40 / Math.sqrt(mod.largerHeals) / (game.healScale ** 0.25)) ** 2) / mech.harmReduction() * game.healScale - if (mech.health < 0.15) { - mech.fireCDcycle = mech.cycle + 120; // fire cool down if about to die - } else { - const totalPowerUps = powerUp.length - powerUps.spawn(mech.pos.x, mech.pos.y, "heal", true, false, size); - mech.damage(dmg, false) - if (powerUp.length > totalPowerUps + 1) { - dmg = (mod.largerHeals * (powerUp[powerUp.length - 1].size / 40 / Math.sqrt(mod.largerHeals) / (game.healScale ** 0.25)) ** 2) / mech.harmReduction() * game.healScale - mech.damage(dmg, false) //do bonus damage if you spawn bonus power ups - } - } - } - } else { - this.holdDamage = 1 - this.holdCount = 0; - } - this.nextFireCycle = mech.cycle + 1 - } + mech.fireCDcycle = mech.cycle const reflectivity = 1 - 1 / (mod.laserReflections * 1.5) let damage = b.dmgScale * mod.laserDamage * this.holdDamage diff --git a/js/engine.js b/js/engine.js index 136e7fc..22bef37 100644 --- a/js/engine.js +++ b/js/engine.js @@ -143,10 +143,7 @@ function collisionChecks(event) { mech.immuneCycle = mech.cycle + mod.collisionImmuneCycles; //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 (mod.isPiezo) { - mech.energy = mech.maxEnergy; - dmg *= 0.85 - } + if (mod.isPiezo) mech.energy = mech.maxEnergy; mech.damage(dmg); if (mod.isBayesian) { const have = [] //find which mods you have @@ -203,8 +200,9 @@ function collisionChecks(event) { //mob + bullet collisions if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) { let dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity))) - if (mod.isCrit && !mob[k].seePlayer.recall && !mob[k].shield) dmg *= 5 - if (!mech.isStealth) mob[k].foundPlayer(); + // console.log(mob[k].seePlayer.recall) + if (mod.isCrit && mob[k].isStunned) dmg *= 5 + mob[k].foundPlayer(); mob[k].damage(dmg); obj.onDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here game.drawList.push({ //add dmg to draw queue @@ -225,7 +223,7 @@ function collisionChecks(event) { mob[k].damage(dmg, true); const stunTime = dmg / Math.sqrt(obj.mass) if (stunTime > 0.5) mobs.statusStun(mob[k], 30 + 60 * Math.sqrt(stunTime)) - if (mob[k].distanceToPlayer2() < 1000000 && !mech.isStealth) mob[k].foundPlayer(); + if (mob[k].distanceToPlayer2() < 1000000 && !mech.isCloak) mob[k].foundPlayer(); game.drawList.push({ x: pairs[i].activeContacts[0].vertex.x, y: pairs[i].activeContacts[0].vertex.y, diff --git a/js/game.js b/js/game.js index 7f91ea0..3084b98 100644 --- a/js/game.js +++ b/js/game.js @@ -476,9 +476,7 @@ const game = { powerUps.directSpawn(game.mouseInGame.x, game.mouseInGame.y, "mod"); } else if (keys[54]) { // 6 spawn mob const pick = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; - spawn.allowShields = false; spawn[pick](game.mouseInGame.x, game.mouseInGame.y); - spawn.allowShields = true; } else if (keys[55]) { // 7 spawn body index = body.length spawn.bodyRect(game.mouseInGame.x, game.mouseInGame.y, 50, 50); @@ -712,8 +710,8 @@ const game = { if (game.isCommunityMaps) { level.levels.push("stronghold"); level.levels.push("basement"); + level.levels.push("newLevel"); level.levels.push("house"); - // level.levels.push("newLevel"); } level.levels = shuffle(level.levels); //shuffles order of maps level.levels.unshift("bosses"); //add bosses level to the end of the randomized levels list diff --git a/js/level.js b/js/level.js index af55bb1..e20f145 100644 --- a/js/level.js +++ b/js/level.js @@ -14,10 +14,10 @@ const level = { // game.enableConstructMode() //used to build maps in testing mode // game.zoomScale = 1000; // game.setZoom(); - // mech.isStealth = true; - // mech.setField("pilot wave") - // b.giveGuns("ice IX") - // mod.giveMod("quantum immortality"); + // mech.isCloak = true; + // mech.setField("metamaterial cloaking") + // b.giveGuns("laser") + // mod.giveMod("phase decoherence"); level.intro(); //starting level // level.testing(); //not in rotation @@ -53,13 +53,14 @@ const level = { game.draw.setPaths(); b.respawnBots(); if (mod.isArmorFromPowerUps) { - mech.maxHealth += 0.05 * powerUps.totalPowerUps + mod.armorFromPowerUps += 0.05 * powerUps.totalPowerUps + mech.setMaxHealth(); if (powerUps.totalPowerUps) game.makeTextLog(" max health increased by " + (0.05 * powerUps.totalPowerUps * 100).toFixed(0) + "%", 300) } if (mod.isHealLowHealth) { const len = Math.floor((mech.maxHealth - mech.health) / 0.5) for (let i = 0; i < len; i++) { - powerUps.spawn(mech.pos.x, mech.pos.y, "heal", false); + powerUps.spawn(mech.pos.x + 60 * (Math.random() - 0.5), mech.pos.y + 60 * (Math.random() - 0.5), "heal", false); } } if (mod.isGunCycle) { @@ -142,7 +143,7 @@ const level = { // spawn.sniper(1800, -120) // spawn.sniper(2200, -120) // spawn.cellBossCulture(1600, -500) - // spawn.starter(1600, -500, 60) + spawn.starter(1600, -500, 60) // spawn.powerUpBoss(1600, -500) // spawn.shield(mob[mob.length - 1], 1200, -500, 1); @@ -221,8 +222,8 @@ const level = { y: -600 }, -2 * Math.PI / 3) //up left - const hazard = level.hazard(350, -2025, 700, 10, 0.4, "hsl(0, 100%, 50%)") //laser - const hazard2 = level.hazard(1775, -2550, 150, 10, 0.4, "hsl(0, 100%, 50%)") //laser + const hazard = level.hazard(350, -2025, 700, 10, 0.4, "hsl(0, 100%, 50%)", true) //laser + const hazard2 = level.hazard(1775, -2550, 150, 10, 0.4, "hsl(0, 100%, 50%)", true) //laser const button = level.button(2100, -2600) @@ -1484,6 +1485,8 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00007 }); + World.add(engine.world, cons[cons.length - 1]); + if (game.difficulty > 4) spawn.nodeBoss(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss } else if (Math.random() < 0.15) { spawn.randomLevelBoss(4250, -250); @@ -1699,6 +1702,37 @@ const level = { height: 275, color: "#cff" }); + level.fillBG.push({ + x: -3375, + y: -2875, + width: 25, + height: 725, + color: "#d0d0d2" + }); + level.fillBG.push({ + x: -2975, + y: -2750, + width: 25, + height: 600, + color: "#d0d0d2" + }); + level.fillBG.push({ + x: -2475, + y: -2450, + width: 25, + height: 750, + color: "#d0d0d2" + }); + + //3 platforms that lead to exit + spawn.mapRect(-3440, -2875, 155, 25); + spawn.mapRect(-3025, -2775, 125, 25); + spawn.mapRect(-2525, -2475, 125, 25); + spawn.bodyRect(-2600, -2500, 225, 20, 0.7); + spawn.bodyRect(-3350, -2900, 25, 25, 0.5); + spawn.bodyRect(-3400, -2950, 50, 75, 0.5); + + //foreground level.fill.push({ x: -1650, @@ -1709,11 +1743,12 @@ const level = { }); level.fill.push({ x: -2600, - y: -2400, + y: -1675, width: 450, - height: 1800, + height: 1125, color: "rgba(0,0,0,0.12)" }); + level.fill.push({ x: -3425, y: -2150, @@ -1781,7 +1816,7 @@ const level = { spawn.mapRect(-3450, -1325, 550, 50); spawn.mapRect(-3425, -2200, 525, 50); spawn.mapRect(-2600, -1700, 450, 50); - spawn.mapRect(-2600, -2450, 450, 50); + // spawn.mapRect(-2600, -2450, 450, 50); spawn.bodyRect(-2275, -2700, 50, 60); spawn.bodyRect(-2600, -1925, 250, 225); spawn.bodyRect(-3415, -1425, 100, 100); @@ -1799,6 +1834,7 @@ const level = { spawn.bodyRect(-3080, -2250, 40, 40); spawn.bodyRect(-3420, -650, 50, 50); + //exit spawn.mapRect(-4450, -3075, 25, 300); spawn.mapRect(-4450, -3075, 450, 25); @@ -1831,7 +1867,8 @@ const level = { spawn.randomMob(-550, -100, -0.1); spawn.randomBoss(-3250, -2700, 0.2); spawn.randomBoss(-2450, -1100, 0); - if (game.difficulty > 3) spawn.randomLevelBoss(-3400, -2800); + + if (game.difficulty > 3) spawn.randomLevelBoss(-2400, -3000); powerUps.addRerollToLevel() //needs to run after mobs are spawned }, warehouse() { @@ -1930,6 +1967,7 @@ const level = { stiffness: 0.0001815, length: 1 }); + World.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(600, 525, 125, 125, 1, spawn.propsSlide); //weight spawn.bodyRect(800, 600, 300, 100, 1, spawn.propsHoist); //hoist @@ -1942,6 +1980,7 @@ const level = { stiffness: 0.0001815, length: 1 }); + World.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight spawn.bodyRect(-2550, 1150, 200, 100, 1, spawn.propsSlide); //weight @@ -1955,6 +1994,7 @@ const level = { stiffness: 0.0005, length: 566 }); + World.add(engine.world, cons[cons.length - 1]); //blocks spawn.bodyRect(-165, -150, 30, 35, 1); @@ -2130,6 +2170,7 @@ const level = { bodyB: map[map.length - 1], stiffness: 1 }); + World.add(engine.world, consBB[consBB.length - 1]); spawn.mapRect(-600 + 300, -2000 * 0.75, 1900, 50); //3rd floor spawn.mapRect(-600 + 2000 * 0.7, -2000 * 0.74, 50, 375); //center wall spawn.bodyRect(-600 + 2000 * 0.7, -2000 * 0.5 - 106, 50, 106); //center block under wall @@ -2194,6 +2235,7 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00012 }); + World.add(engine.world, cons[cons.length - 1]); //chance to spawn a ring of exploding mobs around this boss if (game.difficulty > 6) spawn.nodeBoss(2850, -80, "spawns", 8, 20, 105); } else { @@ -2356,6 +2398,7 @@ const level = { stiffness: 0.0002, //1217, length: 200 }); + World.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(2799, -870, 310, 290); //Gros bloc angle toit spawn.mapRect(4000, -1750, 50, 400); //Right Wall Cuve @@ -2406,7 +2449,7 @@ const level = { bodyB: map[map.length - 1], stiffness: 1 }); - + World.add(engine.world, consBB[consBB.length - 1]); spawn.bodyRect(650, 50, 70, 50); spawn.bodyRect(300, 0, 100, 60); spawn.bodyRect(400, 0, 100, 150); @@ -2587,6 +2630,7 @@ const level = { stiffness: 0.00014, length: 120 }); + World.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(0, -1250, 240, 190) //Fat cube ascenseur } else { /// Reversed spawn spawn.bodyRect(0, -650, 225, 175); @@ -2666,6 +2710,7 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00006 }); + World.add(engine.world, cons[cons.length - 1]); if (game.difficulty > 4) spawn.nodeBoss(7000, -3300, "spawns", 8, 20, 105); } else if (game.difficulty > 3) { spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss"]); @@ -2684,6 +2729,7 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00036 }); + World.add(engine.world, cons[cons.length - 1]); if (game.difficulty > 4) spawn.nodeBoss(2350, -1300, "spawns", 8, 20, 105); } else if (game.difficulty > 3) { spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "snakeBoss"]); @@ -2759,6 +2805,7 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00017 }); + World.add(engine.world, cons[cons.length - 1]); //chance to spawn a ring of exploding mobs around this boss if (game.difficulty > 4) spawn.nodeBoss(2330, 1850, "spawns", 8, 20, 105); powerUps.spawn(3010, 1630, "mod"); @@ -3193,6 +3240,7 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00015 }); + World.add(engine.world, cons[cons.length - 1]); if (game.difficulty > 4) spawn.nodeBoss(8000, 630, "spawns", 8, 20, 105); } else if (game.difficulty > 3) { spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss"]); @@ -3768,6 +3816,7 @@ const level = { bodyB: mob[mob.length - 1], stiffness: 0.00018 + 0.000007 * level.levelsCleared }); + World.add(engine.world, cons[cons.length - 1]); if (game.difficulty > 4) spawn.nodeBoss(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss } else { @@ -4003,12 +4052,10 @@ const level = { Matter.Body.setStatic(map[i], true); //make static World.add(engine.world, map[i]); //add to world } - for (let i = 0; i < cons.length; i++) { - World.add(engine.world, cons[i]); - } - for (let i = 0; i < consBB.length; i++) { - World.add(engine.world, consBB[i]); - } + // for (let i = 0; i < cons.length; i++) { + // World.add(engine.world, cons[i]); + // } + }, spinner(x, y, width, height, density = 0.001) { x = x + width / 2 @@ -4404,7 +4451,7 @@ const level = { mapB.portalPair = mapA return [portalA, portalB, mapA, mapB] }, - hazard(x, y, width, height, damage = 0.0005, color = "hsla(160, 100%, 35%,0.75)") { + hazard(x, y, width, height, damage = 0.0005, color = "hsla(160, 100%, 35%,0.75)", isOptical = false) { return { min: { x: x, @@ -4419,7 +4466,7 @@ const level = { maxHeight: height, isOn: true, query() { - if (this.isOn && this.height > 0 && Matter.Query.region([player], this).length && !mech.isStealth) { + if (this.isOn && this.height > 0 && Matter.Query.region([player], this).length && !(mech.isCloak && isOptical)) { if (damage < 0.02) { mech.damage(damage) } else if (mech.immuneCycle < mech.cycle) { @@ -4480,6 +4527,7 @@ const level = { stiffness: stiffness, damping: damping }); + World.add(engine.world, consBB[consBB.length - 1]); } cons[cons.length] = Constraint.create({ //pin first block to a point in space pointA: { @@ -4490,6 +4538,7 @@ const level = { stiffness: 1, damping: damping }); + World.add(engine.world, cons[cons.length - 1]); if (isAttached) { cons[cons.length] = Constraint.create({ //pin last block to a point in space pointA: { @@ -4500,6 +4549,7 @@ const level = { stiffness: 1, damping: damping }); + World.add(engine.world, cons[cons.length - 1]); } }, }; \ No newline at end of file diff --git a/js/mob.js b/js/mob.js index 9d547b7..cabc1ea 100644 --- a/js/mob.js +++ b/js/mob.js @@ -292,13 +292,16 @@ const mobs = { this.seePlayer.position.x = player.position.x; this.seePlayer.position.y = player.position.y; }, - // locatePlayerByDist() { - // if (this.distanceToPlayer2() < this.locateRange) { - // this.locatePlayer(); - // } - // }, + alertNearByMobs() { + //this.alertRange2 is set at the very bottom of this mobs, after mob is made + for (let i = 0; i < mob.length; i++) { + if (!mob[i].seePlayer.recall && Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < this.alertRange2) { + mob[i].locatePlayer(); + } + } + }, alwaysSeePlayer() { - if (!mech.isStealth) { + if (!mech.isCloak) { this.seePlayer.recall = true; this.seePlayer.position.x = player.position.x; this.seePlayer.position.y = player.position.y; @@ -310,7 +313,7 @@ const mobs = { this.distanceToPlayer2() < this.seeAtDistance2 && Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 && - !mech.isStealth + !mech.isCloak ) { this.foundPlayer(); } else if (this.seePlayer.recall) { @@ -320,7 +323,7 @@ const mobs = { }, seePlayerCheckByDistance() { if (!(game.cycle % this.seePlayerFreq)) { - if (this.distanceToPlayer2() < this.seeAtDistance2 && !mech.isStealth) { + if (this.distanceToPlayer2() < this.seeAtDistance2 && !mech.isCloak) { this.foundPlayer(); } else if (this.seePlayer.recall) { this.lostPlayer(); @@ -331,7 +334,7 @@ const mobs = { if (!(game.cycle % this.seePlayerFreq)) { if ( (this.distanceToPlayer2() < this.seeAtDistance2 || (Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0)) && - !mech.isStealth + !mech.isCloak ) { this.foundPlayer(); } else if (this.seePlayer.recall) { @@ -363,7 +366,7 @@ const mobs = { this.distanceToPlayer2() < this.seeAtDistance2 && Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 && - !mech.isStealth + !mech.isCloak ) { this.foundPlayer(); } else if (this.seePlayer.recall) { @@ -411,7 +414,7 @@ const mobs = { if (game.cycle % 7 && this.seePlayer.yes) { ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); // ctx.lineDashOffset = 6*(game.cycle % 215); - if (this.distanceToPlayer() < this.laserRange && !mech.isStealth) { + if (this.distanceToPlayer() < this.laserRange) { if (mech.immuneCycle < mech.cycle) mech.damage(0.0003 * game.dmgScale); if (mech.energy > 0.1) mech.energy -= 0.003 ctx.beginPath(); @@ -497,7 +500,7 @@ const mobs = { }; vertexCollision(this.position, look, map); vertexCollision(this.position, look, body); - if (!mech.isStealth) vertexCollision(this.position, look, [player]); + if (!mech.isCloak) vertexCollision(this.position, look, [player]); // hitting player if (best.who === player) { if (mech.immuneCycle < mech.cycle) { @@ -538,7 +541,7 @@ const mobs = { this.distanceToPlayer2() < this.seeAtDistance2 && Matter.Query.ray(map, this.position, player.position).length === 0 && Matter.Query.ray(body, this.position, player.position).length === 0 && - !mech.isStealth + !mech.isCloak ) { this.foundPlayer(); } else if (this.seePlayer.recall) { @@ -644,14 +647,6 @@ const mobs = { } } }, - alertNearByMobs() { - //this.alertRange2 is set at the very bottom of this mobs, after mob is made - for (let i = 0; i < mob.length; i++) { - if (!mob[i].seePlayer.recall && Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < this.alertRange2) { - mob[i].locatePlayer(); - } - } - }, curl(range = 1000, mag = -10) { //cause all mobs, and bodies to rotate in a circle applyCurl = function (center, array, isAntiGravity = true) { @@ -1049,7 +1044,7 @@ const mobs = { } } if (Math.random() < mod.isBotSpawner) b.randomBot(this.position, false) - if (mod.isExplodeMob) b.explosion(this.position, Math.min(425, Math.sqrt(this.mass + 3) * 70)) + if (mod.isExplodeMob) b.explosion(this.position, Math.min(550, Math.sqrt(this.mass + 2.5) * 50)) if (mod.nailsDeathMob) b.targetedNail(this.position, mod.nailsDeathMob, 40 + 7 * Math.random()) } else if (mod.isShieldAmmo && this.shield) { let type = "ammo" diff --git a/js/mods.js b/js/mods.js index bb54395..816d333 100644 --- a/js/mods.js +++ b/js/mods.js @@ -5,6 +5,7 @@ const mod = { mod.mods[i].remove(); mod.mods[i].count = 0 } + mod.armorFromPowerUps = 0; mod.totalCount = 0; game.updateModHUD(); }, @@ -37,6 +38,7 @@ const mod = { } if (!found) return //if name not found don't give any mod } + if (mod.mods[index].isLost) mod.mods[index].isLost = false; //give specific mod mod.mods[index].effect(); //give specific mod mod.mods[index].count++ mod.totalCount++ //used in power up randomization @@ -78,7 +80,7 @@ const mod = { return false }, damageFromMods() { - let dmg = 1 + let dmg = mech.fieldDamage if (mod.isEnergyNoAmmo) dmg *= 1.4 if (mod.isDamageForGuns) dmg *= 1 + 0.07 * b.inventory.length if (mod.isLowHealthDmg) dmg *= 1 + 0.6 * Math.max(0, 1 - mech.health) @@ -112,7 +114,6 @@ const mod = { } }, { name: "capacitor", - // nameInfo: "", description: "increase damage by 1%
for every 5.5% stored energy", maxCount: 1, count: 0, @@ -121,7 +122,7 @@ const mod = { }, requires: "increased energy regen or max energy", effect: () => { - mod.isEnergyDamage = true // used in mech.grabPowerUp + mod.isEnergyDamage = true }, remove() { mod.isEnergyDamage = false; @@ -161,7 +162,6 @@ const mod = { }, { name: "rest frame", - // nameInfo: "", description: "increase damage by 20%
when not moving", maxCount: 1, count: 0, @@ -170,7 +170,7 @@ const mod = { }, requires: "", effect: () => { - mod.isRest = true // used in mech.grabPowerUp + mod.isRest = true }, remove() { mod.isRest = false; @@ -756,7 +756,7 @@ const mod = { }, requires: "", effect() { - mod.collisionImmuneCycles += 60; + mod.collisionImmuneCycles += 55; mech.immuneCycle = mech.cycle + mod.collisionImmuneCycles; //player is immune to collision damage for 30 cycles }, remove() { @@ -818,7 +818,7 @@ const mod = { maxCount: 1, count: 0, allowed() { - return mod.superposition || mod.isStunField || mod.isPulseStun || mod.isNeutronStun || mod.oneSuperBall || mod.isHarmFreeze || mod.isIceField || mod.isIceCrystals || mod.isSporeFreeze || mod.isAoESlow || mod.isFreezeMobs || mod.isPilotFreeze || mod.haveGunCheck("ice IX") + return mod.isStunField || mod.isPulseStun || mod.isNeutronStun || mod.oneSuperBall || mod.isHarmFreeze || mod.isIceField || mod.isIceCrystals || mod.isSporeFreeze || mod.isAoESlow || mod.isFreezeMobs || mod.isPilotFreeze || mod.haveGunCheck("ice IX") }, requires: "a freezing or stunning effect", effect() { @@ -830,7 +830,7 @@ const mod = { }, { name: "piezoelectricity", - description: "colliding with mobs fills your energy
15% less harm from mob collisions", + description: "colliding with mobs fills your energy
reduce harm by 15%", maxCount: 1, count: 0, allowed() { @@ -982,12 +982,14 @@ const mod = { }, requires: "not mass-energy equivalence", effect() { - mech.maxHealth += 0.50 + mod.bonusHealth += 0.5 mech.addHealth(0.50) + mech.setMaxHealth(); }, remove() { - mech.maxHealth = 1; - mech.displayHealth(); + mod.bonusHealth = 0 + mech.setMaxHealth(); + } }, { @@ -996,14 +998,16 @@ const mod = { maxCount: 1, count: 0, allowed() { - return !mod.isEnergyHealth && !mod.isDroneGrab + return !mod.isEnergyHealth }, requires: "not mass-energy equivalence", effect() { - mod.isArmorFromPowerUps = true; + mod.isArmorFromPowerUps = true; //tracked by mod.armorFromPowerUps }, remove() { mod.isArmorFromPowerUps = false; + // mod.armorFromPowerUps = 0; //this is now reset in mod.setupAllMods(); + mech.setMaxHealth(); } }, { @@ -2023,7 +2027,7 @@ const mod = { }, { name: "harvester", - description: "after a drone picks up a power up,
it's larger, faster, and infinitely durable", + description: "after a drone picks up a power up,
it's larger, faster, and very durable", maxCount: 1, count: 0, allowed() { @@ -2203,22 +2207,22 @@ const mod = { mod.laserFieldDrain = 0.0016; } }, - { - name: "waste heat recovery", - description: "laser damage grows by 400% as you fire
but you periodically eject your health", - maxCount: 1, - count: 0, - allowed() { - return mod.haveGunCheck("laser") - }, - requires: "laser", - effect() { - mod.isLaserHealth = true; - }, - remove() { - mod.isLaserHealth = false - } - }, + // { + // name: "waste heat recovery", + // description: "laser damage grows by 400% as you fire
but you periodically eject your health", + // maxCount: 1, + // count: 0, + // allowed() { + // return mod.haveGunCheck("laser") && !mod.isEnergyHealth + // }, + // requires: "laser
not mass-energy equivalence", + // effect() { + // mod.isLaserHealth = true; + // }, + // remove() { + // mod.isLaserHealth = false + // } + // }, { name: "shock wave", description: "mobs caught in pulse's explosion are stunned
for up to 2 seconds", @@ -2272,6 +2276,22 @@ const mod = { mod.isStunField = 0; } }, + { + name: "fracture analysis", + description: "bullet impacts do 500% damage
to stunned mobs", + maxCount: 1, + count: 0, + allowed() { + return mod.isStunField || mod.oneSuperBall || mod.isCloakStun + }, + requires: "flux pinning or super ball
or flashbang", + effect() { + mod.isCrit = true; + }, + remove() { + mod.isCrit = false; + } + }, { name: "timelike world line", description: "time dilation doubles your relative time rate
and makes you immune to harm", @@ -2451,7 +2471,7 @@ const mod = { maxCount: 1, count: 0, allowed() { - return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && !(mod.isMissileField || mod.isIceField || mod.isFastDrones) + return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && !(mod.isMissileField || mod.isIceField || mod.isFastDrones || mod.isDroneGrab) }, requires: "nano-scale manufacturing", effect() { @@ -2467,7 +2487,7 @@ const mod = { maxCount: 1, count: 0, allowed() { - return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && !(mod.isSporeField || mod.isIceField || mod.isFastDrones) + return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && !(mod.isSporeField || mod.isIceField || mod.isFastDrones || mod.isDroneGrab) }, requires: "nano-scale manufacturing", effect() { @@ -2483,7 +2503,7 @@ const mod = { maxCount: 1, count: 0, allowed() { - return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && !(mod.isSporeField || mod.isMissileField || mod.isFastDrones) + return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && !(mod.isSporeField || mod.isMissileField || mod.isFastDrones || mod.isDroneGrab) }, requires: "nano-scale manufacturing", effect() { @@ -2494,35 +2514,35 @@ const mod = { } }, { - name: "superposition", - description: "mobs that touch the phased player
are stunned for 5 seconds", + name: "phase decoherence", + description: "become intangible while cloaked
but, passing through mobs drains your energy", maxCount: 1, count: 0, allowed() { - return mech.fieldUpgrades[mech.fieldMode].name === "phase decoherence field" + return mech.fieldUpgrades[mech.fieldMode].name === "metamaterial cloaking" }, - requires: "phase decoherence field", + requires: "metamaterial cloaking", effect() { - mod.superposition = true; + mod.isIntangible = true; }, remove() { - mod.superposition = false; + mod.isIntangible = false; } }, { - name: "fracture analysis", - description: "bullet impacts do 500% damage
to mobs that are unaware of you or stunned", + name: "flashbang", + description: "decloaking stuns nearby mobs for 2 second", maxCount: 1, count: 0, allowed() { - return mod.isStunField || mech.fieldUpgrades[mech.fieldMode].name === "phase decoherence field" + return mech.fieldUpgrades[mech.fieldMode].name === "metamaterial cloaking" }, - requires: "phase decoherence field or flux pinning", + requires: "metamaterial cloaking", effect() { - mod.isCrit = true; + mod.isCloakStun = true; }, remove() { - mod.isCrit = false; + mod.isCloakStun = false; } }, { @@ -2760,5 +2780,8 @@ const mod = { isFreezeHarmImmune: null, isSmallExplosion: null, isExplosionHarm: null, - isLaserHealth: null + armorFromPowerUps: null, + bonusHealth: null, + isIntangible: null, + isCloakStun: null } \ No newline at end of file diff --git a/js/player.js b/js/player.js index 70a1a5c..93eaf71 100644 --- a/js/player.js +++ b/js/player.js @@ -469,12 +469,19 @@ const mech = { mech.displayHealth(); } }, + baseHealth: 1, + setMaxHealth() { + mech.maxHealth = mech.baseHealth + mod.bonusHealth + mod.armorFromPowerUps + if (mech.health > mech.maxHealth) mech.health = mech.maxHealth; + mech.displayHealth(); + }, defaultFPSCycle: 0, //tracks when to return to normal fps immuneCycle: 0, //used in engine harmReduction() { let dmg = 1 dmg *= mech.fieldHarmReduction - dmg *= mod.isSlowFPS ? 0.85 : 1 + if (mod.isSlowFPS) dmg *= 0.85 + if (mod.isPiezo) dmg *= 0.85 if (mod.isHarmReduce && mech.fieldUpgrades[mech.fieldMode].name === "negative mass field" && mech.isFieldActive) dmg *= 0.6 if (mod.isBotArmor) dmg *= 0.95 ** mod.totalBots() if (mod.isHarmArmor && mech.lastHarmCycle + 600 > mech.cycle) dmg *= 0.5; @@ -487,7 +494,7 @@ const mech = { } return dmg }, - damage(dmg, isShowRed = true) { + damage(dmg) { mech.lastHarmCycle = mech.cycle if (mod.isDroneOnDamage) { //chance to build a drone on damage from mod const len = Math.min((dmg - 0.06 * Math.random()) * 40, 40) @@ -552,10 +559,8 @@ const mech = { } } mech.displayHealth(); - if (isShowRed) { - document.getElementById("dmg").style.transition = "opacity 0s"; - document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); - } + document.getElementById("dmg").style.transition = "opacity 0s"; + document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); } if (dmg > 0.06 / mech.holdingMassScale) mech.drop(); //drop block if holding @@ -583,7 +588,7 @@ const mech = { } } } else { - if (dmg > 0.05 && isShowRed) { // freeze game for high damage hits + if (dmg > 0.05) { // freeze game for high damage hits game.fpsCap = 4 //40 - Math.min(25, 100 * dmg) game.fpsInterval = 1000 / game.fpsCap; } else { @@ -702,7 +707,7 @@ const mech = { index: 0 }, isHolding: false, - isStealth: false, + isCloak: false, throwCharge: 0, fireCDcycle: 0, fieldCDcycle: 0, @@ -715,6 +720,7 @@ const mech = { isFieldActive: false, fieldRange: 155, fieldShieldingScale: 1, + fieldDamage: 1, energy: 0, fieldRegen: 0, fieldMode: 0, @@ -734,11 +740,12 @@ const mech = { mech.fieldBlockCD = 10; game.isBodyDamage = true; mech.fieldHarmReduction = 1; + mech.fieldDamage = 1 mech.grabPowerUpRange2 = 156000; mech.fieldRange = 155; mech.fieldFire = false; mech.fieldCDcycle = 0; - mech.isStealth = false; + mech.isCloak = false; player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield mech.airSpeedLimit = 125 mech.drop(); @@ -849,6 +856,7 @@ const mech = { if (mech.holdingTarget) { if (keys[32] || game.mouseDownRight) { if (mech.energy > 0.001) { + mech.fireCDcycle = mech.cycle mech.energy -= 0.001 / mod.throwChargeRate; mech.throwCharge += 0.5 * mod.throwChargeRate / mech.holdingTarget.mass //draw charge @@ -1392,7 +1400,7 @@ const mech = { }, { name: "negative mass field", - description: "use energy to nullify   gravity
reduce harm by 45%
blocks held by the field have a lower mass", + description: "use energy to nullify  gravity
reduce harm by 45%
blocks held by the field have a lower mass", fieldDrawRadius: 0, effect: () => { mech.fieldFire = true; @@ -1759,22 +1767,59 @@ const mech = { } }, { - name: "phase decoherence field", - description: "use energy to become intangible
firing and touching shields drains energy
unable to see and be seen by mobs", + name: "metamaterial cloaking", //"weak photonic coupling" "electromagnetically induced transparency" "optical non-coupling" "slow light field" "electro-optic transparency" + description: "cloak after not using your gun or field
while cloaked mobs can't see you
increase damage by 33%", effect: () => { mech.fieldFire = true; mech.fieldMeterColor = "#fff"; mech.fieldPhase = 0; + mech.isCloak = false + mech.fieldDamage = 1.33 mech.hold = function () { + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throwBlock(); + if (mech.fireCDcycle < mech.cycle) mech.fireCDcycle = mech.cycle //to disable cloak + } else if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold and field button is pressed + mech.grabPowerUp(); + mech.lookForPickUp(); + if (mech.fireCDcycle < mech.cycle) mech.fireCDcycle = mech.cycle - 40 //to disable cloak + } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding target exists, and field button is not pressed + mech.pickUp(); + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + } + + //120 cycles after shooting (or using field) enable cloak + if (mech.energy < 0.05 && mech.fireCDcycle < mech.cycle) mech.fireCDcycle = mech.cycle + if (mech.fireCDcycle + 50 < mech.cycle) { + if (!mech.isCloak) mech.isCloak = true + } else { + if (mech.isCloak) { + mech.isCloak = false + if (mod.isCloakStun) { //stun nearby mobs after exiting cloak + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, 800, 0, 2 * Math.PI); + ctx.fillStyle = "#000" + ctx.fill(); + for (let i = 0, len = mob.length; i < len; ++i) { + if (Vector.magnitude(Vector.sub(mob[i].position, mech.pos)) < 850) { + mobs.statusStun(mob[i], 120) + } + } + } + } + } + function drawField(radius) { - radius *= Math.min(4, 0.9 + 2.2 * mech.energy * mech.energy); - const rotate = mech.cycle * 0.005; - mech.fieldPhase += 0.5 - 0.5 * Math.sqrt(Math.max(0.01, Math.min(mech.energy, 1))); - const off1 = 1 + 0.06 * Math.sin(mech.fieldPhase); - const off2 = 1 - 0.06 * Math.sin(mech.fieldPhase); + const energy = Math.max(0.01, Math.min(mech.energy, 1)) + radius *= Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy)); + mech.fieldPhase += 0.007 + 0.07 * (1 - energy) + const wiggle = 0.15 * Math.sin(mech.fieldPhase * 0.5) ctx.beginPath(); - ctx.ellipse(mech.pos.x, mech.pos.y, radius * off1, radius * off2, rotate, 0, 2 * Math.PI); + ctx.ellipse(mech.pos.x, mech.pos.y, radius * (1 - wiggle), radius * (1 + wiggle), mech.fieldPhase, 0, 2 * Math.PI); if (mech.fireCDcycle > mech.cycle && (keys[32] || game.mouseDownRight)) { ctx.lineWidth = 5; ctx.strokeStyle = `rgba(0, 204, 255,1)` @@ -1787,94 +1832,36 @@ const mech = { ctx.clip(); } - mech.isStealth = false //isStealth disables most uses of foundPlayer() - player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions - if (mech.isHolding) { - if (this.fieldRange < 2000) { - this.fieldRange += 100 + if (mech.isCloak) { + this.fieldRange = this.fieldRange * 0.9 + 0.1 * 800 + drawField(this.fieldRange) + } else { + if (this.fieldRange < 3000) { + this.fieldRange += 200 drawField(this.fieldRange) } - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throwBlock(); - } else if (keys[32] || game.mouseDownRight) { - mech.grabPowerUp(); - mech.lookForPickUp(); - - if (mech.fieldCDcycle < mech.cycle) { - // game.draw.bodyFill = "transparent" - // game.draw.bodyStroke = "transparent" - - const DRAIN = 0.00013 + (mech.fireCDcycle > mech.cycle ? 0.005 : 0) - if (mech.energy > DRAIN) { - mech.energy -= DRAIN; - // if (mech.energy < 0.001) { - // mech.fieldCDcycle = mech.cycle + 120; - // mech.energy = 0; - // mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - // } - this.fieldRange = this.fieldRange * 0.8 + 0.2 * 160 - drawField(this.fieldRange) - - mech.isStealth = true //isStealth disables most uses of foundPlayer() - player.collisionFilter.mask = cat.map - - - let inPlayer = Matter.Query.region(mob, player.bounds) - if (inPlayer.length > 0) { - for (let i = 0; i < inPlayer.length; i++) { - if (inPlayer[i].shield) { - mech.energy -= 0.005; //shields drain player energy - //draw outline of shield - ctx.fillStyle = `rgba(140,217,255,0.5)` - ctx.fill() - } else if (mod.superposition && inPlayer[i].dropPowerUp) { - // inPlayer[i].damage(0.4 * b.dmgScale); //damage mobs inside the player - // mech.energy += 0.005; - - mobs.statusStun(inPlayer[i], 300) - //draw outline of mob in a few random locations to show blurriness - const vertices = inPlayer[i].vertices; - const off = 30 - for (let k = 0; k < 3; k++) { - const xOff = off * (Math.random() - 0.5) - const yOff = off * (Math.random() - 0.5) - ctx.beginPath(); - ctx.moveTo(xOff + vertices[0].x, yOff + vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(xOff + vertices[j].x, yOff + vertices[j].y); - } - ctx.lineTo(xOff + vertices[0].x, yOff + vertices[0].y); - ctx.fillStyle = "rgba(0,0,0,0.1)" - ctx.fill() - } - break; + } + if (mod.isIntangible) { + if (mech.isCloak) { + player.collisionFilter.mask = cat.map + let inPlayer = Matter.Query.region(mob, player.bounds) + if (inPlayer.length > 0) { + for (let i = 0; i < inPlayer.length; i++) { + if (mech.energy > 0) { + if (inPlayer[i].shield) { //shields drain player energy + mech.energy -= 0.02; + } else { + mech.energy -= 0.007; } } } - } else { - mech.fieldCDcycle = mech.cycle + 120; - mech.energy = 0; - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - drawField(this.fieldRange) } + } else { + player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions } - } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released - mech.pickUp(); - if (this.fieldRange < 2000) { - this.fieldRange += 100 - drawField(this.fieldRange) - } - } else { - // this.fieldRange = 3000 - if (this.fieldRange < 2000 && mech.holdingTarget === null) { - this.fieldRange += 100 - drawField(this.fieldRange) - } - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - if (mech.energy < mech.maxEnergy) { + if (mech.energy < mech.maxEnergy) { // replaces mech.drawFieldMeter() with custom code mech.energy += mech.fieldRegen; const xOff = mech.pos.x - mech.radius * mech.maxEnergy const yOff = mech.pos.y - 50 @@ -1888,10 +1875,143 @@ const mech = { ctx.lineWidth = 1; ctx.stroke(); } - if (mech.energy < 0) mech.energy = 0 } } }, + // { + // name: "phase decoherence field", + // description: "use energy to become intangible
firing and touching shields drains energy
unable to see and be seen by mobs", + // effect: () => { + // mech.fieldFire = true; + // mech.fieldMeterColor = "#fff"; + // mech.fieldPhase = 0; + + // mech.hold = function () { + // function drawField(radius) { + // radius *= Math.min(4, 0.9 + 2.2 * mech.energy * mech.energy); + // const rotate = mech.cycle * 0.005; + // mech.fieldPhase += 0.5 - 0.5 * Math.sqrt(Math.max(0.01, Math.min(mech.energy, 1))); + // const off1 = 1 + 0.06 * Math.sin(mech.fieldPhase); + // const off2 = 1 - 0.06 * Math.sin(mech.fieldPhase); + // ctx.beginPath(); + // ctx.ellipse(mech.pos.x, mech.pos.y, radius * off1, radius * off2, rotate, 0, 2 * Math.PI); + // if (mech.fireCDcycle > mech.cycle && (keys[32] || game.mouseDownRight)) { + // ctx.lineWidth = 5; + // ctx.strokeStyle = `rgba(0, 204, 255,1)` + // ctx.stroke() + // } + // ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*mech.energy})`; + // ctx.globalCompositeOperation = "destination-in"; //in or atop + // ctx.fill(); + // ctx.globalCompositeOperation = "source-over"; + // ctx.clip(); + // } + + // mech.isCloak = false //isCloak disables most uses of foundPlayer() + // player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions + // if (mech.isHolding) { + // if (this.fieldRange < 2000) { + // this.fieldRange += 100 + // drawField(this.fieldRange) + // } + // mech.drawHold(mech.holdingTarget); + // mech.holding(); + // mech.throwBlock(); + // } else if (keys[32] || game.mouseDownRight) { + // mech.grabPowerUp(); + // mech.lookForPickUp(); + + // if (mech.fieldCDcycle < mech.cycle) { + // // game.draw.bodyFill = "transparent" + // // game.draw.bodyStroke = "transparent" + + // const DRAIN = 0.00013 + (mech.fireCDcycle > mech.cycle ? 0.005 : 0) + // if (mech.energy > DRAIN) { + // mech.energy -= DRAIN; + // // if (mech.energy < 0.001) { + // // mech.fieldCDcycle = mech.cycle + 120; + // // mech.energy = 0; + // // mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + // // } + // this.fieldRange = this.fieldRange * 0.8 + 0.2 * 160 + // drawField(this.fieldRange) + + // mech.isCloak = true //isCloak disables most uses of foundPlayer() + // player.collisionFilter.mask = cat.map + + + // let inPlayer = Matter.Query.region(mob, player.bounds) + // if (inPlayer.length > 0) { + // for (let i = 0; i < inPlayer.length; i++) { + // if (inPlayer[i].shield) { + // mech.energy -= 0.005; //shields drain player energy + // //draw outline of shield + // ctx.fillStyle = `rgba(140,217,255,0.5)` + // ctx.fill() + // } else if (mod.superposition && inPlayer[i].dropPowerUp) { + // // inPlayer[i].damage(0.4 * b.dmgScale); //damage mobs inside the player + // // mech.energy += 0.005; + + // mobs.statusStun(inPlayer[i], 300) + // //draw outline of mob in a few random locations to show blurriness + // const vertices = inPlayer[i].vertices; + // const off = 30 + // for (let k = 0; k < 3; k++) { + // const xOff = off * (Math.random() - 0.5) + // const yOff = off * (Math.random() - 0.5) + // ctx.beginPath(); + // ctx.moveTo(xOff + vertices[0].x, yOff + vertices[0].y); + // for (let j = 1, len = vertices.length; j < len; ++j) { + // ctx.lineTo(xOff + vertices[j].x, yOff + vertices[j].y); + // } + // ctx.lineTo(xOff + vertices[0].x, yOff + vertices[0].y); + // ctx.fillStyle = "rgba(0,0,0,0.1)" + // ctx.fill() + // } + // break; + // } + // } + // } + // } else { + // mech.fieldCDcycle = mech.cycle + 120; + // mech.energy = 0; + // mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + // drawField(this.fieldRange) + // } + // } + // } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released + // mech.pickUp(); + // if (this.fieldRange < 2000) { + // this.fieldRange += 100 + // drawField(this.fieldRange) + // } + // } else { + // // this.fieldRange = 3000 + // if (this.fieldRange < 2000 && mech.holdingTarget === null) { + // this.fieldRange += 100 + // drawField(this.fieldRange) + // } + // mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + // } + + // if (mech.energy < mech.maxEnergy) { + // mech.energy += mech.fieldRegen; + // const xOff = mech.pos.x - mech.radius * mech.maxEnergy + // const yOff = mech.pos.y - 50 + // ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; + // ctx.fillRect(xOff, yOff, 60 * mech.maxEnergy, 10); + // ctx.fillStyle = mech.fieldMeterColor; + // ctx.fillRect(xOff, yOff, 60 * mech.energy, 10); + // ctx.beginPath() + // ctx.rect(xOff, yOff, 60 * mech.maxEnergy, 10); + // ctx.strokeStyle = "rgb(0, 0, 0)"; + // ctx.lineWidth = 1; + // ctx.stroke(); + // } + // if (mech.energy < 0) mech.energy = 0 + // } + // } + // }, { name: "pilot wave", description: "use energy to push blocks with your mouse
field radius decreases out of line of sight", diff --git a/js/spawn.js b/js/spawn.js index e9faf2a..8d154d5 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -245,7 +245,7 @@ const spawn = { powerUps.spawnBossPowerUp(me.position.x, me.position.y) powerUps.spawn(me.position.x, me.position.y, "heal"); powerUps.spawn(me.position.x, me.position.y, "ammo"); - } else if (!mech.isStealth) { + } else if (!mech.isCloak) { me.foundPlayer(); } @@ -578,7 +578,7 @@ const spawn = { //when player is inside event horizon if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { - mech.energy -= 0.004 + if (mech.energy > 0) mech.energy -= 0.004 if (mech.energy < 0.1) { mech.damage(0.00015 * game.dmgScale); } @@ -677,7 +677,7 @@ const spawn = { ctx.fill(); //when player is inside event horizon if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { - mech.energy -= 0.006 + if (mech.energy > 0) mech.energy -= 0.006 if (mech.energy < 0.1) { mech.damage(0.0002 * game.dmgScale); } @@ -727,6 +727,7 @@ const spawn = { damping: springDampening }); cons[len].length = 100 + 1.5 * radius; + me.cons = cons[len]; me.springTarget2 = { @@ -780,7 +781,7 @@ const spawn = { stiffness: attachmentStiffness, damping: 0.01 }); - // console.log(consBB[consBB.length - 1]) + World.add(engine.world, consBB[consBB.length - 1]); } }, timeSkipBoss(x, y, radius = 55) { @@ -1061,7 +1062,7 @@ const spawn = { }; vertexCollision(this.position, look, map); vertexCollision(this.position, look, body); - if (!mech.isStealth) vertexCollision(this.position, look, [player]); + if (!mech.isCloak) vertexCollision(this.position, look, [player]); // hitting player if (best.who === player) { if (mech.immuneCycle < mech.cycle) { @@ -1217,7 +1218,7 @@ const spawn = { // vertexCollision(where, look, mob); vertexCollision(where, look, map); vertexCollision(where, look, body); - if (!mech.isStealth) vertexCollision(where, look, [player]); + if (!mech.isCloak) vertexCollision(where, look, [player]); if (best.who && best.who === player && mech.immuneCycle < mech.cycle) { mech.immuneCycle = mech.cycle + mod.collisionImmuneCycles; //player is immune to collision damage for 30 cycles const dmg = 0.14 * game.dmgScale; @@ -1336,7 +1337,7 @@ const spawn = { this.distanceToPlayer2() < this.seeAtDistance2 && Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 && - !mech.isStealth + !mech.isCloak ) { this.foundPlayer(); if (this.cd === Infinity) this.cd = game.cycle + this.delay * 0.7; @@ -1447,7 +1448,7 @@ const spawn = { if (this.alpha > 0) this.alpha -= 0.03; } if (this.alpha > 0) { - if (this.alpha > 0.9) { + if (this.alpha > 0.9 && this.seePlayer.recall) { this.healthBar(); if (!this.canTouchPlayer) { this.canTouchPlayer = true; @@ -2008,16 +2009,19 @@ const spawn = { bodyB: mob[mob.length - 1 - nodes], stiffness: 0.05 }); + World.add(engine.world, consBB[consBB.length - 1]); consBB[consBB.length] = Constraint.create({ bodyA: mob[mob.length - nodes + 1], bodyB: mob[mob.length - 1 - nodes], stiffness: 0.05 }); + World.add(engine.world, consBB[consBB.length - 1]); consBB[consBB.length] = Constraint.create({ bodyA: mob[mob.length - nodes + 2], bodyB: mob[mob.length - 1 - nodes], stiffness: 0.05 }); + World.add(engine.world, consBB[consBB.length - 1]); }, tetherBoss(x, y, radius = 90) { @@ -2057,6 +2061,8 @@ const spawn = { stiffness: 0.4, damping: 0.1 }); + World.add(engine.world, consBB[consBB.length - 1]); + me.onDamage = function () { //make sure the mob that owns the shield can tell when damage is done this.alertNearByMobs(); @@ -2101,6 +2107,7 @@ const spawn = { stiffness: stiffness, damping: 0.1 }); + World.add(engine.world, consBB[consBB.length - 1]); } me.onDamage = function () { this.alertNearByMobs(); //makes sure the mob that owns the shield can tell when damage is done @@ -2220,6 +2227,7 @@ const spawn = { bodyB: mob[mob.length - j], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); } } }, @@ -2231,6 +2239,7 @@ const spawn = { bodyB: mob[mob.length - i - 2], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); } if (nodes > 2) { for (let i = 0; i < nodes - 2; ++i) { @@ -2239,6 +2248,7 @@ const spawn = { bodyB: mob[mob.length - i - 3], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); } } //optional connect the tail to head @@ -2248,16 +2258,19 @@ const spawn = { bodyB: mob[mob.length - nodes], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); consBB[consBB.length] = Constraint.create({ bodyA: mob[mob.length - 2], bodyB: mob[mob.length - nodes], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); consBB[consBB.length] = Constraint.create({ bodyA: mob[mob.length - 1], bodyB: mob[mob.length - nodes + 1], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); } }, constraintPB(x, y, bodyIndex, stiffness) { @@ -2269,6 +2282,7 @@ const spawn = { bodyB: body[bodyIndex], stiffness: stiffness }); + World.add(engine.world, cons[cons.length - 1]); }, constraintBB(bodyIndexA, bodyIndexB, stiffness) { consBB[consBB.length] = Constraint.create({ @@ -2276,6 +2290,7 @@ const spawn = { bodyB: body[bodyIndexB], stiffness: stiffness }); + World.add(engine.world, consBB[consBB.length - 1]); }, // body and map spawns ****************************************************************************** //********************************************************************************************** diff --git a/style.css b/style.css index 0047fd7..56f5f00 100644 --- a/style.css +++ b/style.css @@ -464,6 +464,11 @@ em { letter-spacing: 1px; } +.color-cloaked { + opacity: 0.25; + letter-spacing: 1px; +} + .color-harm { /* color: */ /* text-shadow: #FC0 1px 0 10px; */ diff --git a/todo.txt b/todo.txt index e9e297c..ae4be41 100644 --- a/todo.txt +++ b/todo.txt @@ -1,19 +1,47 @@ -mod: electric reactive armor - reduce harm from explosions by 6% for every 10 energy -mod: waste heat recovery - laser damage grows to 400%, but you start to eject your health as a heal power up -new community level by Francois: house ************** TODO - n-gon ************** +mod - mines stun targets nearby when they explode + +cloaking field mods + larger vision + return to stealth faster + +damage to nearby mobs + +damage to unaware mobs (code for this doesn't seem to work) + +mod - negative mass field intangibility + doesn't seem that interesting + +mod - do something for 2 seconds after firing + if (mech.fireCDcycle + 120) + +getting stuck above a mob can immobilize player + occurs with Pauli exclusion, and time dilation field immunity - mod time-like world line + add a knock to player mob collisions even while player is immune to damage + keep the knock very small + +Health mod idea: health can go above max health. At the end of each level, the amount of health above max is halved. + +general idea: shrink mech.baseHealth in a mod or field + +mod: some drones(or spores) have a chance to spawn as a more power full version + do electric damage to nearby mobs + stun effect? + a bot that eats up health and ammo, but poops a reroll after picking up 2 power ups it passes through walls moves slower then the player so you can get to it before the bot if you hurry 4 rerolls can convert to a bot, also 1 rerolls can convert to 5% damage the mods that do those effects could be required before you see this bot disable crystalized armor? + could convert rerolls, ammo, and health into mods instead laser-bot orbits player +bot that does AOE damage while it rotates around player + no physics / collisions + cap 3 ? mod: radiation effects can spread to nearby mobs @@ -43,23 +71,11 @@ new gun or field - fire 3+ balls in arc hold fire to charge: increases the size of the balls mod: balls are attracted to mobs -fix: even with a scroll bar the top of the selection window is off screen for very short windows - rework perfect diamagnetism let the shield also do bremsstrahlung radiation - mod: grab and launch mobs? - -getting stuck above a mob can immobilize player - seems to only occur with Pauli exclusion - add a knock to player mob collisions even while player is immune to damage - keep the knock very small map element - player rotates a rotor that makes a platform go up or down -removing supersaturation sets total health to 1 - this cancels the health benefits from crystallized armor - produce a method that calculates max health based on mods - use mac automator to speed up your n-gon -> git sync fix door.isOpen actually meaning isClosed @@ -68,10 +84,6 @@ mod - laser fires 3 beams give missiles a suck and delay explosion, like vacuum bomb -bot that does AOE damage while it rotates around player - no physics / collisions - cap 3 ? - level Boss: fractal SierpiƄski triangle https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level @@ -151,9 +163,6 @@ mod - do 50% more damage in close, but 50% less at a distance code it like mod.isFarAwayDmg have these mods disable each other -phase field still isn't fun - does phase field need the stealth flag? - mod harmonic shield: slow everything in range around shield (temporal shield) set max speed?