diff --git a/img/rupture.webp b/img/swarf.webp similarity index 100% rename from img/rupture.webp rename to img/swarf.webp diff --git a/img/topological defect.webp b/img/topological defect.webp index c81a53c..a4be7c9 100644 Binary files a/img/topological defect.webp and b/img/topological defect.webp differ diff --git a/img/yield stress.webp b/img/yield stress.webp deleted file mode 100644 index a4be7c9..0000000 Binary files a/img/yield stress.webp and /dev/null differ diff --git a/js/bullet.js b/js/bullet.js index 674bfd5..b1bc458 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -558,46 +558,6 @@ const b = { y: where.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, @@ -607,28 +567,8 @@ const b = { v1: null, v2: null }; - // if (tech.isPulseAim && !m.crouch) { //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 && - // !mob[i].isBadTarget && - // Matter.Query.ray(map, path[0], mob[i].position).length === 0 && - // Matter.Query.ray(body, path[0], mob[i].position).length === 0 && - // !mob[i].isInvulnerable - // ) { - // 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); + best = vertexCollision(path[0], path[1], [mob, map, body]); if (best.dist2 != Infinity) { //if hitting something path[path.length - 1] = { x: best.x, @@ -678,135 +618,20 @@ 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) - - // //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()) - // }); - // } - // }, - fireworks(where, size) { //can occur after grenades detonate + clusterExplode(where, size) { //can occur after grenades detonate const cycle = () => { if (m.alive) { if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else { count++ - if (count < 130) requestAnimationFrame(cycle); - if (!(count % 10)) { + if (count < 84) requestAnimationFrame(cycle); + if (!(count % 7)) { const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random()) - b.explosion(Vector.add(where, Vector.mult(unit, size * (count * 0.01 + 0.02 * Math.random()))), size * (0.4 + Math.random() * 0.35), `hsla(${360 * Math.random()},100%,66%,0.6)`); //makes bullet do explosive damage at end + b.explosion(Vector.add(where, Vector.mult(unit, size * (count * 0.01 + 0.03 * Math.random()))), size * (0.4 + Math.random() * 0.35), `hsla(${360 * Math.random()},100%,66%,0.6)`); //makes bullet do explosive damage at end } } } @@ -884,7 +709,7 @@ const b = { } else if (tech.isPetalsExplode) { b.fireFlower(this.position, this.explodeRad) } else if (tech.isClusterExplode) { - b.fireworks(this.position, this.explodeRad) + b.clusterExplode(this.position, this.explodeRad) } else { b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end } @@ -1501,7 +1326,7 @@ const b = { drawStringControlMagnitude: 1000 + 1000 * Math.random(), drawStringFlip: (Math.round(Math.random()) ? 1 : -1), attached: false, - glowColor: tech.isHookExplosion ? "rgba(200,0,0,0.07)" : tech.isHarmReduce ? "rgba(50,100,255,0.1)" : "rgba(0,200,255,0.07)", + glowColor: tech.hookNails ? "rgba(200,0,0,0.07)" : tech.isHarmReduce ? "rgba(50,100,255,0.1)" : "rgba(0,200,255,0.07)", collisionFilter: { category: cat.bullet, mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield, @@ -1598,14 +1423,20 @@ const b = { }); } if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs - if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end + if (tech.hookNails) { + // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles + // b.explosion(this.position, 300 + 150 * Math.random()); //makes bullet do explosive damage at end + b.targetedNail(this.position, tech.hookNails) + const ANGLE = 2 * Math.PI * Math.random() //make a few random ones + for (let i = 0; i < 4; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2) + } // if (this.powerUpDamage) this.density = 2 * 0.004 //double damage after pick up power up for 8 seconds if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) { Matter.Body.setDensity(this, 1.8 * 0.004); //+90% damage after pick up power up for 8 seconds } else if (tech.isHarpoonFullHealth && who.health === 1) { - Matter.Body.setDensity(this, 1.9 * 0.004); //+90% damage if mob has full health do + Matter.Body.setDensity(this, 2.11 * 0.004); //+90% damage if mob has full health do simulation.ephemera.push({ name: "grapple outline", count: 3, //cycles before it self removes @@ -1688,7 +1519,7 @@ const b = { if (this.pickUpTarget) { if (tech.isReel && this.blockDist > 150) { // console.log(0.0003 * Math.min(this.blockDist, 1000)) - m.energy += 0.00044 * Math.min(this.blockDist, 800) //max 0.352 energy + m.energy += 0.0009 * Math.min(this.blockDist, 800) //max 0.352 energy simulation.drawList.push({ //add dmg to draw queue x: m.pos.x, y: m.pos.y, @@ -1758,10 +1589,15 @@ const b = { if (blocks.length) { // console.log(blocks) for (let i = 0; i < blocks.length; i++) { - if (blocks[i].bodyA.classType === "body" && !blocks[i].bodyA.isNotHoldable && !blocks[0].bodyA.mass < 60) { + if (blocks[i].bodyA.classType === "body" && !blocks[i].bodyA.isNotHoldable && blocks[0].bodyA.mass < 60) { this.retract() - if (tech.isHookExplosion) { - b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end + if (tech.hookNails) { + // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles + // b.explosion(this.position, 300 + 150 * Math.random()); //makes bullet do explosive damage at end + b.targetedNail(this.position, 3 * tech.hookNails) + const ANGLE = 2 * Math.PI * Math.random() //make a few random ones + for (let i = 0; i < 13; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2) + const blockVertices = blocks[i].bodyA.vertices Composite.remove(engine.world, blocks[i].bodyA) body.splice(body.indexOf(blocks[i].bodyA), 1) @@ -1785,12 +1621,20 @@ const b = { this.pickUpTarget = blocks[i].bodyA this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos)) } - } else if (blocks[i].bodyB.classType === "body" && !blocks[i].bodyB.isNotHoldable && !blocks[0].bodyB.mass < 60) { - this.retract() - this.pickUpTarget = blocks[i].bodyB - this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos)) - if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end } + // else if (blocks[i].bodyB.classType === "body" && !blocks[i].bodyB.isNotHoldable && blocks[0].bodyB.mass < 60) { + // this.retract() + // this.pickUpTarget = blocks[i].bodyB + // this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos)) + // if (tech.hookNails) { + // // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles + // // b.explosion(this.position, 300 + 150 * Math.random()); //makes bullet do explosive damage at end + // b.targetedNail(this.position, tech.hookNails) + // const ANGLE = 2 * Math.PI * Math.random() //make a few random ones + // for (let i = 0; i < 4; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2) + + // } + // } } // if (blocks[0].bodyA.mass > 2.5 && blocks[0].bodyA.mass > 15) { @@ -1855,7 +1699,14 @@ const b = { if (input.field && Matter.Query.collides(this, map).length) { Matter.Body.setPosition(this, Vector.add(this.position, { x: -20 * Math.cos(this.angle), y: -20 * Math.sin(this.angle) })) if (Matter.Query.collides(this, map).length) { - if (tech.isHookExplosion) b.explosion(this.position, 150 + 50 * Math.random()); //makes bullet do explosive damage at end + if (tech.hookNails) { + // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles + // b.explosion(this.position, 200 + 150 * Math.random()); //makes bullet do explosive damage at end + b.targetedNail(this.position, tech.hookNails) + const ANGLE = 2 * Math.PI * Math.random() //make a few random ones + for (let i = 0; i < 4; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2) + + } this.attached = true Matter.Body.setVelocity(this, { x: 0, y: 0 }); Matter.Sleeping.set(this, true) @@ -1976,7 +1827,7 @@ const b = { friction: 1, frictionAir: 0.4, // thrustMag: 0.1, - drain: tech.isRailEnergy ? 0.0006 : 0.006, + drain: tech.isRailEnergy ? 0 : 0.006, turnRate: isReturn ? 0.1 : 0.03, //0.015 drawStringControlMagnitude: 3000 + 5000 * Math.random(), drawStringFlip: (Math.round(Math.random()) ? 1 : -1), @@ -2022,7 +1873,7 @@ const b = { if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) { Matter.Body.setDensity(this, 1.8 * tech.harpoonDensity); //+90% damage after pick up power up for 8 seconds } else if (tech.isHarpoonFullHealth && who.health === 1) { - Matter.Body.setDensity(this, 1.9 * tech.harpoonDensity); //+90% damage if mob has full health do + Matter.Body.setDensity(this, 2.11 * tech.harpoonDensity); //+90% damage if mob has full health do simulation.ephemera.push({ name: "harpoon outline", count: 2, //cycles before it self removes @@ -2435,7 +2286,6 @@ const b = { } //calculate laser collision - let best; let range = tech.isPlasmaRange * (120 + (m.crouch ? 400 : 300) * Math.sqrt(Math.random())) //+ 100 * Math.sin(m.cycle * 0.3); // const dir = m.angle // + 0.04 * (Math.random() - 0.5) const path = [{ @@ -2447,49 +2297,8 @@ const b = { y: m.pos.y + range * Math.sin(m.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 = { + let best = { x: null, y: null, dist2: Infinity, @@ -2497,14 +2306,9 @@ const b = { v1: null, v2: null }; - vertexCollision(path[0], path[1], mob); - vertexCollision(path[0], path[1], map); - vertexCollision(path[0], path[1], body); + best = vertexCollision(path[0], path[1], [mob, map, body]); if (best.dist2 != Infinity) { //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; + path[path.length - 1] = { x: best.x, y: best.y }; if (best.who.alive) { const dmg = 0.9 * m.dmgScale; //********** SCALE DAMAGE HERE ********************* best.who.damage(dmg); @@ -2571,6 +2375,7 @@ const b = { }, dmg = tech.laserDamage, reflections = tech.laserReflections, isThickBeam = false, push = 1) { const reflectivity = 1 - 1 / (reflections * 3) let damage = m.dmgScale * dmg + let best = { x: 1, y: 1, @@ -2586,59 +2391,9 @@ const b = { x: whereEnd.x, y: whereEnd.y }]; - 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] - }; - } - } - } - }; const checkForCollisions = function () { - best = { - x: 1, - y: 1, - dist2: Infinity, - who: null, - v1: 1, - v2: 1 - }; - vertexCollision(path[path.length - 2], path[path.length - 1], mob); - vertexCollision(path[path.length - 2], path[path.length - 1], map); - vertexCollision(path[path.length - 2], path[path.length - 1], body); + best = vertexCollision(path[path.length - 2], path[path.length - 1], [mob, map, body]); }; const laserHitMob = function () { if (best.who.alive) { @@ -2895,7 +2650,7 @@ const b = { } else if (tech.isSuperMine) { b.targetedBall(this.position, 22 + 2 * tech.extraSuperBalls) } else { - b.targetedNail(this.position, 22, 40 + 10 * Math.random(), 1200, true, 2.2) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) { + b.targetedNail(this.position, 22, 40 + 10 * Math.random(), 1200, 2.2) } } }, @@ -2993,7 +2748,7 @@ const b = { if (Math.random() < 0.33) b.targetedBall(this.position, 1, 42 + 12 * Math.random(), 1200, false) } } else { - this.shots -= b.targetedNail(this.position, 1, 45 + 5 * Math.random(), 1100, false, 2.3) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) { + this.shots -= b.targetedNail(this.position, 1, 45 + 5 * Math.random(), 1100, 2.3) } if (this.shots < 0) this.endCycle = 0 if (!(simulation.cycle % (this.lookFrequency * 6))) { @@ -3508,10 +3263,7 @@ const b = { } requestAnimationFrame(respawnDrones); }, - drone(where = { - x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), - y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) - }, speed = 1) { + drone(where = { x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) }, speed = 1) { const me = bullet.length; const THRUST = 0.0015 const dir = m.angle + 0.2 * (Math.random() - 0.5); @@ -3688,7 +3440,7 @@ const b = { for (let i = 0, len = powerUp.length; i < len; ++i) { //grab, but don't lock onto nearby power up if ( Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 20000 && - (powerUp[i].name !== "heal" || m.health < 0.93 * m.maxHealth || tech.isDroneGrab) && + (powerUp[i].name !== "heal" || m.health < 0.97 * m.maxHealth || tech.isDroneGrab) && (powerUp[i].name !== "field" || !tech.isSuperDeterminism) // &&(b.inventory.length > 1 || powerUp[i].name !== "ammo" || b.guns[b.activeGun].ammo !== Infinity || tech.isDroneGrab) ) { @@ -3719,7 +3471,7 @@ const b = { let closeDist = Infinity; for (let i = 0, len = powerUp.length; i < len; ++i) { if ( - (powerUp[i].name !== "heal" || m.health < 0.93 * m.maxHealth || tech.isDroneGrab) && + (powerUp[i].name !== "heal" || m.health < 0.97 * m.maxHealth || tech.isDroneGrab) && (powerUp[i].name !== "field" || !tech.isSuperDeterminism) // &&(b.inventory.length > 1 || powerUp[i].name !== "ammo" || b.guns[b.activeGun].ammo !== Infinity || tech.isDroneGrab) ) { @@ -3748,8 +3500,7 @@ const b = { } //look for power ups to lock onto if ( - Matter.Query.ray(map, this.position, powerUp[i].position).length === 0 && - Matter.Query.ray(body, this.position, powerUp[i].position).length === 0 + Matter.Query.ray(map, this.position, powerUp[i].position).length === 0 //&& Matter.Query.ray(body, this.position, powerUp[i].position).length === 0 ) { const TARGET_VECTOR = Vector.sub(this.position, powerUp[i].position) const DIST = Vector.magnitude(TARGET_VECTOR); @@ -4545,7 +4296,7 @@ const b = { Matter.Body.setVelocity(who, velocity); } }, - targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) { + targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, damage = 1.4) { let shotsFired = 0 const targets = [] //target nearby mobs for (let i = 0, len = mob.length; i < len; i++) { @@ -4570,7 +4321,7 @@ const b = { } b.nail(position, Vector.mult(Vector.normalise(Vector.sub(WHERE, position)), speed), damage) shotsFired++ - } else if (isRandomAim) { // aim in random direction + } else { // aim in random direction const ANGLE = 2 * Math.PI * Math.random() b.nail(position, { x: speed * Math.cos(ANGLE), @@ -5634,59 +5385,9 @@ const b = { const perp2 = Vector.mult(Vector.rotate({ x: 1, y: 0 }, m.angle + Math.PI / 2), 0.6 * this.lockedOn.radius * Math.sin(simulation.cycle / this.lookFrequency)) const path = [{ x: this.vertices[0].x, y: this.vertices[0].y }, Vector.add(this.lockedOn.position, perp2)]; - 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] - }; - } - } - } - }; - const checkForCollisions = function () { - best = { - x: 1, - y: 1, - dist2: Infinity, - who: null, - v1: 1, - v2: 1 - }; - vertexCollision(path[path.length - 2], path[path.length - 1], mob); - vertexCollision(path[path.length - 2], path[path.length - 1], map); - vertexCollision(path[path.length - 2], path[path.length - 1], body); + best = { x: 1, y: 1, dist2: Infinity, who: null, v1: 1, v2: 1 }; + best = vertexCollision(path[path.length - 2], path[path.length - 1], [mob, map, body]); }; const laserHitMob = function () { if (best.who.alive) { @@ -5717,19 +5418,13 @@ const b = { } if (tech.isLaserPush) { //push mobs away const index = path.length - 1 - Matter.Body.setVelocity(best.who, { - x: best.who.velocity.x * 0.97, - y: best.who.velocity.y * 0.97 - }); + Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } } else if (tech.isLaserPush && best.who.classType === "body") { const index = path.length - 1 - Matter.Body.setVelocity(best.who, { - x: best.who.velocity.x * 0.97, - y: best.who.velocity.y * 0.97 - }); + Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } @@ -5746,20 +5441,14 @@ const b = { let lastBestOdd let lastBestEven = best.who //used in hack below if (best.dist2 !== Infinity) { //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; + path[path.length - 1] = { x: best.x, y: best.y }; laserHitMob(); for (let i = 0; i < tech.laserReflections; i++) { reflection(); checkForCollisions(); if (best.dist2 !== Infinity) { //if hitting something lastReflection = best - path[path.length - 1] = { - x: best.x, - y: best.y - }; + path[path.length - 1] = { x: best.x, y: best.y }; damage *= reflectivity laserHitMob(); //I'm not clear on how this works, but it gets rid of a bug where the laser reflects inside a block, often vertically. @@ -5947,51 +5636,9 @@ const b = { let best; let range = tech.isPlasmaRange * (120 + 300 * Math.sqrt(Math.random())) const path = [{ x: this.position.x, y: this.position.y }, { x: this.position.x + range * unit.x, y: this.position.y + range * unit.y }]; - 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 }; - vertexCollision(path[0], path[1], mob); - vertexCollision(path[0], path[1], map); - vertexCollision(path[0], path[1], body); + best = vertexCollision(path[0], path[1], [mob, map, body]); if (best.dist2 != Infinity) { //if hitting something path[path.length - 1] = { x: best.x, y: best.y }; if (best.who.alive) { @@ -6001,12 +5648,7 @@ const b = { //push mobs away const force = Vector.mult(Vector.normalise(Vector.sub(m.pos, path[1])), -0.007 * Math.min(5, best.who.mass)) Matter.Body.applyForce(best.who, path[1], force) - if (best.who.speed > 2.5) { - Matter.Body.setVelocity(best.who, { //friction - x: best.who.velocity.x * 0.75, - y: best.who.velocity.y * 0.75 - }); - } + if (best.who.speed > 2.5) Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.75, y: best.who.velocity.y * 0.75 }); //draw mob damage circle if (best.who.damageReduction) { simulation.drawList.push({ @@ -7729,7 +7371,7 @@ const b = { charge: 0, railDo() { if (this.charge > 0) { - const DRAIN = (tech.isRailEnergy ? 0.0002 : 0.002) + const DRAIN = (tech.isRailEnergy ? 0 : 0.002) //exit railgun charging without firing if (m.energy < DRAIN) { // m.energy += 0.025 + this.charge * 22 * this.drain diff --git a/js/engine.js b/js/engine.js index 3eecee3..9c79988 100644 --- a/js/engine.js +++ b/js/engine.js @@ -229,8 +229,8 @@ function collisionChecks(event) { y: mob[k].velocity.y - 8 * Math.sin(angle) }); - if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy && mob[k].damageReduction > 0) { - m.energy -= 0.33 * Math.max(m.maxEnergy, m.energy) //0.33 * m.energy + if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.1 && mob[k].damageReduction > 0) { + m.energy -= 0.1 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy if (m.immuneCycle === m.cycle + m.collisionImmuneCycles) m.immuneCycle = 0; //player doesn't go immune to collision damage mob[k].death(); simulation.drawList.push({ //add dmg to draw queue diff --git a/js/index.js b/js/index.js index a2eb61b..5c22bad 100644 --- a/js/index.js +++ b/js/index.js @@ -39,6 +39,96 @@ function shuffle(array) { } return array; } +// function vertexCollision(v1, v1End, domain, best) { +// let results +// 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) { +// best = { +// x: results.x, +// y: results.y, +// dist2: dist2, +// who: domain[i], +// v1: vertices[0], +// v2: vertices[len] +// }; +// } +// } +// } +// return best +// } +//this function is used for finding the point where a ray hits things, used for lasers mostly +function vertexCollision(v1, v1End, domains) { //= [map, body, [playerBody, playerHead]] //m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]] + let results + let best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; + for (let j = 0; j < domains.length; j++) { + let domain = domains[j] + 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) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[0], + v2: vertices[len] + }; + } + } + } + } + return best +} + //collision groups // cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.mobShield | cat.phased diff --git a/js/level.js b/js/level.js index 5292830..4e72d84 100644 --- a/js/level.js +++ b/js/level.js @@ -19,26 +19,26 @@ const level = { // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode // simulation.isHorizontalFlipped = true // tech.giveTech("performance") - // level.difficultyIncrease(8 * 2) //30 is near max on hard //60 is near max on why - // m.maxHealth = m.health = 1 + // level.difficultyIncrease(3 * 2) //30 is near max on hard //60 is near max on why + // m.maxHealth = m.health = 100000000 // m.maxEnergy = m.energy = 10000000 // tech.isRerollDamage = true // powerUps.research.changeRerolls(99999) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 // m.couplingChange(10) - // m.setField("metamaterial cloaking") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook + // m.setField("plasma torch") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook // m.energy = 0 // tech.isHookWire = true // m.energy = 0 // simulation.molecularMode = 2 // m.damage(0.1); - // b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser + // b.giveGuns("drones") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.guns[8].ammo = 100000000 // requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") }); - // for (let i = 0; i < 1; ++i) tech.giveTech("optical amplifier") - // for (let i = 0; i < 1; ++i) tech.giveTech("depolarization") + // for (let i = 0; i < 1; ++i) tech.giveTech("flame test") + // for (let i = 0; i < 1; ++i) tech.giveTech("dazzler") // for (let i = 0; i < 1; ++i) tech.giveTech("mass production") // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") }); // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) }); @@ -46,26 +46,30 @@ const level = { // for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide") // m.lastKillCycle = m.cycle - // for (let i = 0; i < 1; ++i) tech.giveTech("depolarization") + // for (let i = 0; i < 1; ++i) tech.giveTech("swarf") // for (let i = 0; i < 1; ++i) tech.giveTech("CPT symmetry") // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research"); // for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); - // level.arena(); + // spawn.mapRect(575, -700, 25, 425); //block mob line of site on testing + // level.testing(); - // for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500) - // for (let i = 0; i < 4; ++i) spawn.stinger(1900, -500) - // for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500) + // for (let i = 0; i < 1; ++i) spawn.laserLayer(1400, -500) + // Matter.Body.setPosition(player, { x: -200, y: -3330 }); + // for (let i = 0; i < 4; ++i) spawn.laserLayer(1300, -500 + 100 * Math.random()) + // for (let i = 0; i < 3; ++i) spawn.laser(1900, -500) + // for (let i = 0; i < 1; ++i) spawn.laserBombingBoss(1900, -2500) // spawn.beetleBoss(1900, -500, 25) - // spawn.slasher2(2000, -1150) // spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color) // for (let i = 0; i < 5; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random()) // tech.addJunkTechToPool(2) // tech.tech[322].frequency = 100 // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // for (let i = 0; i < 40; ++i) tech.giveTech() + level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** + // for (let i = 0; i < 2; i++) spawn.ghoster(1300, -500) //ghosters need to spawn after the map loads // spawn.bodyRect(2425, -120, 200, 200); // console.log(body[body.length - 1].mass) // simulation.isAutoZoom = false; //look in close @@ -289,8 +293,8 @@ const level = { simulation.updateTechHUD(); simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map - //pop up new level info screen for a few seconds - if (!localSettings.isHideHUD && !simulation.isChoosing && !simulation.isCheating && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor" || level.levels[level.onLevel] === "subway")) { + //pop up new level info screen for a few seconds //|| level.levels[level.onLevel] === "subway" + if (!localSettings.isHideHUD && !simulation.isCheating && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor")) { //pause if (!simulation.paused) { simulation.paused = true; @@ -325,7 +329,7 @@ const level = { simulation.draw.cons(); simulation.draw.body(); level.customTopLayer(); - let count = countMax = simulation.testing ? 0 : 180 + let count = countMax = simulation.testing ? 0 : 240 let newLevelDraw = () => { count-- if (count > 0) { @@ -346,40 +350,46 @@ const level = { simulation.wipe(); m.look(); simulation.camera(); - // if (count < 30) { - // } - // if (count < 60) { - // simulation.draw.cons(); - // simulation.draw.body(); - // level.customTopLayer(); - // simulation.draw.body(); - // simulation.draw.drawMapPath(); - // mobs.draw(); - // } else - // if (count < 240) { - - // ctx.lineDashOffset = 900 * Math.random() - // ctx.setLineDash([3, -8 + 0.5 * count]); - - const scale = 10 + const scale = 15 ctx.setLineDash([scale * (countMax - count), scale * count]); simulation.draw.wireFrame(); ctx.setLineDash([]); - - - // } - // else if (count === 91) { //hide text boss - // document.getElementById("choose-grid").style.opacity = "0" - // setTimeout(() => { - // document.getElementById("choose-grid").style.visibility = "hidden" - // }, 1000); - // } ctx.restore(); simulation.drawCursor(); } requestAnimationFrame(newLevelDraw); - } + // else { + // //pause + // if (!simulation.paused) { + // simulation.paused = true; + // simulation.isChoosing = true; //stops p from un pausing on key down + // } + // let count = countMax = simulation.testing ? 0 : 60 + // let newLevelDraw = () => { + // count-- + // if (count > 0) { + // requestAnimationFrame(newLevelDraw); + // } else { //unpause + // // if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 30; //player is immune to damage for 30 cycles + // if (simulation.paused) requestAnimationFrame(cycle); + // if (m.alive) simulation.paused = false; + // simulation.isChoosing = false; //stops p from un pausing on key down + // build.unPauseGrid() + // } + // //draw + // simulation.wipe(); + // m.look(); + // simulation.camera(); + // const scale = 30 + // ctx.setLineDash([scale * (countMax - count), scale * count]); + // simulation.draw.wireFrame(); + // ctx.setLineDash([]); + // ctx.restore(); + // simulation.drawCursor(); + // } + // requestAnimationFrame(newLevelDraw); + // } } }, unPause() { diff --git a/js/mob.js b/js/mob.js index 6f5b85c..349d687 100644 --- a/js/mob.js +++ b/js/mob.js @@ -505,89 +505,48 @@ const mobs = { ctx.fill(); } }, - laser() { - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; - if (this.seePlayer.recall && !this.isSlowed) { - const seeRange = 2500; - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - vertexCollision(this.position, look, body); - if (!m.isCloak) vertexCollision(this.position, look, [player]); - // hitting player - if (best.who === player) { - if (m.immuneCycle < m.cycle) { - const dmg = 0.0014 * simulation.dmgScale; - m.damage(dmg); - ctx.fillStyle = "#f00"; //draw damage - ctx.beginPath(); - ctx.arc(best.x, best.y, dmg * 10000, 0, 2 * Math.PI); - ctx.fill(); - } - } - //draw beam - if (best.dist2 === Infinity) { - best = look; - } - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(best.x, best.y); - ctx.strokeStyle = "#f00"; // Purple path - ctx.lineWidth = 1; - ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); - ctx.stroke(); // Draw it - ctx.setLineDash([]); - } - }, + // laser() { + // if (this.seePlayer.recall && !this.isSlowed) { + // const seeRange = 2500; + // best = { + // x: null, + // y: null, + // dist2: Infinity, + // who: null, + // v1: null, + // v2: null + // }; + // const look = { + // x: this.position.x + seeRange * Math.cos(this.angle), + // y: this.position.y + seeRange * Math.sin(this.angle) + // }; + // best = vertexCollision(this.position, look, m.isCloak ? [map, body] : [map, body, [player]]); + + // // hitting player + // if (best.who === player) { + // if (m.immuneCycle < m.cycle) { + // const dmg = 0.0014 * simulation.dmgScale; + // m.damage(dmg); + // ctx.fillStyle = "#f00"; //draw damage + // ctx.beginPath(); + // ctx.arc(best.x, best.y, dmg * 10000, 0, 2 * Math.PI); + // ctx.fill(); + // } + // } + // //draw beam + // if (best.dist2 === Infinity) { + // best = look; + // } + // ctx.beginPath(); + // ctx.moveTo(this.position.x, this.position.y); + // ctx.lineTo(best.x, best.y); + // ctx.strokeStyle = "#f00"; // Purple path + // ctx.lineWidth = 1; + // ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); + // ctx.stroke(); // Draw it + // ctx.setLineDash([]); + // } + // }, wing(a, radius = 250, ellipticity = 0.4, dmg = 0.0006) { const minorRadius = radius * ellipticity const perp = { x: Math.cos(a), y: Math.sin(a) } // @@ -658,47 +617,6 @@ const mobs = { ctx.fillStyle = "rgba(0,0,0,0.07)"; ctx.fill(); //spring to random place on map - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; - //move to a random location if (!(simulation.cycle % (this.seePlayerFreq * 4))) { best = { x: null, @@ -713,8 +631,7 @@ const mobs = { x: this.position.x + seeRange * Math.cos(this.angle), y: this.position.y + seeRange * Math.sin(this.angle) }; - vertexCollision(this.position, look, map); - vertexCollision(this.position, look, body); + best = vertexCollision(this.position, look, [map, body]); if (best.dist2 != Infinity) { if (Math.random() > 0.5) { this.springTarget.x = best.x; @@ -1135,32 +1052,8 @@ const mobs = { dmg *= tech.damageFromTech() if (this.isDropPowerUp) { if (this.health === 1) { - if (tech.isMobFullHealth) { - dmg *= 1.55 - - simulation.ephemera.push({ - name: "damage outline", - count: 5, //cycles before it self removes - vertices: this.vertices, - do() { - this.count-- - if (this.count < 0) simulation.removeEphemera(this.name) - //draw body - ctx.beginPath(); - const vertices = this.vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal) - ctx.strokeStyle = `#f05` //"rgba(150,150,225,0.5)"; - ctx.stroke(); - }, - }) - } else if (tech.isMobFullHealthCloak) { - dmg *= 1.88 - + if (tech.isMobFullHealthCloak) { + dmg *= 2.11 simulation.ephemera.push({ name: "damage outline", count: 7, //cycles before it self removes diff --git a/js/player.js b/js/player.js index 5a9876d..e0df3d5 100644 --- a/js/player.js +++ b/js/player.js @@ -559,7 +559,7 @@ const m = { // 1.25 + Math.sin(m.cycle * 0.01) if (tech.isDiaphragm) dmg *= 0.56 + 0.36 * Math.sin(m.cycle * 0.0075); if (tech.isZeno) dmg *= 0.15 - if (tech.isFieldHarmReduction) dmg *= 0.5 + if (tech.isFieldHarmReduction) dmg *= 0.65 if (tech.isHarmMACHO) dmg *= 0.4 if (tech.isImmortal) dmg *= 0.7 if (tech.energyRegen === 0) dmg *= 0.34 @@ -2192,7 +2192,7 @@ const m = { } }, setMaxEnergy(isMessage = true) { - m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2.66 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 1.5 * (m.fieldMode === 1) + (m.fieldMode === 0 || m.fieldMode === 1) * 0.05 * m.coupling + 0.4 * tech.isStandingWaveExpand + m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2.66 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 1.5 * (m.fieldMode === 1) + (m.fieldMode === 0 || m.fieldMode === 1) * 0.05 * m.coupling + 0.77 * tech.isStandingWaveExpand if (isMessage) simulation.makeTextLog(`m.maxEnergy = ${(m.maxEnergy.toFixed(2))}`) }, fieldMeterColor: "#0cf", @@ -2243,6 +2243,8 @@ const m = { m.fieldRegen = 0.001667 //10 energy per second plasma torch } else if (m.fieldMode === 8) { m.fieldRegen = 0.001667 //10 energy per second pilot wave + } else if (m.fieldMode === 10) { + m.fieldRegen = 0.0015 //9 energy per second grappling hook } else { m.fieldRegen = 0.001 //6 energy per second } @@ -3631,15 +3633,9 @@ const m = { // if (!this.isAttached && !mob[i].isMobBullet) this.isPopping = true mob[i].damage(dmg); if (mob[i].speed > 5) { - Matter.Body.setVelocity(mob[i], { //friction - x: mob[i].velocity.x * 0.6, - y: mob[i].velocity.y * 0.6 - }); + Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.6, y: mob[i].velocity.y * 0.6 }); } else { - Matter.Body.setVelocity(mob[i], { //friction - x: mob[i].velocity.x * 0.93, - y: mob[i].velocity.y * 0.93 - }); + Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.93, y: mob[i].velocity.y * 0.93 }); } } else if (sub < dischargeRange + mob[i].radius && Matter.Query.ray(map, mob[i].position, this.position).length === 0) { arcList.push(mob[i]) //populate electrical arc list @@ -3684,10 +3680,7 @@ const m = { //slowly slow down if too fast if (this.speed > 10) { const scale = 0.998 - Matter.Body.setVelocity(this, { - x: scale * this.velocity.x, - y: scale * this.velocity.y - }); + Matter.Body.setVelocity(this, { x: scale * this.velocity.x, y: scale * this.velocity.y }); } //graphics @@ -3703,10 +3696,7 @@ const m = { ctx.arc(this.position.x, this.position.y, radius, 0, 2 * Math.PI); ctx.fill(); //draw arcs - const unit = Vector.rotate({ - x: 1, - y: 0 - }, Math.random() * 6.28) + const unit = Vector.rotate({ x: 1, y: 0 }, Math.random() * 6.28) let len = 8 const step = this.circleRadius / len let x = this.position.x @@ -3761,13 +3751,6 @@ const m = { // m.plasmaBall.reset() } - // const scale = 0.7 - // Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast - // if (m.plasmaBall.circleRadius < m.plasmaBall.radiusLimit) { - // m.plasmaBall.isAttached = true - // m.plasmaBall.isOn = true - // m.plasmaBall.setPositionToNose() - // } } else if (m.energy > m.plasmaBall.drain) { //charge up when attached if (tech.isCapacitor) { m.energy -= m.plasmaBall.drain * 2; @@ -4233,16 +4216,14 @@ const m = { //not shooting (or using field) enable cloak if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle if (m.fireCDcycle + 10 < m.cycle && !input.fire) { //automatically cloak if not firing - const drain = 0.02 - if (!m.isCloak && m.energy > drain + 0.03) { - m.energy -= drain + // const drain = 0.02 + if (!m.isCloak) { //&& m.energy > drain + 0.03 + // m.energy -= drain m.isCloak = true //enter cloak m.fieldHarmReduction = 0.33; //66% reduction m.enterCloakCycle = m.cycle if (tech.isCloakHealLastHit && m.lastHit > 0) { const heal = Math.min(0.75 * m.lastHit, m.energy) - // if (m.energy > heal) { - // m.energy -= heal * 0.8 m.addHealth(heal); //heal from last hit m.lastHit = 0 simulation.drawList.push({ //add dmg to draw queue @@ -4252,7 +4233,6 @@ const m = { color: "rgba(0,255,200,0.6)", time: 16 }); - // } } if (tech.isIntangible) { for (let i = 0; i < bullet.length; i++) { @@ -4272,26 +4252,26 @@ const m = { } if (tech.isCloakStun) { //stun nearby mobs after exiting cloak let isMobsAround = false - const stunRange = m.fieldDrawRadius * 1.5 - const drain = 0.1 - if (m.energy > drain) { - for (let i = 0, len = mob.length; i < len; ++i) { - if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) < stunRange && Matter.Query.ray(map, mob[i].position, m.pos).length === 0 && !mob[i].isBadTarget) { - isMobsAround = true - mobs.statusStun(mob[i], 180) - } - } - if (isMobsAround) { - m.energy -= drain - simulation.drawList.push({ - x: m.pos.x, - y: m.pos.y, - radius: stunRange, - color: "hsla(0,50%,100%,0.7)", - time: 7 - }); + const stunRange = m.fieldDrawRadius * 1.25 + // const drain = 0.01 + // if (m.energy > drain) { + for (let i = 0, len = mob.length; i < len; ++i) { + if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) < stunRange && Matter.Query.ray(map, mob[i].position, m.pos).length === 0 && !mob[i].isBadTarget) { + isMobsAround = true + mobs.statusStun(mob[i], 120) } } + // if (isMobsAround) { + // m.energy -= drain + // simulation.drawList.push({ + // x: m.pos.x, + // y: m.pos.y, + // radius: stunRange, + // color: "hsla(0,50%,100%,0.7)", + // time: 7 + // }); + // } + // } } } @@ -4580,13 +4560,13 @@ const m = { { name: "wormhole", //wormholes attract blocks and power ups
- description: "use energy to tunnel through a wormhole
+5% chance to duplicate spawned power ups
generate 6 energy per second", //
bullets may also traverse wormholes + description: "use energy to tunnel through a wormhole
+7% chance to duplicate spawned power ups
generate 6 energy per second", //
bullets may also traverse wormholes drain: 0, effect: function () { m.fieldMeterColor = "#bbf" //"#0c5" m.eyeFillColor = m.fieldMeterColor - m.duplicateChance = 0.05 + m.duplicateChance = 0.07 m.fieldRange = 0 powerUps.setPowerUpMode(); //needed after adjusting duplication chance @@ -4639,10 +4619,7 @@ const m = { if (dist2 < 600000) { //&& !(m.health === m.maxHealth && powerUp[i].name === "heal") powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity - Matter.Body.setVelocity(powerUp[i], { //extra friction - x: powerUp[i].velocity.x * 0.05, - y: powerUp[i].velocity.y * 0.05 - }); + Matter.Body.setVelocity(powerUp[i], { x: powerUp[i].velocity.x * 0.05, y: powerUp[i].velocity.y * 0.05 }); if (dist2 < 1000 && !simulation.isChoosing) { //use power up if it is close enough // if (true) { //AoE radiation effect @@ -4811,10 +4788,7 @@ const m = { this.drain = tech.isFreeWormHole ? 0 : 0.05 + 0.005 * Math.sqrt(mag) } const unit = Vector.perp(Vector.normalise(sub)) - const where = { - x: m.pos.x + 30 * Math.cos(m.angle), - y: m.pos.y + 30 * Math.sin(m.angle) - } + const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025)) const edge2a = Vector.add(Vector.mult(unit, 1.5 * m.fieldRange), simulation.mouseInGame) const edge2b = Vector.add(Vector.mult(unit, -1.5 * m.fieldRange), simulation.mouseInGame) @@ -5135,7 +5109,7 @@ const m = { { name: "grappling hook", // description: `use energy to pull yourself towards the map
generate 6 energy per second`, - description: `use energy to fire a hook that pulls player
damages mobs and grabs blocks
generate 6 energy per second`, + description: `use energy to fire a hook that pulls player
damages mobs and grabs blocks
generate 9 energy per second`, effect: () => { m.fieldFire = true; // m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping @@ -5159,7 +5133,7 @@ const m = { m.grabPowerUp(); } else { m.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 (tech.isHookDefense && m.energy > 0.33 && m.fieldCDcycle < m.cycle) { + if (tech.isHookDefense && m.energy > 0.15 && m.fieldCDcycle < m.cycle) { const range = 300 for (let i = 0; i < mob.length; i++) { if (!mob[i].isBadTarget && @@ -5167,7 +5141,7 @@ const m = { Vector.magnitude(Vector.sub(m.pos, mob[i].position)) < range && Matter.Query.ray(map, m.pos, mob[i].position).length === 0 ) { - m.energy -= 0.18 + m.energy -= 0.1 if (m.fieldCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 30 const angle = Math.atan2(mob[i].position.y - player.position.y, mob[i].position.x - player.position.x); b.harpoon(m.pos, mob[i], angle, 0.75, true, 20) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) { diff --git a/js/powerup.js b/js/powerup.js index 5292b4d..c836f6e 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -332,7 +332,7 @@ const powerUps = { simulation.circleFlare(0.043); } if (tech.isCancelRerolls) { - for (let i = 0, len = 6 + 6 * Math.random(); i < len; i++) { + for (let i = 0, len = 10 + 4 * Math.random(); i < len; i++) { let spawnType if (Math.random() < 0.4 && !tech.isEnergyNoAmmo) { spawnType = "ammo" diff --git a/js/spawn.js b/js/spawn.js index a13550e..9f7c1df 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -26,16 +26,17 @@ const spawn = { "springer", "springer", "springer", "stinger", "stinger", "stinger", "flutter", "flutter", + "striker", "striker", "shooter", "shooter", "grenadier", "grenadier", - "striker", "striker", - "laser", "laser", "pulsar", "pulsar", + "laser", "laser", + "laserLayer", "laserLayer", "sneaker", "launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser" ], mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed mobTypeSpawnIndex: 0, //increases as the mob type cycles - allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter", "stinger"], + allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter", "stinger", "laserLayer"], setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level spawn.pickList.splice(0, 1); const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length] @@ -892,43 +893,6 @@ const spawn = { }; } me.lasers = function (where, angle, dmg = 0.1 * simulation.dmgScale) { - 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) best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - }; - const seeRange = 7000; best = { x: null, @@ -942,10 +906,7 @@ const spawn = { x: where.x + seeRange * Math.cos(angle), y: where.y + seeRange * Math.sin(angle) }; - // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - vertexCollision(where, look, body); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { if (m.immuneCycle < m.cycle + 60 + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 60 + m.collisionImmuneCycles; //player is immune to damage extra time m.damage(dmg); @@ -1101,499 +1062,6 @@ const spawn = { } }; }, - // finalBoss(x, y, radius = 300) { - // mobs.spawn(x, y, 6, radius, "rgb(150,150,255)"); - // let me = mob[mob.length - 1]; - // setTimeout(() => { //fix mob in place, but allow rotation - // me.constraint = Constraint.create({ - // pointA: { - // x: me.position.x, - // y: me.position.y - // }, - // bodyB: me, - // stiffness: 1, - // damping: 1 - // }); - // Composite.add(engine.world, me.constraint); - // }, 2000); //add in a delay in case the level gets flipped left right - // me.isBoss = true; - // me.isFinalBoss = true; - // me.frictionAir = 0.01; - // me.memory = Infinity; - // me.hasRunDeathScript = false - // me.locatePlayer(); - // // const density = 0.2 - // Matter.Body.setDensity(me, 0.2); //extra dense //normal is 0.001 //makes effective life much larger - // // spawn.shield(me, x, y, 1); - // me.onDamage = function() {}; - // me.cycle = 660; - // me.endCycle = 780; - // me.totalCycles = 0 - // me.mode = 0; - // me.damageReduction = 0.25 //reset on each new mode - // me.pushAway = function(magX = 0.13, magY = 0.05) { - // for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally - // body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1) - // body[i].force.y -= magY * body[i].mass - // } - // for (let i = 0, len = bullet.length; i < len; ++i) { //push blocks away horizontally - // bullet[i].force.x += magX * bullet[i].mass * (bullet[i].position.x > this.position.x ? 1 : -1) - // bullet[i].force.y -= magY * bullet[i].mass - // } - // for (let i = 0, len = powerUp.length; i < len; ++i) { //push blocks away horizontally - // powerUp[i].force.x += magX * powerUp[i].mass * (powerUp[i].position.x > this.position.x ? 1 : -1) - // powerUp[i].force.y -= magY * powerUp[i].mass - // } - // player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1) - // player.force.y -= magY * player.mass - // } - // me.do = function() { - // this.modeDo(); //this does different things based on the mode - // this.checkStatus(); - // this.cycle++; //switch modes÷ if time isn't paused - // this.totalCycles++; - // if (this.health > 0.3) { - // if (this.cycle > this.endCycle) { - // this.showHealthBar = true - // this.cycle = 0; - // this.mode++ - // this.damageReduction = 0.25 - // if (this.totalCycles > 180) this.pushAway(); - // if (this.mode > 3) { - // this.mode = 0; - // this.fill = "#50f"; - // this.rotateVelocity = Math.abs(this.rotateVelocity) * (player.position.x > this.position.x ? 1 : -1) //rotate so that the player can get away - // this.modeDo = this.modeLasers - // //push blocks and player away, since this is the end of suck, and suck causes blocks to fall on the boss and stun it - // Matter.Body.scale(this, 1000, 1000); - // if (!this.isShielded) spawn.shield(this, this.position.x, this.position.y, 1); // regen shield to also prevent stun - // } else if (this.mode === 1) { - // this.fill = "#50f"; // this.fill = "rgb(150,150,255)"; - // this.modeDo = this.modeSpawns - // } else if (this.mode === 2) { - // this.fill = "#50f"; - // this.modeDo = this.modeBombs - // } else if (this.mode === 3) { - // for (let i = 0; i < mob.length; i++) { - // if (mob[i].isMine) mob[i].isExploding = true //explode the mines at the start of new round - // } - // this.fill = "#000"; - // this.modeDo = this.modeSuck - // Matter.Body.scale(this, 0.001, 0.001); - // this.damageReduction = 0.000025 - // this.showHealthBar = false - // } - - // if (tech.isGunCycle) { - // b.inventoryGun++; - // if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0; - // simulation.switchGun(); - // } - // } - // } else if (this.mode !== 3) { //all three modes at once , this runs once - // this.showHealthBar = true - // this.pushAway(); - // this.cycle = 0; - // this.endCycle = Infinity - // this.damageReduction = 0.15 - // if (this.mode === 2) { - // Matter.Body.scale(this, 500, 500); - // } else { - // Matter.Body.scale(this, 0.5, 0.5); - // } - // this.mode = 3 - // this.fill = "#000"; - // this.eventHorizon = 750 - // this.spawnInterval = 600 - // this.rotateVelocity = 0.001 * (player.position.x > this.position.x ? 1 : -1) //rotate so that the player can get away - // // if (!this.isShielded) spawn.shield(this, x, y, 1); //regen shield here ? - // this.modeDo = this.modeAll - // this.eventHorizonRadius = 700 - // if (tech.isGunCycle) { - // b.inventoryGun++; - // if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0; - // simulation.switchGun(); - // } - // } - // // } - // }; - // me.modeDo = function() {} - // me.modeAll = function() { - // this.modeBombs() - // this.modeSpawns() - // this.modeSuck() - // this.modeLasers() - // } - // me.bombInterval = 36 - 0.5 * simulation.difficultyMode * simulation.difficultyMode - // me.modeBombs = function() { - // if (!(this.cycle % 20)) { - // if (m.pos.x < 750) { - // spawn.mine(m.pos.x + 200 * (Math.random() - 0.5), -500) - // } else { - // spawn.mine(Math.min(Math.max(770, m.pos.x + 200 * (Math.random() - 0.5)), 5350), -1500) - // } - // } - // if (!(this.cycle % 10)) spawn.mine(800 + 4550 * Math.random(), -1500) - - // //mines fall - // for (let i = 0; i < mob.length; i++) { - // // if (mob[i].isMine && mob[i].position.y < -5) Matter.Body.setPosition(mob[i], { x: mob[i].position.x, y: mob[i].position.y + 5 }) - // if (mob[i].isMine && mob[i].position.y < -14) mob[i].force.y += mob[i].mass * 0.03; - // } - - // } - // me.spawnInterval = 395 - // me.modeSpawns = function() { - // if (!(this.cycle % this.spawnInterval) && mob.length < 40) { - // if (this.mode !== 3) Matter.Body.setAngularVelocity(this, 0.1) - // //fire a bullet from each vertex - // const whoSpawn = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; - // for (let i = 0, len = 2 + this.totalCycles / 1000; i < len; i++) { - // const vertex = this.vertices[i % 6] - // spawn[whoSpawn](vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5)); - // const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex - // Matter.Body.setVelocity(mob[mob.length - 1], { - // x: this.velocity.x + velocity.x, - // y: this.velocity.y + velocity.y - // }); - // } - // if (!(this.cycle % 2 * this.spawnInterval) && mob.length < 40) { - // const len = (this.totalCycles / 1000 + simulation.difficulty / 2 - 30) / 15 - // for (let i = 0; i < len; i++) { - // spawn.randomLevelBoss(3000 * (simulation.isHorizontalFlipped ? -1 : 1) + 2000 * (Math.random() - 0.5), -1100 + 200 * (Math.random() - 0.5)) - // } - // } - // } - // } - // me.eventHorizon = 0 - // me.eventHorizonRadius = 1300 - // me.modeSuck = function() { - // if (!(this.cycle % 30)) { - // const index = Math.floor((this.cycle % 360) / 60) - // spawn.seeker(this.vertices[index].x, this.vertices[index].y, 20 * (0.5 + Math.random()), 9); //give the bullet a rotational velocity as if they were attached to a vertex - // const who = mob[mob.length - 1] - // Matter.Body.setDensity(who, 0.00003); //normal is 0.001 - // who.timeLeft = 720 + 10 * simulation.difficulty //* (0.8 + 0.4 * Math.random()); - // who.accelMag = 0.0003 * simulation.accelScale; //* (0.8 + 0.4 * Math.random()) - // who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random()); - // const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[index]))), -7) - // Matter.Body.setVelocity(who, { - // x: this.velocity.x + velocity.x, - // y: this.velocity.y + velocity.y - // }); - // } - - // //eventHorizon waves in and out - // if (this.cycle + 30 > this.endCycle) { //shrink fast in last bit of cycle - // this.eventHorizon = 0.93 * this.eventHorizon - // } else { - // this.eventHorizon = 0.97 * this.eventHorizon + 0.03 * (this.eventHorizonRadius * (1 - 0.5 * Math.cos(this.cycle * 0.015))) - // } - // //draw darkness - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.2, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(0,20,40,0.6)"; - // ctx.fill(); - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.4, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(0,20,40,0.4)"; - // ctx.fill(); - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.6, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(0,20,40,0.3)"; - // ctx.fill(); - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.8, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(0,20,40,0.2)"; - // ctx.fill(); - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(0,0,0,0.05)"; - // ctx.fill(); - // //when player is inside event horizon - // if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) { - // if (m.immuneCycle < m.cycle) { - // if (m.energy > 0) m.energy -= 0.02 - // if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0004 * simulation.dmgScale); - // } - // const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); - // player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1); - // player.force.y -= 0.0017 * Math.sin(angle) * player.mass; - // //draw line to player - // ctx.beginPath(); - // ctx.moveTo(this.position.x, this.position.y); - // ctx.lineTo(m.pos.x, m.pos.y); - // ctx.lineWidth = Math.min(60, this.radius * 2); - // ctx.strokeStyle = "rgba(0,0,0,0.5)"; - // ctx.stroke(); - // ctx.beginPath(); - // ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(0,0,0,0.3)"; - // ctx.fill(); - // } - // this.curl(this.eventHorizon); - // } - // me.rotateVelocity = 0.0025 - // me.rotateCount = 0; - // me.lasers = function(where, angle, dmg = 0.14 * simulation.dmgScale) { - // 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) best = { - // x: results.x, - // y: results.y, - // dist2: dist2, - // who: domain[i], - // v1: vertices[0], - // v2: vertices[len] - // }; - // } - // } - // }; - - // const seeRange = 7000; - // best = { - // x: null, - // y: null, - // dist2: Infinity, - // who: null, - // v1: null, - // v2: null - // }; - // const look = { - // x: where.x + seeRange * Math.cos(angle), - // y: where.y + seeRange * Math.sin(angle) - // }; - // // vertexCollision(where, look, mob); - // vertexCollision(where, look, map); - // vertexCollision(where, look, body); - // if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); - // if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { - // if (m.immuneCycle < m.cycle + 60 + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 60 + m.collisionImmuneCycles; //player is immune to damage extra time - // m.damage(dmg); - // simulation.drawList.push({ //add dmg to draw queue - // x: best.x, - // y: best.y, - // radius: dmg * 1500, - // color: "rgba(80,0,255,0.5)", - // time: 20 - // }); - // } - // //draw beam - // if (best.dist2 === Infinity) best = look; - // ctx.moveTo(where.x, where.y); - // ctx.lineTo(best.x, best.y); - // } - // me.modeLasers = function() { - // if (!this.isStunned) { - // let slowed = false //check if slowed - // for (let i = 0; i < this.status.length; i++) { - // if (this.status[i].type === "slow") { - // slowed = true - // break - // } - // } - // if (!slowed) { - // this.rotateCount++ - // Matter.Body.setAngle(this, this.rotateCount * this.rotateVelocity) - // Matter.Body.setAngularVelocity(this, 0) - // Matter - // } - // } - // if (this.cycle < 240) { //damage scales up over 2 seconds to give player time to move - // const scale = this.cycle / 240 - // const dmg = (this.cycle < 120) ? 0 : 0.14 * simulation.dmgScale * scale - // ctx.beginPath(); - // this.lasers(this.vertices[0], this.angle + Math.PI / 6, dmg); - // this.lasers(this.vertices[1], this.angle + 3 * Math.PI / 6, dmg); - // this.lasers(this.vertices[2], this.angle + 5 * Math.PI / 6, dmg); - // this.lasers(this.vertices[3], this.angle + 7 * Math.PI / 6, dmg); - // this.lasers(this.vertices[4], this.angle + 9 * Math.PI / 6, dmg); - // this.lasers(this.vertices[5], this.angle + 11 * Math.PI / 6, dmg); - // ctx.strokeStyle = "#50f"; - // ctx.lineWidth = 1.5 * scale; - // ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); - // ctx.stroke(); // Draw it - // ctx.setLineDash([]); - // ctx.lineWidth = 20; - // ctx.strokeStyle = `rgba(80,0,255,${0.07 * scale})`; - // ctx.stroke(); // Draw it - // } else { - // ctx.beginPath(); - // this.lasers(this.vertices[0], this.angle + Math.PI / 6); - // this.lasers(this.vertices[1], this.angle + 3 * Math.PI / 6); - // this.lasers(this.vertices[2], this.angle + 5 * Math.PI / 6); - // this.lasers(this.vertices[3], this.angle + 7 * Math.PI / 6); - // this.lasers(this.vertices[4], this.angle + 9 * Math.PI / 6); - // this.lasers(this.vertices[5], this.angle + 11 * Math.PI / 6); - // ctx.strokeStyle = "#50f"; - // ctx.lineWidth = 1.5; - // ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); - // ctx.stroke(); // Draw it - // ctx.setLineDash([]); - // ctx.lineWidth = 20; - // ctx.strokeStyle = "rgba(80,0,255,0.07)"; - // ctx.stroke(); // Draw it - // } - // } - // me.onDeath = function() { - // if (!this.hasRunDeathScript) { - // this.hasRunDeathScript = true - // //make a block body to replace this one - // //this body is too big to leave behind in the normal way mobs.replace() - // const len = body.length; - // const v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure - // body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v); - // Matter.Body.setVelocity(body[len], { x: 0, y: -3 }); - // Matter.Body.setAngularVelocity(body[len], this.angularVelocity); - // body[len].collisionFilter.category = cat.body; - // body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; - // body[len].classType = "body"; - // Composite.add(engine.world, body[len]); //add to world - // const expand = function(that, massLimit) { - // const scale = 1.05; - // Matter.Body.scale(that, scale, scale); - // if (that.mass < massLimit) setTimeout(expand, 20, that, massLimit); - // }; - // expand(body[len], 200) - - // function unlockExit() { - // if (simulation.isHorizontalFlipped) { - // level.exit.x = -5500 - 100; - // } else { - // level.exit.x = 5500; - // } - // level.exit.y = -330; - // Matter.Composite.remove(engine.world, map[map.length - 1]); - // map.splice(map.length - 1, 1); - // simulation.draw.setPaths(); //redraw map draw path - // // level.levels.push("null") - // } - - // //add lore level as next level if player took lore tech earlier in the game - // if (lore.techCount > (lore.techGoal - 1) && !simulation.isCheating) { - // simulation.makeTextLog(`undefined = ${lore.techCount}/${lore.techGoal}`, 360); - // setTimeout(function() { - // simulation.makeTextLog(`level.levels.push("null")`, 720); - // unlockExit() - // level.levels.push("null") - // }, 4000); - // //remove block map element so exit is clear - // } else { //reset game - // let count = 0 - - // function loop() { - // if (!simulation.paused && !simulation.onTitlePage) { - // count++ - // if (count < 660) { - // if (count === 1) simulation.makeTextLog(`//enter testing mode to set level.levels.length to Infinite`); - // if (!(count % 60)) simulation.makeTextLog(`simulation.analysis = ${((count / 60 - Math.random()) * 0.1).toFixed(3)}`); - // } else if (count === 660) { - // simulation.makeTextLog(`simulation.analysis = 1 //analysis complete`); - // } else if (count === 780) { - // simulation.makeTextLog(`undefined = ${lore.techCount}/${lore.techGoal}`) - // } else if (count === 1020) { - // simulation.makeTextLog(`Engine.clear(engine) //simulation successful`); - // } else if (count === 1260) { - // // tech.isImmortal = false; - // // m.death() - // // m.alive = false; - // // simulation.paused = true; - // // m.health = 0; - // // m.displayHealth(); - // document.getElementById("health").style.display = "none" - // document.getElementById("health-bg").style.display = "none" - // document.getElementById("text-log").style.opacity = 0; //fade out any active text logs - // document.getElementById("fade-out").style.opacity = 1; //slowly fades out - // // build.shareURL(false) - // setTimeout(function() { - // if (!simulation.onTitlePage) { - // simulation.paused = true; - // // simulation.clearMap(); - // // Matter.Composite.clear(composite, keepStatic, [deep = false]) - // // Composite.clear(engine.composite); - // engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) }) - // Engine.clear(engine); - // simulation.splashReturn(); - // } - // }, 6000); - // return - // } - // } - // if (simulation.testing) { - // unlockExit() - // setTimeout(function() { - // simulation.makeTextLog(`level.levels.length = Infinite`); - // }, 1500); - // } else { - // if (!simulation.onTitlePage) requestAnimationFrame(loop); - // } - // } - // requestAnimationFrame(loop); - // } - // // for (let i = 0; i < 3; i++) - // level.difficultyIncrease(simulation.difficultyMode) //ramp up damage - // //remove power Ups, to avoid spamming console - // function removeAll(array) { - // for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]); - // } - // removeAll(powerUp); - // powerUp = []; - - // //pull in particles - // for (let i = 0, len = body.length; i < len; ++i) { - // const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, body[i].position)), 65) - // const pushUp = Vector.add(velocity, { x: 0, y: -0.5 }) - // Matter.Body.setVelocity(body[i], Vector.add(body[i].velocity, pushUp)); - // } - // //damage all mobs - // for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die - // for (let i = 0, len = mob.length; i < len; ++i) { - // if (mob[i] !== this) { - // if (mob[i].isInvulnerable) { //disable invulnerability - // mob[i].isInvulnerable = false - // mob[i].damageReduction = 1 - // } - // mob[i].damage(Infinity, true); - // } - // } - // } - - // //draw stuff - // for (let i = 0, len = 22; i < len; i++) { - // simulation.drawList.push({ //add dmg to draw queue - // x: this.position.x, - // y: this.position.y, - // radius: (i + 1) * 150, - // color: `rgba(255,255,255,0.17)`, - // time: 5 * (len - i + 1) - // }); - // } - // } - // }; - // }, zombie(x, y, radius, sides, color) { //mob that attacks other mobs mobs.spawn(x, y, sides, radius, color); let me = mob[mob.length - 1]; @@ -2229,7 +1697,7 @@ const spawn = { me.isInvulnerable = true me.startingDamageReduction = me.damageReduction me.damageReduction = 0 - me.invulnerabilityCountDown = 40 + simulation.difficulty + me.invulnerabilityCountDown = 25 + simulation.difficulty me.onHit = function () { //run this function on hitting player if (powerUps.ejectTech()) { powerUps.ejectGraphic("150, 138, 255"); @@ -2276,10 +1744,7 @@ const spawn = { for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) { powerUp[i].collisionFilter.mask = 0 Matter.Body.setPosition(powerUp[i], this.vertices[i]) - Matter.Body.setVelocity(powerUp[i], { - x: 0, - y: 0 - }) + Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 }) } } this.seePlayerByHistory(50); @@ -2294,7 +1759,7 @@ const spawn = { me.frictionAir = 0.01 me.seeAtDistance2 = 1000000; me.accelMag = 0.0002 + 0.0004 * simulation.accelScale; - Matter.Body.setDensity(me, 0.00035); //normal is 0.001 + Matter.Body.setDensity(me, 0.0003); //normal is 0.001 me.collisionFilter.mask = cat.bullet | cat.player //| cat.body me.memory = Infinity; me.seePlayerFreq = 30 @@ -2308,7 +1773,7 @@ const spawn = { me.foundPlayer(); } - me.damageReduction = 0.16 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0.15 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) // me.isInvulnerable = true // me.startingDamageReduction = me.damageReduction // me.damageReduction = 0 @@ -3215,10 +2680,7 @@ const spawn = { me.seePlayerFreq = 31; const springStiffness = 0.00003; //simulation.difficulty const springDampening = 0.0002; - me.springTarget = { - x: me.position.x, - y: me.position.y - }; + me.springTarget = { x: me.position.x, y: me.position.y }; const len = cons.length; cons[len] = Constraint.create({ pointA: me.springTarget, @@ -3314,47 +2776,6 @@ const spawn = { } else { this.torque = this.lookTorque * this.inertia; //spring to random place on map - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; - //move to a random location if (!(simulation.cycle % (this.seePlayerFreq))) { best = { x: null, @@ -3365,11 +2786,8 @@ const spawn = { v2: null }; const seeRange = 3000; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); + const look = { x: this.position.x + seeRange * Math.cos(this.angle), y: this.position.y + seeRange * Math.sin(this.angle) }; + best = vertexCollision(this.position, look, [map]); if (best.dist2 != Infinity) { this.springTarget.x = best.x; this.springTarget.y = best.y; @@ -3899,46 +3317,6 @@ const spawn = { const seeRange = 550 + 35 * simulation.difficultyMode; if (this.distanceToPlayer() < seeRange) { - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; best = { x: null, y: null, @@ -3948,13 +3326,8 @@ const spawn = { v2: null }; const seeRangeRandom = seeRange - 200 - 150 * Math.random() - const look = { - x: this.position.x + seeRangeRandom * Math.cos(this.angle), - y: this.position.y + seeRangeRandom * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - vertexCollision(this.position, look, body); - if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]); + const look = { x: this.position.x + seeRangeRandom * Math.cos(this.angle), y: this.position.y + seeRangeRandom * Math.sin(this.angle) }; + best = vertexCollision(this.position, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); // hitting player if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { @@ -4272,46 +3645,6 @@ const spawn = { this.torque -= 0.000004 * this.inertia; } if (simulation.cycle % this.laserInterval > this.laserInterval / 2) { - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; const seeRange = 8000; best = { x: null, @@ -4321,13 +3654,8 @@ const spawn = { v1: null, v2: null }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - vertexCollision(this.position, look, body); - if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]); + const look = { x: this.position.x + seeRange * Math.cos(this.angle), y: this.position.y + seeRange * Math.sin(this.angle) }; + best = vertexCollision(this.position, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); // hitting player if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { @@ -4390,26 +3718,6 @@ const spawn = { me.targetingCount = 0; me.targetingTime = 60 - Math.min(58, 3 * simulation.difficulty) me.do = function () { - - // //wings - // const wing = (simulation.cycle % 9) > 4 ? this.vertices[0] : this.vertices[2] //Vector.add(this.position, { x: 100, y: 0 }) - // const radius = 200 - // //draw - // ctx.beginPath(); - // ctx.arc(wing.x, wing.y, radius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay - // ctx.fillStyle = "rgba(0,235,255,0.3)"; - // ctx.fill(); - // //check damage - // const hitPlayer = Matter.Query.ray([player], this.position, wing, radius) - // if (hitPlayer.length && m.immuneCycle < m.cycle) { - // m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage - // m.damage(0.02 * simulation.dmgScale); - // } - - - - - this.seePlayerByLookingAt(); this.checkStatus(); this.attraction(); @@ -4427,46 +3735,6 @@ const spawn = { } else if (c < -threshold) { this.torque -= 0.000004 * this.inertia; } - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; const seeRange = 8000; best = { @@ -4477,12 +3745,8 @@ const spawn = { v1: null, v2: null }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]); + const look = { x: this.position.x + seeRange * Math.cos(this.angle), y: this.position.y + seeRange * Math.sin(this.angle) }; + best = vertexCollision(this.position, look, m.isCloak ? [map] : [map, [playerBody, playerHead]]); // hitting player if (best.who === playerBody || best.who === playerHead) { @@ -4844,6 +4108,152 @@ const spawn = { } }; }, + laserLayer(x, y, radius = 18 + Math.floor(6 * Math.random())) { + const color = "#f09" + mobs.spawn(x, y, 4, radius, color); + let me = mob[mob.length - 1]; + me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front + for (let i = 0; i < 4; i += 2) { + let spike = Vector.mult(Vector.normalise(Vector.sub(me.vertices[i], me.position)), radius * 2) + me.vertices[i].x = me.position.x + spike.x + me.vertices[i].y = me.position.y + spike.y + } + Matter.Body.rotate(me, Math.random() * Math.PI * 2); + me.accelMag = 0.0002 * simulation.accelScale; + // me.frictionAir = 1 + + me.lasers = [] //keeps track of static laser beams + me.laserLimit = simulation.difficultyMode < 3 ? 1 : 2 + me.fireDelay = Math.max(75, 140 - simulation.difficulty * 0.5) + me.cycle = 0 + me.laserDelay = 150 + Math.floor(Math.random() * 120) + me.addLaser = function () { + if (this.cycle > this.laserDelay) { + this.cycle = 0 + const seeRange = 6000; + const angle = this.angle + Math.PI / 4 + const v1 = { x: this.position.x + seeRange * Math.cos(angle), y: this.position.y + seeRange * Math.sin(angle) }; + const v2 = { x: this.position.x + seeRange * Math.cos(angle + Math.PI), y: this.position.y + seeRange * Math.sin(angle + Math.PI) }; + //find where v1,v2 hit walls and make them stop there + let best1 = vertexCollision(this.position, v1, [map]); + let best2 = vertexCollision(this.position, v2, [map]); + if (best2.who === null) { + best2.x = v2.x + best2.y = v2.y + } + if (best1.who === null) { //if the path never hits the map , just stop at seeRange + best1.x = v1.x + best1.y = v1.y + } + if (best1.y > best2.y) { //make laser beams always fire from top to bottom so they are predicable, and not stopped by blocks on the ground + const save1X = best1.x + const save1Y = best1.y + best1.x = best2.x + best1.y = best2.y + best2.x = save1X + best2.y = save1Y + } + + this.lasers.push({ a: { x: best1.x, y: best1.y }, b: { x: best2.x, y: best2.y }, fade: 0 }) + //friction to animate the mob dropping something + Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.05)); + Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.05) + // simulation.drawList.push({ x: best1.x, y: best1.y, radius: 10, color: "rgba(255,0,100,0.3)", time: simulation.drawTime * 2 }); + // simulation.drawList.push({ x: best2.x, y: best2.y, radius: 10, color: "rgba(255,0,100,0.3)", time: simulation.drawTime * 2 }); + + if (this.lasers.length > this.laserLimit) this.lasers.shift() //cap total lasers + if (!this.seePlayer.recall && (Vector.magnitude(Vector.sub(this.position, this.driftGoal)) < 200 || 0.3 > Math.random())) { + //used in drift when can't find player + const radius = Math.random() * 1000; + const angle = Math.random() * 2 * Math.PI; + this.driftGoal = Vector.add(this.driftCenter, { x: radius * Math.cos(angle), y: radius * Math.sin(angle) }) + } + } + } + me.fireLaser = function () { + for (let i = 0; i < this.lasers.length; i++) { //fire all lasers in the array + let best = vertexCollision(this.lasers[i].a, this.lasers[i].b, m.isCloak ? [body] : [body, [playerBody, playerHead]]); //not checking map to fix not hitting player bug, this might make some lasers look strange when the map changes + if (this.lasers[i].fade > 0.99) { + if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { // hitting player + m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage after getting hit + const dmg = 0.05 * simulation.dmgScale; + m.damage(dmg); + simulation.drawList.push({ //add dmg to draw queue + x: best.x, + y: best.y, + radius: dmg * 1500, + color: "rgba(255,0,100,0.5)", + time: 20 + }); + this.lasers.splice(i, 1) //remove this laser node + if (this.distanceToPlayer < 1000) { //mob jumps away from player + const forceMag = 0.03 * this.mass; + const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x); + this.force.x -= 2 * forceMag * Math.cos(angle); + this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity + } + } else if (best.who && best.who.classType === "body") { //hitting block + ctx.beginPath(); + ctx.moveTo(best.x, best.y); + ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y); + ctx.strokeStyle = `rgb(255,0,100)`; + ctx.lineWidth = 2; + ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); + ctx.stroke(); + ctx.setLineDash([]); + } else { //hitting nothing + ctx.beginPath(); + ctx.moveTo(this.lasers[i].b.x, this.lasers[i].b.y); + ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y); + ctx.strokeStyle = `rgb(255,0,100)`; + ctx.lineWidth = 2; + ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); + ctx.stroke(); + ctx.setLineDash([]); + } + } else {//fade in warning + this.lasers[i].fade += 0.01 + ctx.beginPath(); + ctx.moveTo(this.lasers[i].a.x, this.lasers[i].a.y); + ctx.lineTo(this.lasers[i].b.x, this.lasers[i].b.y); + ctx.lineWidth = 5 + 5 * this.lasers[i].fade; + ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.lasers[i].fade})`; + ctx.stroke(); + } + } + } + me.driftCenter = { ...me.position }; //copy position with out reference so it doesn't change as mob moves + const r = Math.random() * 100; + const a = Math.random() * 2 * Math.PI; + me.driftGoal = Vector.add(me.driftCenter, { x: r * Math.cos(a), y: r * Math.sin(a) }) //updated in addLaser() + me.drift = function () { + //accelerate towards the player + if (this.seePlayer.recall) { + const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass) + this.force.x += force.x; + this.force.y += force.y; + } else { //drift + const force = Vector.mult(Vector.normalise(Vector.sub(this.driftGoal, this.position)), 0.00002 * this.mass) + // const force = Vector.mult(this.driftGoal, 0.0001 * this.mass) + this.force.x += force.x; + this.force.y += force.y; + } + }, + me.do = function () { + this.cycle++ + this.torque = this.lookTorque * this.inertia * 0.6; + this.seePlayerCheck(); + this.checkStatus(); + this.drift(); + //add new laser to lasers array + this.addLaser() + this.fireLaser() + // if (this.seePlayer.recall) { + // //set direction to turn to fire + // if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); + // } + }; + }, laser(x, y, radius = 30) { const color = "#f00" mobs.spawn(x, y, 3, radius, color); @@ -4866,46 +4276,6 @@ const spawn = { if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); if (simulation.cycle % this.laserInterval > this.laserInterval / 2) { - 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) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; const seeRange = 8000; best = { x: null, @@ -4915,13 +4285,8 @@ const spawn = { v1: null, v2: null }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - vertexCollision(this.position, look, body); - if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]); + const look = { x: this.position.x + seeRange * Math.cos(this.angle), y: this.position.y + seeRange * Math.sin(this.angle) }; + best = vertexCollision(this.position, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); // hitting player if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { @@ -4963,10 +4328,7 @@ const spawn = { setTimeout(() => { //fix mob in place, but allow rotation me.constraint = Constraint.create({ - pointA: { - x: me.position.x, - y: me.position.y - }, + pointA: { x: me.position.x, y: me.position.y }, bodyB: me, stiffness: 1, damping: 1 @@ -4988,7 +4350,6 @@ const spawn = { me.do = function () { this.fill = '#' + Math.random().toString(16).substr(-6); //flash colors this.checkStatus(); - if (!this.isStunned) { //check if slowed let slowed = false @@ -5003,7 +4364,6 @@ const spawn = { Matter.Body.setAngle(this, this.count * this.rotateVelocity) Matter.Body.setAngularVelocity(this, 0) } - ctx.beginPath(); this.lasers(this.vertices[0], this.angle + Math.PI / 3); this.lasers(this.vertices[1], this.angle + Math.PI); @@ -5017,53 +4377,8 @@ const spawn = { ctx.strokeStyle = "rgba(80,0,255,0.07)"; ctx.stroke(); // Draw it } - - - // Matter.Body.setVelocity(this, { - // x: 0, - // y: 0 - // }); - // Matter.Body.setPosition(this, this.startingPosition); - }; me.lasers = function (where, 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) best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - }; - const seeRange = 7000; best = { x: null, @@ -5073,14 +4388,9 @@ const spawn = { v1: null, v2: null }; - const look = { - x: where.x + seeRange * Math.cos(angle), - y: where.y + seeRange * Math.sin(angle) - }; - // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - vertexCollision(where, look, body); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + const look = { x: where.x + seeRange * Math.cos(angle), y: where.y + seeRange * Math.sin(angle) }; + best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second const dmg = 0.14 * simulation.dmgScale; @@ -5115,9 +4425,6 @@ const spawn = { me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.player //can't touch other mobs Matter.Body.rotate(me, Math.PI * 0.1); spawn.shield(me, x, y); - // me.onDamage = function () {}; - // me.onHit = function() { //run this function on hitting player - // }; me.onDeath = function () { if (this.spikeLength > 4) { this.spikeLength = 4 @@ -5157,11 +4464,6 @@ const spawn = { } else { if (this.isSpikeGrowing) { this.spikeLength += Math.pow(this.spikeGrowth += 0.02, 8) - // if (this.spikeLength < 2) { - // this.spikeLength += 0.035 - // } else { - // this.spikeLength += 1 - // } if (this.spikeLength > spikeMax) { this.isSpikeGrowing = false; this.spikeGrowth = 0 @@ -5182,7 +4484,6 @@ const spawn = { } }; }, - striker(x, y, radius = 14 + Math.ceil(Math.random() * 25)) { mobs.spawn(x, y, 5, radius, "rgb(221,102,119)"); let me = mob[mob.length - 1]; @@ -5306,33 +4607,9 @@ const spawn = { } }; me.laserSword = function (where, angle, length) { - 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) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[0], v2: vertices[len] }; - } - } - }; best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) }; - // vertexCollision(where, look, body); // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + best = vertexCollision(where, look, m.isCloak ? [map] : [map, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -5934,33 +5211,11 @@ const spawn = { ctx.stroke(); } me.laserSword = function (where, angle) { - const vertexCollision = function (v1, v1End, domain) { - for (let i = 0; i < domain.length; ++i) { - let v = domain[i].vertices; - const len = v.length - 1; - for (let j = 0; j < len; j++) { - results = simulation.checkLineIntersection(v1, v1End, v[j], v[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: v[j], v2: v[j + 1] }; - } - } - results = simulation.checkLineIntersection(v1, v1End, v[0], v[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) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] }; - } - } - }; + best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - vertexCollision(where, look, body); // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -6056,33 +5311,9 @@ const spawn = { } } me.laserSword = function (where, angle) { - const vertexCollision = function (v1, v1End, domain) { - for (let i = 0; i < domain.length; ++i) { - let v = domain[i].vertices; - const len = v.length - 1; - for (let j = 0; j < len; j++) { - results = simulation.checkLineIntersection(v1, v1End, v[j], v[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: v[j], v2: v[j + 1] }; - } - } - results = simulation.checkLineIntersection(v1, v1End, v[0], v[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) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] }; - } - } - }; best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - vertexCollision(where, look, body); // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -6172,33 +5403,9 @@ const spawn = { } } me.laserSword = function (where, angle) { - const vertexCollision = function (v1, v1End, domain) { - for (let i = 0; i < domain.length; ++i) { - let v = domain[i].vertices; - const len = v.length - 1; - for (let j = 0; j < len; j++) { - results = simulation.checkLineIntersection(v1, v1End, v[j], v[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: v[j], v2: v[j + 1] }; - } - } - results = simulation.checkLineIntersection(v1, v1End, v[0], v[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) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] }; - } - } - }; best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - vertexCollision(where, look, body); // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second m.damage(this.swordDamage); @@ -6306,33 +5513,10 @@ const spawn = { } } me.laserSpear = function (where, angle) { - const vertexCollision = function (v1, v1End, domain) { - for (let i = 0; i < domain.length; ++i) { - let v = domain[i].vertices; - const len = v.length - 1; - for (let j = 0; j < len; j++) { - results = simulation.checkLineIntersection(v1, v1End, v[j], v[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: v[j], v2: v[j + 1] }; - } - } - results = simulation.checkLineIntersection(v1, v1End, v[0], v[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) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] }; - } - } - }; best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; - vertexCollision(where, look, body); // vertexCollision(where, look, mob); - vertexCollision(where, look, map); - if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]); + if (best.who && (best.who === playerBody || best.who === playerHead)) { this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player @@ -6543,10 +5727,10 @@ const spawn = { mobs.spawn(x, y, 7, radius, "transparent"); let me = mob[mob.length - 1]; me.seeAtDistance2 = 300000; - me.accelMag = 0.00004 + 0.00015 * simulation.accelScale; + me.accelMag = 0.00007 + 0.0001 * simulation.accelScale; if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search - // Matter.Body.setDensity(me, 0.0015); //normal is 0.001 - me.damageReduction = 0.5 + Matter.Body.setDensity(me, 0.0002); //normal is 0.001 + me.damageReduction = 0.1 me.stroke = "transparent"; //used for drawGhost me.alpha = 1; //used in drawGhost me.isNotCloaked = false; //used in drawGhost @@ -6555,14 +5739,35 @@ const spawn = { me.collisionFilter.mask = cat.bullet //| cat.body me.showHealthBar = false; me.memory = 600; - me.do = function () { - //cap max speed to avoid getting launched by deflection, explosion - if (this.speed > 7) { - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.8, - y: this.velocity.y * 0.8 - }); + me.delay = 60 + me.cd = 0; + me.onHit = function () { + if (this.cd < simulation.cycle) { + this.cd = simulation.cycle + this.delay; + //dislodge ammo + if (b.inventory.length) { + let isRemovedAmmo = false + const numRemoved = 3 + for (let j = 0; j < numRemoved; j++) { + for (let i = 0; i < b.inventory.length; i++) { + const gun = b.guns[b.inventory[i]] + if (gun.ammo > 0 && gun.ammo !== Infinity) { + gun.ammo -= Math.ceil((0.6 * Math.random() + 0.6 * Math.random()) * gun.ammoPack) //Math.ceil(Math.random() * target.ammoPack) + if (gun.ammo < 0) gun.ammo = 0 + isRemovedAmmo = true + } + } + } + if (isRemovedAmmo) { + simulation.updateGunHUD(); + for (let j = 0; j < numRemoved; j++) powerUps.directSpawn(this.position.x + 10 * Math.random(), this.position.y + 10 * Math.random(), "ammo"); + powerUps.ejectGraphic(); + } + } } + }; + me.do = function () { + if (this.speed > 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 0.8, y: this.velocity.y * 0.8 }); //cap max speed to avoid getting launched by deflection, explosion this.seePlayerCheckByDistance(); this.checkStatus(); this.attraction(); @@ -6586,9 +5791,7 @@ const spawn = { ctx.beginPath(); const vertices = this.vertices; ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } + for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); ctx.lineTo(vertices[0].x, vertices[0].y); // ctx.lineWidth = 1; ctx.fillStyle = `rgba(255,255,255,${this.alpha * this.alpha})`; diff --git a/js/tech.js b/js/tech.js index 7900dfa..a62ab72 100644 --- a/js/tech.js +++ b/js/tech.js @@ -218,7 +218,7 @@ const tech = { } }, hasExplosiveDamageCheck() { - return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isHookExplosion + return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) }, damage: 1, //used for tech changes to player damage that don't have complex conditions damageFromTech() { @@ -1215,6 +1215,38 @@ const tech = { b.setFireCD(); } }, + { + name: "dynamical systems", + description: `use ${powerUps.orb.research(2)}
+30% damage`, + // isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return powerUps.research.count > 1 || build.isExperimentSelection + }, + requires: "", + // allowed() { + // return (m.fieldMode === 5 || m.fieldMode === 7 || m.fieldMode === 8) && (build.isExperimentSelection || powerUps.research.count > 1) + // }, + // requires: "cloaking, pilot wave, or plasma torch", + damage: 1.3, + effect() { + tech.damage *= this.damage + tech.isCloakingDamage = true + for (let i = 0; i < 2; i++) { + if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) + } + }, + remove() { + tech.isCloakingDamage = false + if (this.count > 0) { + tech.damage /= this.damage + powerUps.research.changeRerolls(2) + } + } + }, { name: "heuristics", description: "+22% fire rate
spawn a gun", @@ -1412,24 +1444,24 @@ const tech = { tech.healSpawn = 0; } }, - { - name: "yield stress", - description: "+55% damage
to mobs at maximum health", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return m.fieldMode !== 7 && tech.mobSpawnWithHealth === 0 - }, - requires: "not cloaking, reaction inhibitor", - effect() { - tech.isMobFullHealth = true - }, - remove() { - tech.isMobFullHealth = false - } - }, + // { + // name: "yield stress", + // description: "+55% damage
to mobs at maximum health", + // maxCount: 1, + // count: 0, + // frequency: 1, + // frequencyDefault: 1, + // allowed() { + // return m.fieldMode !== 7 && tech.mobSpawnWithHealth === 0 + // }, + // requires: "not cloaking, reaction inhibitor", + // effect() { + // tech.isMobFullHealth = true + // }, + // remove() { + // tech.isMobFullHealth = false + // } + // }, { name: "cascading failure", description: "+222% damage
to mobs below 25% health", @@ -1456,7 +1488,7 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return !tech.isMobFullHealth + return !tech.isMobFullHealthCloak }, requires: "not topological defect", effect() { @@ -2676,6 +2708,34 @@ const tech = { tech.isHarmArmor = false; } }, + { + name: "tessellation", + description: `use ${powerUps.orb.research(2)}
+35% defense`, + // description: "use 4 research
reduce defense by 50%", + // isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return powerUps.research.count > 1 || build.isExperimentSelection + }, + requires: "", + // allowed() { + // return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 3) + // }, + // requires: "perfect diamagnetism, negative mass, grappling hook, pilot wave", + effect() { + tech.isFieldHarmReduction = true + for (let i = 0; i < 2; i++) { + if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) + } + }, + remove() { + tech.isFieldHarmReduction = false + if (this.count > 0) powerUps.research.changeRerolls(2) + } + }, { name: "Pauli exclusion", description: `after mob collisions
become invulnerable for +3.5 seconds`, @@ -2796,14 +2856,14 @@ const tech = { }, { name: "heat engine", - description: `+50% damage
–50 maximum energy`, + description: `+40% damage
–50 maximum energy`, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, allowed: () => true, requires: "not CPT", - damage: 1.5, + damage: 1.4, effect() { tech.damage *= this.damage tech.isMaxEnergyTech = true; @@ -4184,7 +4244,7 @@ const tech = { { name: "commodities exchange", descriptionFunction() { - return `clicking cancel for a field, tech, or gun
spawns 6-12 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}` + return `clicking cancel for a field, tech, or gun
spawns 10-14 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}` }, maxCount: 1, count: 0, @@ -4912,7 +4972,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 + return tech.hookNails + tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 }, requires: "nails, nail gun, rivets, shotgun, super balls, mine", effect() { @@ -4951,7 +5011,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || ((tech.isMineDrop || tech.haveGunCheck("mine")) && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot)) + return tech.isNailBotUpgrade || tech.hookNails || tech.fragments || tech.nailsDeathMob || ((tech.isMineDrop || tech.haveGunCheck("mine")) && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot)) }, requires: "nail gun, nails, rivets, mine, not ceramic needles", effect() { @@ -5842,7 +5902,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || tech.isHookExplosion || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) + return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) }, requires: "an explosive damage source, not rocket propelled grenade", effect() { @@ -6123,7 +6183,7 @@ const tech = { frequencyDefault: 2, allowed() { // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines")) - return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles) + return tech.isMineDrop || tech.isNailBotUpgrade || tech.hookNails || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles) }, // requires: "nail gun, not rotary cannon, rivets, or needles", @@ -7074,7 +7134,7 @@ const tech = { // }, { name: "alternator", - description: "+90% harpoon energy efficiency", + description: "harpoon no longer uses any energy", isGunTech: true, maxCount: 1, count: 0, @@ -7113,7 +7173,7 @@ const tech = { { name: "Bessemer process", descriptionFunction() { - return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}% harpoon size and damage
(1/10 √ harpoon ammo)` + return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}% harpoon size and damage
(effect scales by 1/10 √ harpoon ammo)` }, isGunTech: true, maxCount: 1, @@ -7179,7 +7239,7 @@ const tech = { { name: "UHMWPE", descriptionFunction() { - return `+${(b.guns[9].ammo * 1.25).toFixed(0)}% harpoon rope length
(1/80 of harpoon ammo)` + return `+${(b.guns[9].ammo * 1.25).toFixed(0)}% harpoon rope length
(effect scales by 1/80 of harpoon ammo)` }, isGunTech: true, maxCount: 1, @@ -7219,7 +7279,7 @@ const tech = { }, { name: "brittle", - description: "+88% harpoon/grapple damage
to mobs at maximum health", + description: "+111% harpoon/grapple damage
to mobs at maximum health", isGunTech: true, maxCount: 1, count: 0, @@ -7673,7 +7733,7 @@ const tech = { }, { name: "zero point energy", - description: `use ${powerUps.orb.research(2)}
+100 maximum energy`, + description: `use ${powerUps.orb.research(2)}
+166 maximum energy`, isFieldTech: true, maxCount: 1, count: 0, @@ -7684,7 +7744,7 @@ const tech = { }, requires: "standing wave, pilot wave, time dilation", effect() { - tech.harmonicEnergy = 1 + tech.harmonicEnergy = 1.66 m.setMaxEnergy() for (let i = 0; i < 2; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) @@ -7698,7 +7758,7 @@ const tech = { }, { name: "expansion", - description: "using standing wave field expands its radius
+40 maximum energy", + description: "using standing wave field expands its radius
+77 maximum energy", isFieldTech: true, maxCount: 1, count: 0, @@ -7860,30 +7920,6 @@ const tech = { tech.isBigField = false; } }, - { - name: "tessellation", - description: `use ${powerUps.orb.research(2)}
+50% defense`, - // description: "use 4 research
reduce defense by 50%", - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 3, - frequencyDefault: 3, - allowed() { - return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 3) - }, - requires: "perfect diamagnetism, negative mass, grappling hook, pilot wave", - effect() { - tech.isFieldHarmReduction = true - for (let i = 0; i < 2; i++) { - if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) - } - }, - remove() { - tech.isFieldHarmReduction = false - if (this.count > 0) powerUps.research.changeRerolls(2) - } - }, { name: "radiative equilibrium", descriptionFunction() { @@ -7978,7 +8014,7 @@ const tech = { }, { name: "annihilation", - description: "after colliding with non-boss mobs
they are annihilated and –33% energy", + description: "after colliding with non-boss mobs
they are annihilated and –10 energy", isFieldTech: true, maxCount: 1, count: 0, @@ -8291,9 +8327,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return m.fieldMode === 5 || m.fieldMode === 6 || m.fieldMode === 7 || m.fieldMode === 8 || m.fieldMode === 4 + return m.fieldMode === 6 || m.fieldMode === 7 || m.fieldMode === 8 }, - requires: "cloaking, molecular assembler, plasma torch, pilot wave", + requires: "time dilation, cloaking, pilot wave", damage: 1.35, effect() { tech.damage *= this.damage @@ -8315,9 +8351,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) && !tech.isPrinter && !tech.isReel && !tech.isHookExplosion + return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) && !tech.isPrinter && !tech.isReel && !tech.hookNails }, - requires: "plasma torch, molecular assembler, grappling hook, not printer, reel, rupture", + requires: "plasma torch, molecular assembler, grappling hook, not printer, reel, swarf", effect() { tech.isTokamak = true; }, @@ -8705,7 +8741,7 @@ const tech = { { name: "dazzler", link: `dazzler`, - description: "after decloaking stun nearby mobs
and drain –10 energy", + description: "after decloaking
stun nearby mobs for 2 second", isFieldTech: true, maxCount: 1, count: 0, @@ -8724,16 +8760,16 @@ const tech = { }, { name: "topological defect", - description: "+88% damage
to mobs at maximum health", + description: "+111% damage
to mobs at maximum health", isFieldTech: true, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return (m.fieldMode === 8 || m.fieldMode === 7) && tech.mobSpawnWithHealth === 0 && !tech.isMobFullHealth + return (m.fieldMode === 8 || m.fieldMode === 7) && tech.mobSpawnWithHealth === 0 }, - requires: "cloaking, pilot wave, not reaction inhibitor, yield stress", + requires: "cloaking, pilot wave, not reaction inhibitor", effect() { tech.isMobFullHealthCloak = true }, @@ -8760,34 +8796,6 @@ const tech = { // tech.sneakAttackDmg = 4.33 //333% + 100% // } // }, - { - name: "dynamical systems", - description: `use ${powerUps.orb.research(2)}
+35% damage`, - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 3, - frequencyDefault: 3, - allowed() { - return (m.fieldMode === 5 || m.fieldMode === 7 || m.fieldMode === 8) && (build.isExperimentSelection || powerUps.research.count > 1) - }, - requires: "cloaking, pilot wave, or plasma torch", - damage: 1.35, - effect() { - tech.damage *= this.damage - tech.isCloakingDamage = true - for (let i = 0; i < 2; i++) { - if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) - } - }, - remove() { - tech.isCloakingDamage = false - if (this.count > 0) { - tech.damage /= this.damage - powerUps.research.changeRerolls(2) - } - } - }, { name: "WIMPs", description: `at the end of each level spawn ${powerUps.orb.research(4)}
and a dangerous particle that slowly chases you`, @@ -8818,9 +8826,9 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 2) + return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2) }, - requires: "wormhole, time dilation, negative mass, pilot wave, grappling hook", + requires: "wormhole, time dilation, negative mass, pilot wave", effect() { tech.fieldDuplicate = 0.11 powerUps.setPowerUpMode(); //needed after adjusting duplication chance @@ -8988,7 +8996,7 @@ const tech = { }, { name: "CIWS", - description: "grappling hook uses 18 energy
to fire harpoons at nearby mobs", + description: "grappling hook uses 10 energy
to fire harpoons at nearby mobs", isFieldTech: true, maxCount: 1, count: 0, @@ -9006,10 +9014,11 @@ const tech = { } }, { - name: "rupture", - description: "after grappling hook impacts solid objects
generate an explosion", + name: "swarf", + // description: "after grappling hook impacts solid objects generate an explosion and become briefly invulnerable", + description: "after grappling hook impacts something
eject nails splinters towards nearby mobs", isFieldTech: true, - maxCount: 1, + maxCount: 3, count: 0, frequency: 2, frequencyDefault: 2, @@ -9018,24 +9027,24 @@ const tech = { }, requires: "grappling hook, not reel, tokamak", effect() { - tech.isHookExplosion = true + tech.hookNails += 4 }, remove() { - tech.isHookExplosion = false + tech.hookNails = 0 } }, { name: "reel", - description: "+400% block collision damage
+30 energy when reeling in far away blocks", + description: "+400% block collision damage
up to +75 energy after reeling in blocks", isFieldTech: true, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return m.fieldMode === 10 && !tech.isTokamak && tech.blockDamage === 0.075 && !tech.isHookExplosion + return m.fieldMode === 10 && !tech.isTokamak && tech.blockDamage === 0.075 && !tech.hookNails }, - requires: "grappling hook, not mass driver, rupture, tokamak", + requires: "grappling hook, not mass driver, swarf, tokamak", effect() { tech.blockDamage = 0.375 tech.isReel = true @@ -11910,7 +11919,7 @@ const tech = { isFastFoam: null, isSporeGrowth: null, isStimulatedEmission: null, - nailGun: null, + // nailGun: null, nailInstantFireRate: null, isCapacitor: null, isEnergyNoAmmo: null, @@ -12148,12 +12157,11 @@ const tech = { isPrinter: null, // isHookWire: null, isHookDefense: null, - isHookExplosion: null, + hookNails: null, isHarpoonDefense: null, isReel: null, harpoonPowerUpCycle: null, isHarpoonFullHealth: null, - isMobFullHealth: null, isMobFullHealthCloak: null, isMobLowHealth: null, isDamageCooldown: null, diff --git a/todo.txt b/todo.txt index 3bf436e..30494eb 100644 --- a/todo.txt +++ b/todo.txt @@ -1,16 +1,71 @@ ******************************************************** NEXT PATCH ************************************************** -tech: hyperpolarization - reduce the CD on depolarization by 1 second +mob: laserLayer - leaves behind lasers that persist for a few seconds +ghoster mobs do 66% less damage, but they eject your ammo -metamaterial absorber 22->25% chance to get power up for mobs not killed -symbiosis -0.5 -> 0.25 max health after killing a mob -dazzler -15->10 energy after decloaking and stunning mobs -Hilbert space 142->300% damage +grappling hook tech rupture renamed swarf + fires several nails at nearby mobs, not explosions +grappling hook 6->9 energy per second +CIWS 18->10 energy +reel +40->75 energy reeling blocks +wormhole 5->7% duplication +cloaking no longer drains energy, this fixes a can't cloak bug + dazzler no longer drains energy + dazzler range reduced by 15% + dazzler stuns for 3->2 seconds +zero point energy 100->166 max energy +expansion 40->77 max energy +annihilation -33% of max energy -> 10 energy +dynamical systems is no longer a field tech 35->30 damage +tessellation is no longer a field tech 50->35 defense +yield stress removed + topological defect 80->111% damage + brittle 80->111% damage +commodities exchange 6-12 -> 10-14 power ups +heat engine 50->40% damage +flame test grenades clusters explode 40% faster +alternator uses 10->0% energy for harpoon + +finally made a shared vertexCollision function + this might cause some bugs with laser-like effects... -fixed bug with 1000x more frequent enthalpy *********************************************************** TODO ***************************************************** +increase damage for each not picked up power up on the level + +make a laserLayerBoss + add lasers on player's history + +button/switch input ideas from Cocoon game + pick up blocks that have a rubber band attached to a sliding switch + as player moves the vector direction of the rubber band will move the slider left or right + use this to open doors, move larger blocks, ... + switches that toggle left, right when player presses input.field while standing nearby + replace laser off on switch? + platform that rises up when player presses input.field while standing + How to instruct player to use field on these? + color with field #0ff + draw field effect + make it still functional without the field button + +tech: - getting a new gun also gives you 2 random tech for that gun + or a field? + can these guntech tech be converted into a player choice? + +tech: interest - research and ammo increases by 10% at the start of each level? + spawn research and ammo at start of new level + extend to current health? + +how to reduce the number of clicks and keypresses + auto fire mode + player shoots at whatever is nearby + should player have to look towards mobs? + increase ammo? + +animate egg laying mobs + just draw a circle when it happens? + improve new player experience training is too long to be a tutorial before nail gun level offer player option to continue or switch to normal game @@ -51,7 +106,7 @@ make grappling hook of different shapes longer circular with spikes indicate tech upgrades? - rupture, reel, tokamak + swarf, reel, tokamak do this in draw or in verticies? draw can have different colors @@ -1097,6 +1152,7 @@ possible names for tech Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity Unruh effect - accelerating makes heat/thermal particles configuration space - holds the position of everything + stress–energy tensor ******************************************************** CARS IMAGES ********************************************************