diff --git a/.DS_Store b/.DS_Store index 20063e5..c99e68d 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/js/bullet.js b/js/bullet.js index eb07b33..312be53 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -51,8 +51,6 @@ const b = { if (m.fireCDcycle < m.cycle && player.speed < 0.5 && m.onGround && Math.abs(m.yOff - m.yOffGoal) < 1) { if (b.guns[b.activeGun].ammo > 0) { b.fireWithAmmo() - } else { - b.outOfAmmo() } if (m.holdingTarget) m.drop(); } @@ -297,17 +295,17 @@ const b = { } }, explosionRange() { - return tech.explosiveRadius * (tech.isExplosionHarm ? 1.8 : 1) * (tech.isSmallExplosion ? 0.8 : 1) * (tech.isExplodeRadio ? 1.25 : 1) + return tech.explosiveRadius * (tech.isExplosionHarm ? 1.8 : 1) * (tech.isSmallExplosion ? 0.66 : 1) * (tech.isExplodeRadio ? 1.25 : 1) }, explosion(where, radius, color = "rgba(255,25,0,0.6)") { // typically explode is used for some bullets with .onEnd radius *= tech.explosiveRadius let dist, sub, knock; - let dmg = radius * 0.013; + let dmg = radius * 0.013 * (tech.isExplosionStun ? 0.6 : 1); if (tech.isExplosionHarm) radius *= 1.8 // 1/sqrt(2) radius -> area if (tech.isSmallExplosion) { color = "rgba(255,0,30,0.7)" - radius *= 0.8 - dmg *= 1.6 + radius *= 0.66 + dmg *= 1.66 } if (tech.isExplodeRadio) { //radiation explosion @@ -430,6 +428,7 @@ const b = { knock = Vector.mult(Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) * 0.01); mob[i].force.x += knock.x; mob[i].force.y += knock.y; + if (tech.isExplosionStun) mobs.statusStun(mob[i], 120) radius *= 0.95 //reduced range for each additional explosion target damageScale *= 0.87 //reduced damage for each additional explosion target } else if (!mob[i].seePlayer.recall && dist < alertRange) { @@ -437,15 +436,16 @@ const b = { knock = Vector.mult(Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) * 0.006); mob[i].force.x += knock.x; mob[i].force.y += knock.y; + if (tech.isExplosionStun) mobs.statusStun(mob[i], 60) } } } } }, - pulse(energy, angle = m.angle) { + pulse(charge, angle = m.angle) { let best; - let explosionRadius = 1250 * energy - let range = 3000 + let explosionRadius = 6 * charge + let range = 5000 const path = [{ x: m.pos.x + 20 * Math.cos(angle), y: m.pos.y + 20 * Math.sin(angle) @@ -529,26 +529,23 @@ const b = { }; } } - if (best.who) b.explosion(path[1], explosionRadius) - - if (tech.isPulseStun) { - const range = 100 + 2000 * energy - for (let i = 0, len = mob.length; i < len; ++i) { - if (mob[i].alive && !mob[i].isShielded) { - dist = Vector.magnitude(Vector.sub(path[1], mob[i].position)) - mob[i].radius; - if (dist < range) mobs.statusStun(mob[i], 30 + Math.floor(energy * 60)) - } - } + if (best.who) { + b.explosion(path[1], explosionRadius) + const off = explosionRadius + b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius) + b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius) } //draw laser beam ctx.beginPath(); ctx.moveTo(path[0].x, path[0].y); ctx.lineTo(path[1].x, path[1].y); - ctx.strokeStyle = "rgba(255,0,0,0.13)" - ctx.lineWidth = 60 * energy / 0.2 - ctx.stroke(); - ctx.strokeStyle = "rgba(255,0,0,0.2)" - ctx.lineWidth = 18 + if (charge > 50) { + ctx.strokeStyle = "rgba(255,0,0,0.10)" + ctx.lineWidth = 70 + ctx.stroke(); + } + ctx.strokeStyle = "rgba(255,0,0,0.25)" + ctx.lineWidth = 20 ctx.stroke(); ctx.strokeStyle = "#f00"; ctx.lineWidth = 4 @@ -557,7 +554,7 @@ const b = { //draw little dots along the laser path const sub = Vector.sub(path[1], path[0]) const mag = Vector.magnitude(sub) - for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) { + for (let i = 0, len = Math.floor(mag * 0.0005 * charge); i < len; i++) { const dist = Math.random() simulation.drawList.push({ x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5), @@ -568,121 +565,121 @@ const b = { }); } }, - photon(where, angle = m.angle) { - let best; - const path = [{ - x: m.pos.x + 20 * Math.cos(angle), - y: m.pos.y + 20 * Math.sin(angle) - }, - { - x: m.pos.x + range * Math.cos(angle), - y: m.pos.y + range * Math.sin(angle) - } - ]; - const vertexCollision = function(v1, v1End, domain) { - for (let i = 0; i < domain.length; ++i) { - let vertices = domain[i].vertices; - const len = vertices.length - 1; - for (let j = 0; j < len; j++) { - results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]); - if (results.onLine1 && results.onLine2) { - const dx = v1.x - results.x; - const dy = v1.y - results.y; - const dist2 = dx * dx + dy * dy; - if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[j], - v2: vertices[j + 1] - }; - } - } - } - results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]); - if (results.onLine1 && results.onLine2) { - const dx = v1.x - results.x; - const dy = v1.y - results.y; - const dist2 = dx * dx + dy * dy; - if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; - //check for collisions - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - if (tech.isPulseAim) { //find mobs in line of sight - let dist = 2200 - for (let i = 0, len = mob.length; i < len; i++) { - const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) - if (explosionRadius < newDist && - newDist < dist && - Matter.Query.ray(map, path[0], mob[i].position).length === 0 && - Matter.Query.ray(body, path[0], mob[i].position).length === 0) { - dist = newDist - best.who = mob[i] - path[path.length - 1] = mob[i].position - } - } - } - if (!best.who) { - vertexCollision(path[0], path[1], mob); - vertexCollision(path[0], path[1], map); - vertexCollision(path[0], path[1], body); - if (best.dist2 != Infinity) { //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; - } - } - if (best.who) b.explosion(path[1], explosionRadius) + // photon(where, angle = m.angle) { + // let best; + // const path = [{ + // x: m.pos.x + 20 * Math.cos(angle), + // y: m.pos.y + 20 * Math.sin(angle) + // }, + // { + // x: m.pos.x + range * Math.cos(angle), + // y: m.pos.y + range * Math.sin(angle) + // } + // ]; + // const vertexCollision = function(v1, v1End, domain) { + // for (let i = 0; i < domain.length; ++i) { + // let vertices = domain[i].vertices; + // const len = vertices.length - 1; + // for (let j = 0; j < len; j++) { + // results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]); + // if (results.onLine1 && results.onLine2) { + // const dx = v1.x - results.x; + // const dy = v1.y - results.y; + // const dist2 = dx * dx + dy * dy; + // if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { + // best = { + // x: results.x, + // y: results.y, + // dist2: dist2, + // who: domain[i], + // v1: vertices[j], + // v2: vertices[j + 1] + // }; + // } + // } + // } + // results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]); + // if (results.onLine1 && results.onLine2) { + // const dx = v1.x - results.x; + // const dy = v1.y - results.y; + // const dist2 = dx * dx + dy * dy; + // if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { + // best = { + // x: results.x, + // y: results.y, + // dist2: dist2, + // who: domain[i], + // v1: vertices[0], + // v2: vertices[len] + // }; + // } + // } + // } + // }; + // //check for collisions + // best = { + // x: null, + // y: null, + // dist2: Infinity, + // who: null, + // v1: null, + // v2: null + // }; + // if (tech.isPulseAim) { //find mobs in line of sight + // let dist = 2200 + // for (let i = 0, len = mob.length; i < len; i++) { + // const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) + // if (explosionRadius < newDist && + // newDist < dist && + // Matter.Query.ray(map, path[0], mob[i].position).length === 0 && + // Matter.Query.ray(body, path[0], mob[i].position).length === 0) { + // dist = newDist + // best.who = mob[i] + // path[path.length - 1] = mob[i].position + // } + // } + // } + // if (!best.who) { + // vertexCollision(path[0], path[1], mob); + // vertexCollision(path[0], path[1], map); + // vertexCollision(path[0], path[1], body); + // if (best.dist2 != Infinity) { //if hitting something + // path[path.length - 1] = { + // x: best.x, + // y: best.y + // }; + // } + // } + // if (best.who) b.explosion(path[1], explosionRadius) - //draw laser beam - ctx.beginPath(); - ctx.moveTo(path[0].x, path[0].y); - ctx.lineTo(path[1].x, path[1].y); - ctx.strokeStyle = "rgba(255,0,0,0.13)" - ctx.lineWidth = 60 * energy / 0.2 - ctx.stroke(); - ctx.strokeStyle = "rgba(255,0,0,0.2)" - ctx.lineWidth = 18 - ctx.stroke(); - ctx.strokeStyle = "#f00"; - ctx.lineWidth = 4 - ctx.stroke(); + // //draw laser beam + // ctx.beginPath(); + // ctx.moveTo(path[0].x, path[0].y); + // ctx.lineTo(path[1].x, path[1].y); + // ctx.strokeStyle = "rgba(255,0,0,0.13)" + // ctx.lineWidth = 60 * energy / 0.2 + // ctx.stroke(); + // ctx.strokeStyle = "rgba(255,0,0,0.2)" + // ctx.lineWidth = 18 + // ctx.stroke(); + // ctx.strokeStyle = "#f00"; + // ctx.lineWidth = 4 + // ctx.stroke(); - //draw little dots along the laser path - const sub = Vector.sub(path[1], path[0]) - const mag = Vector.magnitude(sub) - for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) { - const dist = Math.random() - simulation.drawList.push({ - x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5), - y: path[0].y + sub.y * dist + 13 * (Math.random() - 0.5), - radius: 1 + 4 * Math.random(), - color: "rgba(255,0,0,0.5)", - time: Math.floor(2 + 33 * Math.random() * Math.random()) - }); - } - }, + // //draw little dots along the laser path + // const sub = Vector.sub(path[1], path[0]) + // const mag = Vector.magnitude(sub) + // for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) { + // const dist = Math.random() + // simulation.drawList.push({ + // x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5), + // y: path[0].y + sub.y * dist + 13 * (Math.random() - 0.5), + // radius: 1 + 4 * Math.random(), + // color: "rgba(255,0,0,0.5)", + // time: Math.floor(2 + 33 * Math.random() * Math.random()) + // }); + // } + // }, grenade() { }, @@ -2226,7 +2223,7 @@ const b = { if (this.target.isShielded) { this.target.damage(b.dmgScale * this.damage, true); //shield damage bypass //shrink if mob is shielded - const SCALE = 1 - 0.014 / tech.isBulletsLastLonger + const SCALE = 1 - 0.01 / tech.isBulletsLastLonger Matter.Body.scale(this, SCALE, SCALE); this.radius *= SCALE; } else { @@ -2873,7 +2870,7 @@ const b = { let closeDist = this.range; for (let i = 0, len = mob.length; i < len; ++i) { const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius; - if (DIST < closeDist && mob[i].isDropPowerUp && + if (DIST < closeDist && Matter.Query.ray(map, this.position, mob[i].position).length === 0 && Matter.Query.ray(body, this.position, mob[i].position).length === 0) { closeDist = DIST; @@ -4049,16 +4046,18 @@ const b = { name: "foam", description: "spray bubbly foam that sticks to mobs
slows mobs and does damage over time", ammo: 0, - ammoPack: 30, + ammoPack: 27, have: false, charge: 0, isDischarge: false, do() { if (this.charge > 0) { //draw charge level - ctx.fillStyle = "rgba(0,50,50,0.2)"; + ctx.fillStyle = "rgba(0,50,50,0.3)"; ctx.beginPath(); - ctx.arc(m.pos.x + 35 * Math.cos(m.angle), m.pos.y + 35 * Math.sin(m.angle), 10 * Math.sqrt(this.charge), 0, 2 * Math.PI); + const radius = 10 * Math.sqrt(this.charge) + const mag = 11 + radius + ctx.arc(m.pos.x + mag * Math.cos(m.angle), m.pos.y + mag * Math.sin(m.angle), radius, 0, 2 * Math.PI); ctx.fill(); if (this.isDischarge) { @@ -4094,15 +4093,15 @@ const b = { x: position.x, y: position.y, radius: 5, - color: "rgba(0,0,0,0.1)", + color: "rgba(0,50,50,0.3)", time: 15 * tech.foamFutureFire }); setTimeout(() => { if (!simulation.paused) { b.foam(position, Vector.rotate(velocity, spread), radius) - bullet[bullet.length - 1].damage = (1 + 1.27 * tech.foamFutureFire) * (tech.isFastFoam ? 0.048 : 0.012) //double damage + bullet[bullet.length - 1].damage = (1 + 0.9 * tech.foamFutureFire) * (tech.isFastFoam ? 0.048 : 0.012) //double damage } - }, 250 * tech.foamFutureFire); + }, 300 * tech.foamFutureFire); } else { b.foam(position, Vector.rotate(velocity, spread), radius) } @@ -4467,14 +4466,43 @@ const b = { ammo: 0, ammoPack: Infinity, have: false, - nextFireCycle: 0, //use to remember how longs its been since last fire, used to reset count + charge: 0, do() {}, - fire() { - - }, + fire() {}, chooseFireMethod() { + this.do = () => {}; if (tech.isPulseLaser) { - this.fire = this.firePulse + this.fire = () => { + + const drain = 0.01 * tech.isLaserDiode / b.fireCD + if (m.energy > drain) { + m.energy -= m.fieldRegen + if (this.charge < 50 * m.maxEnergy) { + m.energy -= drain + this.charge += 1 / b.fireCD + } + } + } + this.do = () => { + if (this.charge > 0) { + //draw charge level + ctx.fillStyle = `rgba(255,0,0,${0.09 * Math.sqrt(this.charge)})`; + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, 4.2 * Math.sqrt(this.charge), 0, 2 * Math.PI); + ctx.fill(); + if (!input.fire) { + m.fireCDcycle = m.cycle + 10; // cool down + if (tech.beamSplitter) { + const divergence = m.crouch ? 0.2 : 0.5 + const angle = m.angle - tech.beamSplitter * divergence / 2 + for (let i = 0; i < 1 + tech.beamSplitter; i++) b.pulse(this.charge, angle + i * divergence) + } else { + b.pulse(1.75 * this.charge, m.angle) + } + this.charge = 0; + } + } + }; } else if (tech.beamSplitter) { this.fire = this.fireSplit } else if (tech.historyLaser) { @@ -4627,27 +4655,27 @@ const b = { ctx.stroke(); } }, - firePulse() { - m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down - let energy = 0.3 * Math.min(m.energy, 1.5) - m.energy -= energy * tech.isLaserDiode - if (tech.beamSplitter) { - // energy *= Math.pow(0.9, tech.beamSplitter) - // b.pulse(energy, m.angle) - // for (let i = 1; i < 1 + tech.beamSplitter; i++) { - // b.pulse(energy, m.angle - i * 0.27) - // b.pulse(energy, m.angle + i * 0.27) - // } - const divergence = m.crouch ? 0.2 : 0.5 - const angle = m.angle - tech.beamSplitter * divergence / 2 - for (let i = 0; i < 1 + tech.beamSplitter; i++) { - b.pulse(energy, angle + i * divergence) - } + // firePulse() { + // m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down + // let energy = 0.3 * Math.min(m.energy, 1.5) + // m.energy -= energy * tech.isLaserDiode + // if (tech.beamSplitter) { + // // energy *= Math.pow(0.9, tech.beamSplitter) + // // b.pulse(energy, m.angle) + // // for (let i = 1; i < 1 + tech.beamSplitter; i++) { + // // b.pulse(energy, m.angle - i * 0.27) + // // b.pulse(energy, m.angle + i * 0.27) + // // } + // const divergence = m.crouch ? 0.2 : 0.5 + // const angle = m.angle - tech.beamSplitter * divergence / 2 + // for (let i = 0; i < 1 + tech.beamSplitter; i++) { + // b.pulse(energy, angle + i * divergence) + // } - } else { - b.pulse(energy, m.angle) - } - }, + // } else { + // b.pulse(energy, m.angle) + // } + // }, }, ], gunRewind: { //this gun is added with a tech diff --git a/js/index.js b/js/index.js index d74f71a..71e9018 100644 --- a/js/index.js +++ b/js/index.js @@ -794,17 +794,7 @@ window.addEventListener("keydown", function(event) { simulation.testing = true; simulation.loop = simulation.testingLoop if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'inline' - if (!simulation.isCheating) { - simulation.isCheating = true; - level.levelAnnounce(); - lore.techCount = 0; - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].isLore) { - tech.tech[i].frequency = 0; - tech.tech[i].count = 0; - } - } - } + if (simulation.testing) tech.setCheating(); simulation.makeTextLog( ` diff --git a/js/level.js b/js/level.js index 1cd3858..5b9a673 100644 --- a/js/level.js +++ b/js/level.js @@ -12,14 +12,15 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.enableConstructMode() //used to build maps in testing mode - // level.difficultyIncrease(50) + // level.difficultyIncrease(30) // simulation.zoomScale = 1000; // simulation.setZoom(); // m.setField("nano-scale manufacturing") // b.giveGuns("foam") + // b.giveGuns("laser") // tech.isExplodeRadio = true // for (let i = 0; i < 9; i++) tech.giveTech("auto-loading heuristics") - // tech.giveTech("superfluidity") + // tech.giveTech("pulse") // tech.giveTech("ice crystal nucleation") // tech.giveTech("needle gun") // tech.giveTech("cardinality") @@ -1109,9 +1110,8 @@ const level = { spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump - // simulation.difficulty = 30 - spawn.starter(1900, -500, 100) //big boy - spawn.grower(1900, -500) + spawn.starter(1900, -500, 200) //big boy + // spawn.grower(1900, -500) // spawn.pulsarBoss(1900, -500) // spawn.shooterBoss(1900, -500) // spawn.launcherBoss(1200, -500) diff --git a/js/player.js b/js/player.js index 17acbb8..28e5ede 100644 --- a/js/player.js +++ b/js/player.js @@ -1145,20 +1145,20 @@ const m = { m.fieldCDcycle = m.cycle + 15; m.isHolding = false; //bullet-like collisions - m.holdingTarget.collisionFilter.category = cat.bullet; //cat.body; + // m.holdingTarget.collisionFilter.category = cat.bullet; //cat.body; m.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 (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) { - that.collisionFilter.category = cat.body; //make solid + // 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, 40, that); } }; - setTimeout(solid, 500, m.holdingTarget); + setTimeout(solid, 200, m.holdingTarget); const charge = Math.min(m.throwCharge / 5, 1) //***** scale throw speed with the first number, 80 ***** diff --git a/js/spawn.js b/js/spawn.js index 81c3eb2..e78ee52 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1621,9 +1621,9 @@ const spawn = { ctx.moveTo(this.vertices[1].x, this.vertices[1].y) ctx.lineTo(this.fireTarget.x, this.fireTarget.y) ctx.lineWidth = 20; - ctx.strokeStyle = "rgba(120,0,255,0.2)"; + ctx.strokeStyle = "rgba(120,0,255,0.3)"; ctx.stroke(); - ctx.lineWidth = 4; + ctx.lineWidth = 5; ctx.strokeStyle = "rgba(120,0,255,1)"; ctx.stroke(); } else { //delay before firing @@ -1631,7 +1631,7 @@ const spawn = { //draw explosion outline ctx.beginPath(); ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay - ctx.fillStyle = "rgba(120,0,255,0.05)"; + ctx.fillStyle = "rgba(120,0,255,0.07)"; ctx.fill(); //draw path from mob to explosion ctx.beginPath(); @@ -1639,7 +1639,7 @@ const spawn = { ctx.lineTo(this.fireTarget.x, this.fireTarget.y) ctx.setLineDash([40 * Math.random(), 200 * Math.random()]); ctx.lineWidth = 2; - ctx.strokeStyle = "rgba(120,0,255,0.2)"; + ctx.strokeStyle = "rgba(120,0,255,0.3)"; ctx.stroke(); ctx.setLineDash([0, 0]); } @@ -1741,9 +1741,9 @@ const spawn = { ctx.moveTo(this.vertices[1].x, this.vertices[1].y) ctx.lineTo(this.fireTarget.x, this.fireTarget.y) ctx.lineWidth = 20; - ctx.strokeStyle = "rgba(255,0,100,0.2)"; + ctx.strokeStyle = "rgba(255,0,100,0.3)"; ctx.stroke(); - ctx.lineWidth = 4; + ctx.lineWidth = 5; ctx.strokeStyle = "rgba(255,0,100,1)"; ctx.stroke(); } else { //delay before firing @@ -1754,7 +1754,7 @@ const spawn = { //draw explosion outline ctx.beginPath(); ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay - ctx.fillStyle = "rgba(255,0,100,0.05)"; + ctx.fillStyle = "rgba(255,0,100,0.07)"; ctx.fill(); //draw path from mob to explosion ctx.beginPath(); @@ -1762,7 +1762,7 @@ const spawn = { ctx.lineTo(this.fireTarget.x, this.fireTarget.y) ctx.setLineDash([40 * Math.random(), 200 * Math.random()]); ctx.lineWidth = 2; - ctx.strokeStyle = "rgba(255,0,100,0.2)"; + ctx.strokeStyle = "rgba(255,0,100,0.3)"; ctx.stroke(); ctx.setLineDash([0, 0]); } diff --git a/js/tech.js b/js/tech.js index d230a40..3a182a8 100644 --- a/js/tech.js +++ b/js/tech.js @@ -107,6 +107,17 @@ } } }, + setCheating() { + simulation.isCheating = true; + level.levelAnnounce(); + lore.techCount = 0; + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].isLore) { + tech.tech[i].frequency = 0; + tech.tech[i].count = 0; + } + } + }, haveGunCheck(name) { if ( !build.isExperimentSelection && @@ -745,7 +756,7 @@ }, { name: "nitroglycerin", - description: "increase explosivedamage by 60%
decrease explosiveradius by 20%", + description: "increase explosivedamage by 66%
decrease explosiveradius by 33%", maxCount: 1, count: 0, frequency: 2, @@ -778,6 +789,24 @@ tech.isExplosionHarm = false; } }, + { + name: "shock wave", + description: "explosionsstun mobs for 1-2 seconds
decrease explosivedamage by 40%", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + allowed() { + return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1) + }, + requires: "an explosive damage source, not iridium-192", + effect() { + tech.isExplosionStun = true; + }, + remove() { + tech.isExplosionStun = false; + } + }, { name: "electric reactive armor", // description: "explosions do no harm
while your energy is above 98%", @@ -1443,9 +1472,9 @@ frequency: 4, frequencyDefault: 4, allowed() { - return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" + return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isEnergyHealth }, - requires: "mass driver, a field that can hold things", + requires: "mass driver, a field that can hold things, not mass-energy", effect() { tech.isBlockHarm = true }, @@ -1687,23 +1716,6 @@ tech.isHarmFreeze = false; } }, - { - name: "osmoprotectant", - description: `collisions with stunned or frozen mobs
cause you noharm`, - maxCount: 1, - count: 0, - frequency: 2, - allowed() { - return tech.isStunField || tech.isPulseStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 - }, - requires: "a freezing or stunning effect", - effect() { - tech.isFreezeHarmImmune = true; - }, - remove() { - tech.isFreezeHarmImmune = false; - } - }, { name: "superfluidity", description: "freeze effects are applied to a small area", @@ -1721,6 +1733,40 @@ tech.isAoESlow = false } }, + { + name: "osmoprotectant", + description: `collisions with stunned or frozen mobs
cause you noharm`, + maxCount: 1, + count: 0, + frequency: 2, + allowed() { + return tech.isStunField || tech.isExplosionStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 + }, + requires: "a freezing or stunning effect", + effect() { + tech.isFreezeHarmImmune = true; + }, + remove() { + tech.isFreezeHarmImmune = false; + } + }, + { + name: "fracture analysis", + description: "bullet impacts do 400%damage
to stunned mobs", + maxCount: 1, + count: 0, + frequency: 2, + allowed() { + return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isPerpetualStun || tech.isExplosionStun + }, + requires: "a stun effect", + effect() { + tech.isCrit = true; + }, + remove() { + tech.isCrit = false; + } + }, { name: "ablative drones", description: "rebuild your broken parts as drones
chance to occur after receiving harm", @@ -2124,9 +2170,9 @@ frequency: 4, frequencyDefault: 4, allowed() { - return tech.isDamageAfterKill + return tech.isDamageAfterKill && !tech.isEnergyHealth }, - requires: "dormancy", + requires: "dormancy, not mass-energy", effect() { tech.isHarmReduceAfterKill = true; }, @@ -2553,6 +2599,7 @@ if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech tech.setupAllTech(); // remove all tech + if (simulation.isCheating) tech.setCheating(); lore.techCount = 0; // tech.addLoreTechToPool(); for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups @@ -4006,7 +4053,7 @@ }, { name: "quantum foam", - description: "foam gun fires 0.25 seconds into the future
increase foam gun damage by 127%", + description: "foam gun fires 0.30 seconds into the future
increase foam gun damage by 90%", isGunTech: true, maxCount: 9, count: 0, @@ -4302,7 +4349,7 @@ }, { name: "pulse", - description: "use 25% of your energy in a pulsed laser
that instantly initiates a fusion explosion", + description: "charge your energy and release it as a
laser pulse that initiates an explosion cluster", isGunTech: true, maxCount: 1, count: 0, @@ -4326,27 +4373,9 @@ } } }, - { - name: "shock wave", - description: "mobs caught in pulse's explosion are stunned
for up to 2 seconds", - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - allowed() { - return tech.isPulseLaser - }, - requires: "pulse", - effect() { - tech.isPulseStun = true; - }, - remove() { - tech.isPulseStun = false; - } - }, { name: "neocognitron", - description: "pulse automatically aims at a nearby mob
50% decreased delay after firing", + description: "pulse automatically aims at a nearby mob", isGunTech: true, maxCount: 1, count: 0, @@ -4366,6 +4395,28 @@ //************************************************** field //************************************************** tech //************************************************** + { + name: "frequency resonance", + description: "standing wave harmonics shield is retuned
increase size and blocking efficiency by 50%", + isFieldTech: true, + maxCount: 9, + count: 0, + frequency: 2, + allowed() { + return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" + }, + requires: "standing wave harmonics", + effect() { + tech.frequencyResonance = this.count + 1 // +1 because count updates later + m.fieldRange = 175 + 175 * 0.25 * tech.frequencyResonance + m.fieldShieldingScale = Math.pow(0.5, tech.frequencyResonance) + }, + remove() { + m.fieldRange = 175; + m.fieldShieldingScale = 1; + tech.frequencyResonance = 0 + } + }, { name: "bremsstrahlung", description: "blocking does damage to mobs", @@ -4402,28 +4453,6 @@ tech.blockingIce = 0; } }, - { - name: "frequency resonance", - description: "standing wave harmonics shield is retuned
increase size and blocking efficiency by 50%", - isFieldTech: true, - maxCount: 9, - count: 0, - frequency: 2, - allowed() { - return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" - }, - requires: "standing wave harmonics", - effect() { - tech.frequencyResonance = this.count + 1 // +1 because count updates later - m.fieldRange = 175 + 175 * 0.25 * tech.frequencyResonance - m.fieldShieldingScale = Math.pow(0.5, tech.frequencyResonance) - }, - remove() { - m.fieldRange = 175; - m.fieldShieldingScale = 1; - tech.frequencyResonance = 0 - } - }, { name: "flux pinning", description: "blocking with your field
stuns mobs for +2 second", @@ -4442,24 +4471,6 @@ tech.isStunField = 0; } }, - { - name: "fracture analysis", - description: "bullet impacts do 400%damage
to stunned mobs", - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 2, - allowed() { - return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isPerpetualStun - }, - requires: "a stun effect", - effect() { - tech.isCrit = true; - }, - remove() { - tech.isCrit = false; - } - }, { name: "eddy current brake", description: "project a field that limits the top speed of mobs
field radius scales with stored energy", @@ -4478,25 +4489,6 @@ tech.isPerfectBrake = false; } }, - { - name: "pair production", - description: "picking up a power up gives you 250energy", - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 2, - allowed() { - return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" - }, - requires: "nano-scale manufacturing", - effect: () => { - tech.isMassEnergy = true // used in m.grabPowerUp - m.energy += 3 - }, - remove() { - tech.isMassEnergy = false; - } - }, { name: "bot manufacturing", description: "use nano-scale manufacturing
to build 3 random bots", @@ -4608,6 +4600,25 @@ }, remove() {} }, + { + name: "pair production", + description: "picking up a power up gives you 250energy", + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 2, + allowed() { + return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" + }, + requires: "nano-scale manufacturing", + effect: () => { + tech.isMassEnergy = true // used in m.grabPowerUp + m.energy += 3 + }, + remove() { + tech.isMassEnergy = false; + } + }, { name: "mycelium manufacturing", description: "nano-scale manufacturing is repurposed
excess energy used to grow spores", @@ -4688,9 +4699,9 @@ count: 0, frequency: 2, allowed() { - return m.fieldUpgrades[m.fieldMode].name === "negative mass field" + return m.fieldUpgrades[m.fieldMode].name === "negative mass field" && !tech.isEnergyHealth }, - requires: "negative mass field", + requires: "negative mass field, not mass-energy", effect() { tech.isHarmReduce = true }, @@ -6304,7 +6315,7 @@ isSporeFollow: null, isNailRadiation: null, isEnergyHealth: null, - isPulseStun: null, + isExplosionStun: null, restDamage: null, isRPG: null, missileCount: null, diff --git a/todo.txt b/todo.txt index c40df5c..f8499a4 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,11 @@ ******************************************************** NEXT PATCH ******************************************************** +pulse laser now charges up with energy before you fire, but it fires 3 overlapping explosions + please give feedback on balance (too strong, too weak?) + +tech shockwave: now applies to all explosions + +foam gun now gets 20% less ammo ******************************************************** BUGS ******************************************************** @@ -18,9 +24,9 @@ fix door.isOpen actually meaning isClosed? wasn't able to understand bug after extensive testing had tech: complex spin statistics -(always) make it so that when you are immune to harm you can either jump on mobs or you pass through them +make it so that when you are immune to harm you can either jump on mobs or you pass through them -(always) is there a way to check if the player is stuck inside the map or block +is there a way to check if the player is stuck inside the map or block trigger a short term non-collide if that occurs (intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause @@ -33,8 +39,16 @@ fix door.isOpen actually meaning isClosed? ******************************************************** TODO ******************************************************** -edit foam gun text? -add a foam charge meter would be nice +avoid taking collision damage by teleporting to a random power up + removes the power up + +make a tech that improves all charge guns + for: pulse, foam, rail gun + effect: + faster charge rate? + fire speed already does that... + harm reduction while charging + less ammo/energy used while charging? apply the new gun.do functions to other guns rail gun