diff --git a/index.html b/index.html index 8086413..099c076 100644 --- a/index.html +++ b/index.html @@ -77,25 +77,6 @@
- - -

@@ -179,16 +160,70 @@
about -
- n-gon is a solo project written in JavaScript, CSS, and HTML using the matter.js 2-D physics library. It's free and open source on Github. +
- + + + + + + + + + + + - + +

+ I wrote n-gon in JavaScript, CSS, and HTML using the matter.js 2-D physics library. + The code is free and open source on Github. + This is just my hobby project, but I try to fix bugs when reported. +

+ + + + +
+ +
@@ -230,8 +265,9 @@ - + + diff --git a/js/bullet.js b/js/bullet.js index 80c0d09..dcca903 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -280,8 +280,8 @@ const b = { fireProps(cd, speed, dir, me) { m.fireCDcycle = m.cycle + Math.floor(cd * b.fireCDscale); // cool down Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + speed * Math.cos(dir), - y: m.Vy / 2 + speed * Math.sin(dir) + x: 0.5 * player.velocity.x + speed * Math.cos(dir), + y: 0.5 * player.velocity.y + speed * Math.sin(dir) }); Composite.add(engine.world, bullet[me]); //add bullet to world }, @@ -734,8 +734,8 @@ const b = { }; speed = m.crouch ? 43 : 32 Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + speed * Math.cos(angle), - y: m.Vy / 2 + speed * Math.sin(angle) + x: 0.5 * player.velocity.x + speed * Math.cos(angle), + y: 0.5 * player.velocity.y + speed * Math.sin(angle) }); bullet[me].endCycle = simulation.cycle + Math.floor(m.crouch ? 120 : 80) * tech.bulletsLastLonger; bullet[me].restitution = 0.4; @@ -759,8 +759,8 @@ const b = { }; speed = m.crouch ? 46 : 32 Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + speed * Math.cos(angle), - y: m.Vy / 2 + speed * Math.sin(angle) + x: 0.8 * player.velocity.x + speed * Math.cos(angle), + y: 0.5 * player.velocity.y + speed * Math.sin(angle) }); Composite.add(engine.world, bullet[me]); //add bullet to world @@ -794,8 +794,8 @@ const b = { }; speed = m.crouch ? 46 : 32 Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + speed * Math.cos(angle), - y: m.Vy / 2 + speed * Math.sin(angle) + x: 0.8 * player.velocity.x + speed * Math.cos(angle), + y: 0.5 * player.velocity.y + speed * Math.sin(angle) }); Composite.add(engine.world, bullet[me]); //add bullet to world bullet[me].endCycle = simulation.cycle + 70 * tech.bulletsLastLonger; @@ -924,8 +924,8 @@ const b = { bullet[me].endCycle += 20; } Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + speed * Math.cos(angle), - y: m.Vy / 2 + speed * Math.sin(angle) + x: 0.5 * player.velocity.x + speed * Math.cos(angle), + y: 0.5 * player.velocity.y + speed * Math.sin(angle) }); Composite.add(engine.world, bullet[me]); //add bullet to world } @@ -951,7 +951,7 @@ const b = { Matter.Body.scale(bullet[me], SCALE, SCALE); speed = m.crouch ? 25 : 15 // speed = m.crouch ? 43 : 32 - Matter.Body.setVelocity(bullet[me], { x: m.Vx / 2 + speed * Math.cos(angle), y: m.Vy / 2 + speed * Math.sin(angle) }); + Matter.Body.setVelocity(bullet[me], { x: 0.5 * player.velocity.x + speed * Math.cos(angle), y: 0.5 * player.velocity.y + speed * Math.sin(angle) }); const MAG = 0.005 bullet[me].thrust = { x: bullet[me].mass * MAG * Math.cos(angle), y: bullet[me].mass * MAG * Math.sin(angle) } } @@ -1140,148 +1140,6 @@ const b = { } } }, - // dart(where, angle = m.angle, size = 0.8) { - // //find a target - // const closest = { - // score: 10000, - // position: null - // } - // for (let i = 0, len = mob.length; i < len; ++i) { - // if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, where, mob[i].position).length === 0) { - // const dot = Vector.dot({ x: Math.cos(angle), y: Math.sin(angle) }, Vector.normalise(Vector.sub(mob[i].position, where))) //the dot product of diff and dir will return how much over lap between the vectors - // const dist = Vector.magnitude(Vector.sub(where, mob[i].position)) - // // if (dist < closest.score && ((dist > 500 && dot > 0) || (dot > 0.9))) { //target closest mob that player is looking at and isn't too close to target - // if (dist < closest.score && dot > 0.9 - 0.0004 * dist) { //target closest mob that player is looking at and isn't too close to target - // closest.score = dist - // closest.position = mob[i].position - // } - // } - // } - // if (!closest.position) { - // // const unit = Vector.mult(sub(simulation.mouseInGame, where), 10000) - // closest.position = Vector.mult(Vector.sub(simulation.mouseInGame, where), 10000) - // } - // const me = bullet.length; - // bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -20 * size, y: 2 * size, index: 0, isInternal: false }, { x: -20 * size, y: -2 * size, index: 1, isInternal: false }, { x: 5 * size, y: -2 * size, index: 4, isInternal: false }, { x: 20 * size, y: 0, index: 3, isInternal: false }, { x: 5 * size, y: 2 * size, index: 4, isInternal: false }], { - // cycle: 0, - // angle: angle, - // friction: 1, - // frictionAir: 0.15, - // thrustMag: 0.03, - // turnRate: 0.15, //0.015 - // drawStringControlMagnitude: 3000 + 5000 * Math.random(), - // drawStringFlip: (Math.round(Math.random()) ? 1 : -1), - // dmg: 7, //damage done in addition to the damage from momentum - // classType: "bullet", - // endCycle: simulation.cycle + 120, - // collisionFilter: { - // category: cat.bullet, - // mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield, - // }, - // minDmgSpeed: 0, - // lookFrequency: Math.floor(7 + Math.random() * 3), - // density: 0.001, //0.001 is normal for blocks, 0.008 is normal for harpoon, 0.008*6 when buffed - // beforeDmg(who) { - // if (tech.isShieldPierce && who.isShielded) { //disable shields - // who.isShielded = false - // requestAnimationFrame(() => { who.isShielded = true }); - // } - // if (tech.fragments) { - // b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + 1.5 * Math.random())) - // this.endCycle = 0; - // } - // if (!who.isBadTarget) { - // this.frictionAir = 0.01 - // this.do = this.doNoTargeting - // } - // }, - // onEnd() {}, - // doNoTargeting: function() { - // // this.force.y += this.mass * 0.001; - // if (Matter.Query.collides(this, map).length) { //stick in walls - // this.collisionFilter.mask = 0; - // Matter.Body.setAngularVelocity(this, 0) - // Matter.Body.setVelocity(this, { - // x: 0, - // y: 0 - // }); - // this.do = () => { - // // if (!Matter.Query.collides(this, map).length) this.force.y += this.mass * 0.001; - // } - // } - // }, - // do() { - // this.cycle++ - // // if (this.cycle > 40) { - // // this.frictionAir = 0.003 - // // this.do = this.doNoTargeting - // // } - // // if (closest.target) { //rotate towards the target - // const face = { x: Math.cos(this.angle), y: Math.sin(this.angle) }; - // const vectorGoal = Vector.normalise(Vector.sub(this.position, closest.position)); - // const cross = Vector.cross(vectorGoal, face) - // if (cross > 0.01) { - // Matter.Body.rotate(this, this.turnRate * Math.sqrt(cross)); - // } else if (cross < 0.01) { - // Matter.Body.rotate(this, -this.turnRate * Math.sqrt(Math.abs(cross))); - // } - // this.force.x += this.thrustMag * this.mass * Math.cos(this.angle); - // this.force.y += this.thrustMag * this.mass * Math.sin(this.angle); - // // } - // if (Matter.Query.collides(this, map).length) { //stick in walls - // this.collisionFilter.mask = 0; - // Matter.Body.setAngularVelocity(this, 0) - // Matter.Body.setVelocity(this, { - // x: 0, - // y: 0 - // }); - // this.do = this.doNoTargeting - // } - // // else if (!(this.cycle % 2)) { //look for a target if you don't have one - // // simulation.drawList.push({ //add dmg to draw queue - // // x: this.position.x, - // // y: this.position.y, - // // radius: 10, - // // color: simulation.mobDmgColor, - // // time: simulation.drawTime - // // }); - // // let closest = { - // // distance: 2000, - // // target: null - // // } - // // const dir = Vector.normalise(this.velocity) //make a vector for direction of length 1 - // // for (let i = 0, len = mob.length; i < len; ++i) { - // // if ( - // // mob[i].alive && !mob[i].isBadTarget && - // // Matter.Query.ray(map, this.position, mob[i].position).length === 0 && //check for map in Line of sight - // // Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, this.position))) > 0.55 //the dot product of diff and dir will return how much over lap between the vectors - // // ) { - // // const dist = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - // // if (dist < closest.distance) { - // // closest.distance = dist - // // closest.target = mob[i] - // // } - // // } - // // } - // // if (closest.target) { - // // target = closest.target - // // this.turnRate = 0.05 - // // this.frictionAir = 0.8 - // // } - // // } - // }, - // }); - // Matter.Body.setVelocity(bullet[me], { - // x: m.Vx / 2 + 40 * Math.cos(bullet[me].angle), - // y: m.Vy / 2 + 40 * Math.sin(bullet[me].angle) - // }); - // // if (!closest.target) { - // // bullet[me].frictionAir = 0.002 - // // bullet[me].do = bullet[me].doNoTargeting - // // } - // Composite.add(engine.world, bullet[me]); //add bullet to world - - // }, grapple(where, angle = m.angle) { const me = bullet.length; const returnRadius = 100 @@ -1962,8 +1820,8 @@ const b = { }); if (!isReturn && !target) { Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + 600 * thrust * Math.cos(bullet[me].angle), - y: m.Vy / 2 + 600 * thrust * Math.sin(bullet[me].angle) + x: 0.7 * player.velocity.x + 600 * thrust * Math.cos(bullet[me].angle), + y: 0.5 * player.velocity.x + 600 * thrust * Math.sin(bullet[me].angle) }); bullet[me].frictionAir = 0.002 bullet[me].do = function () { @@ -2084,8 +1942,8 @@ const b = { }); const thrust = 0.0066 * bullet[me].mass * (tech.isMissileBig ? (tech.isMissileBiggest ? 0.3 : 0.7) : 1); Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + speed * Math.cos(angle), - y: m.Vy / 2 + speed * Math.sin(angle) + x: 0.5 * player.velocity.x + speed * Math.cos(angle), + y: 0.5 * player.velocity.y + speed * Math.sin(angle) }); Composite.add(engine.world, bullet[me]); //add bullet to world }, @@ -2972,11 +2830,6 @@ const b = { y: speed * Math.sin(dir) }); Matter.Body.setAngularVelocity(bullet[me], 3000 * bullet[me].spin); - - // Matter.Body.setVelocity(bullet[me], { - // x: m.Vx / 2 + speed * Math.cos(dir), - // y: m.Vy / 2 + speed * Math.sin(dir) - // }); }, flea(where, velocity, radius = 6 + 3 * Math.random() + 10 * tech.wormSize * Math.random()) { const me = bullet.length; @@ -3810,165 +3663,6 @@ const b = { } return shotsFired }, - // plasmaBall(position, velocity, radius) { - // // radius *= Math.sqrt(tech.bulletSize) - // const me = bullet.length; - // bullet[me] = Bodies.polygon(position.x, position.y, 20, radius, { - // density: 0.000001, // 0.001 is normal density - // inertia: Infinity, - // frictionAir: 0.003, - // dmg: 0, //damage on impact - // damage: 0, //damage done over time - // scale: 1 - 0.006 / tech.bulletsLastLonger, - // classType: "bullet", - // collisionFilter: { - // category: cat.bullet, - // mask: 0 //cat.mob | cat.mobBullet // cat.map | cat.body | cat.mob | cat.mobShield - // }, - // minDmgSpeed: 0, - // endCycle: Infinity, - // count: 0, - // radius: radius, - // portFrequency: 5 + Math.floor(5 * Math.random()), - // nextPortCycle: Infinity, //disabled unless you have the teleport tech - // beforeDmg(who) { - // if (!this.target && who.alive) { - // this.target = who; - // if (who.radius < 20) { - // this.targetRelativePosition = { - // x: 0, - // y: 0 - // } //find relative position vector for zero mob rotation - // } else if (Matter.Query.collides(this, [who]).length > 0) { - // const normal = Matter.Query.collides(this, [who])[0].normal - // this.targetRelativePosition = Vector.rotate(Vector.sub(Vector.sub(this.position, who.position), Vector.mult(normal, -this.radius)), -who.angle) //find relative position vector for zero mob rotation - // } else { - // this.targetRelativePosition = Vector.rotate(Vector.sub(this.position, who.position), -who.angle) //find relative position vector for zero mob rotation - // } - // this.collisionFilter.category = cat.body; - // this.collisionFilter.mask = null; - - // let bestVertexDistance = Infinity - // let bestVertex = null - // for (let i = 0; i < this.target.vertices.length; i++) { - // const dist = Vector.magnitude(Vector.sub(this.position, this.target.vertices[i])); - // if (dist < bestVertexDistance) { - // bestVertex = i - // bestVertexDistance = dist - // } - // } - // this.targetVertex = bestVertex - // } - // }, - // onEnd() {}, - // do() { - // if (this.count < 20) { - // this.count++ - // //grow - // const SCALE = 1.06 - // Matter.Body.scale(this, SCALE, SCALE); - // this.radius *= SCALE; - // } else { - // //shrink - // Matter.Body.scale(this, this.scale, this.scale); - // this.radius *= this.scale; - // if (this.radius < 8) this.endCycle = 0; - // } - // if (this.target && this.target.alive) { //if stuck to a target - // const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector - // if (this.target.isVerticesChange) { - // Matter.Body.setPosition(this, this.target.vertices[this.targetVertex]) - // } else { - // Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.target.velocity), this.target.position)) - // } - // if (this.target.isBoss) { - // if (this.target.speed > 8) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.98)) - // } else { - // if (this.target.speed > 4) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.95)) - // } - - // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9); - // // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9) - // if (this.target.isShielded) { - // this.target.damage(m.dmgScale * this.damage, true); //shield damage bypass - // const SCALE = 1 - 0.004 / tech.bulletsLastLonger //shrink if mob is shielded - // Matter.Body.scale(this, SCALE, SCALE); - // this.radius *= SCALE; - // } else { - // this.target.damage(m.dmgScale * this.damage); - // } - // } else if (this.target !== null) { //look for a new target - // this.collisionFilter.category = cat.bullet; - // this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield - // if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) { - // let targets = [] - // for (let i = 0, len = mob.length; i < len; i++) { - // const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)); - // if (dist < 1000000) targets.push(mob[i]) - // } - // const radius = Math.min(this.radius * 0.5, 9) - // const len = bullet.length < 80 ? 2 : 1 - // for (let i = 0; i < len; i++) { - // if (targets.length - i > 0) { - // const index = Math.floor(Math.random() * targets.length) - // const speed = 6 + 6 * Math.random() - // const velocity = Vector.mult(Vector.normalise(Vector.sub(targets[index].position, this.position)), speed) - // b.foam(this.position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius) - // } else { - // b.foam(this.position, Vector.rotate({ - // x: 15 + 10 * Math.random(), - // y: 0 - // }, 2 * Math.PI * Math.random()), radius) - // } - // } - // } - // this.target = null - // } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map or blocks - // const slow = 0.85 - // Matter.Body.setVelocity(this, { - // x: this.velocity.x * slow, - // y: this.velocity.y * slow - // }); - // const SCALE = 0.96 - // Matter.Body.scale(this, SCALE, SCALE); - // this.radius *= SCALE; - // // } else if (Matter.Query.collides(this, body).length > 0) { - // } else if (Matter.Query.point(body, this.position).length > 0) { - // const slow = 0.9 - // Matter.Body.setVelocity(this, { - // x: this.velocity.x * slow, - // y: this.velocity.y * slow - // }); - // const SCALE = 0.96 - // Matter.Body.scale(this, SCALE, SCALE); - // this.radius *= SCALE; - // } else { - // this.force.y += this.mass * tech.foamGravity; //gravity - // if (tech.isFoamAttract) { - // for (let i = 0, len = mob.length; i < len; i++) { - // if (!mob[i].isBadTarget && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { - // this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004) - // const slow = 0.9 - // Matter.Body.setVelocity(this, { - // x: this.velocity.x * slow, - // y: this.velocity.y * slow - // }); - // break - // } - // } - // } - // } - // if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isBulletTeleport - // this.nextPortCycle = simulation.cycle + this.portFrequency - // const range = 15 * Math.sqrt(this.radius) * Math.random() - // Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random()))) - // } - // } - // }); - // if (tech.isBulletTeleport) bullet[me].nextPortCycle = simulation.cycle + bullet[me].portFrequency - // Composite.add(engine.world, bullet[me]); //add bullet to world - // Matter.Body.setVelocity(bullet[me], velocity); - // }, foam(position, velocity, radius) { if (tech.isFoamCavitation && Math.random() < 0.25) { velocity = Vector.mult(velocity, 1.35) @@ -4024,10 +3718,7 @@ const b = { } } this.targetVertex = bestVertex - Matter.Body.setVelocity(this, { - x: 0, - y: 0 - }); + Matter.Body.setVelocity(this, { x: 0, y: 0 }); } }, onEnd() { }, @@ -4070,10 +3761,7 @@ const b = { } else if (this.target !== null) { //look for a new target this.collisionFilter.category = cat.bullet; this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield - Matter.Body.setVelocity(this, { - x: this.target.velocity.x, - y: this.target.velocity.y - }); + Matter.Body.setVelocity(this, { x: this.target.velocity.x, y: this.target.velocity.y }); if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) { let targets = [] for (let i = 0, len = mob.length; i < len; i++) { @@ -4099,20 +3787,14 @@ const b = { this.target = null } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map const slow = 0.87 - Matter.Body.setVelocity(this, { - x: this.velocity.x * slow, - y: this.velocity.y * slow - }); + Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow }); const SCALE = 0.97 Matter.Body.scale(this, SCALE, SCALE); this.radius *= SCALE; // } else if (Matter.Query.collides(this, body).length > 0) { } else if (Matter.Query.point(body, this.position).length > 0) { //slow when touching blocks const slow = 0.94 - Matter.Body.setVelocity(this, { - x: this.velocity.x * slow, - y: this.velocity.y * slow - }); + Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow }); const SCALE = 0.99 Matter.Body.scale(this, SCALE, SCALE); this.radius *= SCALE; @@ -4417,8 +4099,8 @@ const b = { } const SPEED = 90 Matter.Body.setVelocity(bullet[me], { - x: m.Vx / 2 + SPEED * Math.cos(angle), - y: m.Vy / 2 + SPEED * Math.sin(angle) + x: 0.5 * player.velocity.x + SPEED * Math.cos(angle), + y: 0.5 * player.velocity.y + SPEED * Math.sin(angle) }); // Matter.Body.setDensity(bullet[me], 0.00001); Composite.add(engine.world, bullet[me]); //add bullet to world @@ -5928,8 +5610,8 @@ const b = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, { - x: m.Vx / 2 + speed * Math.cos(angle), - y: m.Vy / 2 + speed * Math.sin(angle) + x: 0.8 * player.velocity.x + speed * Math.cos(angle), + y: 0.5 * player.velocity.y + speed * Math.sin(angle) }) //position, velocity, damage if (tech.isIceCrystals) { bullet[bullet.length - 1].beforeDmg = function (who) { @@ -6201,8 +5883,8 @@ const b = { const SPEED = 13 + 4 * Math.random(); const angle = m.angle + spread * (Math.random() - 0.5) b.foam(where, { - x: SPEED * Math.cos(angle), - y: SPEED * Math.sin(angle) + x: 0.6 * player.velocity.x + SPEED * Math.cos(angle), + y: 0.5 * player.velocity.y + SPEED * Math.sin(angle) }, 8 + 7 * Math.random()) } } else if (tech.isNeedles) { @@ -6333,8 +6015,8 @@ const b = { return `emit wave packets that propagate through solids
waves slow mobs
${this.ammoPack.toFixed(0)} wave packets per ${powerUps.orb.ammo()}` }, ammo: 0, - ammoPack: 52, - defaultAmmoPack: 52, + ammoPack: 60, + defaultAmmoPack: 60, have: false, wavePacketCycle: 0, delay: 40, @@ -6655,12 +6337,12 @@ const b = { } } } - let waveSpeedMap = 0.1 - let waveSpeedBody = 0.25 + let waveSpeedMap = 0.13 + let waveSpeedBody = 0.3 if (tech.isPhaseVelocity) { waveSpeedMap = 3.5 waveSpeedBody = 2 - bullet[me].dmg *= 1.4 + bullet[me].dmg *= 1.5 } if (tech.waveReflections) { bullet[me].reflectCycle = totalCycles / tech.waveReflections //tech.waveLengthRange @@ -7083,10 +6765,13 @@ const b = { const radius = 5 + 8 * Math.random() + (tech.isAmmoFoamSize && this.ammo < 300) * 12 const SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25) const dir = m.angle + 0.15 * (Math.random() - 0.5) - const velocity = { x: SPEED * Math.cos(dir), y: SPEED * Math.sin(dir) } + const velocity = { + x: 0.7 * player.velocity.x + SPEED * Math.cos(dir), + y: 0.5 * player.velocity.y + SPEED * Math.sin(dir) + } const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } b.foam(position, Vector.rotate(velocity, spread), radius) - this.applyKnock(velocity) + // this.applyKnock(velocity) m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale); }, doCharges() { @@ -7105,15 +6790,15 @@ const b = { const SPEED = (m.crouch ? 1.2 : 1) * 10 - radius * 0.4 + Math.min(5, Math.sqrt(this.charge)); const dir = m.angle + 0.15 * (Math.random() - 0.5) const velocity = { - x: SPEED * Math.cos(dir), - y: SPEED * Math.sin(dir) + x: 0.7 * player.velocity.x + SPEED * Math.cos(dir), + y: 0.5 * player.velocity.y + SPEED * Math.sin(dir) } const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } b.foam(position, Vector.rotate(velocity, spread), radius) - this.applyKnock(velocity) + // this.applyKnock(velocity) this.charge -= 0.75 m.fireCDcycle = m.cycle + 2; //disable firing and adding more charge until empty } else if (!input.fire) { @@ -7135,31 +6820,13 @@ const b = { const SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25) const dir = m.angle + 0.15 * (Math.random() - 0.5) const velocity = { - x: SPEED * Math.cos(dir), - y: SPEED * Math.sin(dir) + x: 0.7 * player.velocity.x + SPEED * Math.cos(dir), + y: 0.5 * player.velocity.y + SPEED * Math.sin(dir) } - const position = { - x: m.pos.x + 30 * Math.cos(m.angle), - y: m.pos.y + 30 * Math.sin(m.angle) - } - // if (tech.foamFutureFire) { - // simulation.drawList.push({ //add dmg to draw queue - // x: position.x, - // y: position.y, - // radius: 5, - // color: "rgba(0,50,50,0.3)", - // time: 15 * tech.foamFutureFire - // }); - // setTimeout(() => { - // if (!simulation.paused) { - // b.foam(position, Vector.rotate(velocity, spread), radius) - // bullet[bullet.length - 1].damage *= (1 + 0.7 * tech.foamFutureFire) - // } - // }, 210 * tech.foamFutureFire); - // } else { - // } + const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } + b.foam(position, Vector.rotate(velocity, spread), radius) - this.applyKnock(velocity) + // this.applyKnock(velocity) m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale); this.charge += 1 + tech.isCapacitor }, diff --git a/js/index.js b/js/index.js index 59f6379..ec4aaa9 100644 --- a/js/index.js +++ b/js/index.js @@ -643,7 +643,7 @@ ${simulation.difficultyMode > 4 ? `
{ document.getElementById("sort-input").focus(); }); + // requestAnimationFrame(() => { document.getElementById("sort-input").focus(); }); }, sortTech(find, isExperiment = false) { const sortKeyword = (a, b) => { @@ -730,6 +730,8 @@ ${simulation.difficultyMode > 4 ? `
${powerUps.orb.fieldTech()} - - + + @@ -1416,11 +1418,13 @@ window.addEventListener("keydown", function (event) { build.pauseGrid() } else if (simulation.paused) { - build.unPauseGrid() - simulation.paused = false; - // level.levelAnnounce(); - document.body.style.cursor = "none"; - requestAnimationFrame(cycle); + if (document.activeElement !== document.getElementById('sort-input')) { + build.unPauseGrid() + simulation.paused = false; + // level.levelAnnounce(); + document.body.style.cursor = "none"; + requestAnimationFrame(cycle); + } } else { //if (!tech.isNoDraftPause) simulation.paused = true; build.pauseGrid() @@ -1542,7 +1546,7 @@ window.addEventListener("keydown", function (event) { } break } - if (b.inventory.length > 1 && !simulation.testing && !tech.isGunCycle) { + if (b.inventory.length > 1 && !simulation.testing && !(tech.isGunChoice || tech.isGunCycle)) { switch (event.code) { case "Digit1": simulation.switchToGunInInventory(0); diff --git a/js/level.js b/js/level.js index 90a790f..1308368 100644 --- a/js/level.js +++ b/js/level.js @@ -10,7 +10,7 @@ const level = { levelsCleared: 0, isFlipped: false, uniqueLevels: ["initial", "reservoir", "factory", "interferometer", "reactor", "subway", "final"], //see level.populateLevels: (initial, ... , (reservoir, factory, or interferometer), reactor, ... , subway, final) added later - playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock", "towers", "flocculation", "gravitron", "substructure"], + playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock", "towers", "flocculation", "gravitron", "substructure", "corridor"], communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo", "arena", "soft", "flappyGon", "rings", "trial"], trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon"], levels: [], @@ -23,7 +23,7 @@ const level = { // level.levelsCleared = 10 // level.updateDifficulty() // tech.giveTech("performance") - // m.maxHealth = m.health = 1//00000000 + // m.maxHealth = m.health = 100000000 // m.maxEnergy = m.energy = 10000000 // tech.isRerollDamage = true // powerUps.research.changeRerolls(99999) @@ -48,24 +48,24 @@ const level = { // requestAnimationFrame(() => { tech.giveTech("non-renewables") }); // tech.giveTech("dark matter") // tech.addJunkTechToPool(0.5) - // for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot") - // for (let i = 0; i < 1; ++i) tech.giveTech("quantum immortality") + // for (let i = 0; i < 1; ++i) tech.giveTech("pigeonhole principle") + // for (let i = 0; i < 1; ++i) tech.giveTech("generalist") // m.skin.egg(); // for (let i = 0; i < 1; ++i) tech.giveTech("many-worlds") // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("quasiparticles") }); - // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("field coupling") }); + // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("interest") }); // for (let i = 0; i < 1; i++) tech.giveTech("interest") // m.lastKillCycle = m.cycle // for (let i = 0; i < 1; i++) powerUps.directSpawn(450, -50, "warp"); // for (let i = 0; i < 7; i++) powerUps.directSpawn(m.pos.x + 200, m.pos.y - 250, "research", false); // spawn.bodyRect(575, -700, 150, 150); //block mob line of site on testing - // level.cocoon(); + // level.corridor(); level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** - // for (let i = 0; i < 1; ++i) spawn.shieldingBoss(1900, -500) + // for (let i = 0; i < 1; ++i) spawn.powerUpBossBaby(1900, -500) // for (let i = 0; i < 1; i++) spawn.mantisBoss(1900, -500) // for (let i = 0; i < 1; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "entanglement"); @@ -168,14 +168,14 @@ const level = { tech.tokamakHealCount = 0 tech.buffedGun++ if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0; - if (tech.isGunCycle && (b.activeGun !== null && b.activeGun !== undefined) && b.inventory.length) { + if ((tech.isGunCycle || tech.isGunChoice) && (b.activeGun !== null && b.activeGun !== undefined) && b.inventory.length) { b.inventoryGun = tech.buffedGun; simulation.switchGun(); } - if (tech.isGunChoice && Number.isInteger(tech.buffedGun) && b.inventory.length) { - var gun = b.guns[b.inventory[tech.buffedGun]].name - simulation.inGameConsole(`pigeonhole principle: ${(1.3 * Math.max(0, b.inventory.length)).toFixed(2)}x damage for ${gun}`, 600); - } + // if (tech.isGunChoice && Number.isInteger(tech.buffedGun) && b.inventory.length) { + // var gun = b.guns[b.inventory[tech.buffedGun]].name + // simulation.inGameConsole(`pigeonhole principle: ${(1 + 0.4 * Math.max(0, b.inventory.length)).toFixed(2)}x damage for ${gun}`, 600); + // } if (tech.isSwitchReality && level.levelsCleared !== 0) { simulation.inGameConsole(`simulation.amplitude = ${Math.random()}`); m.switchWorlds("many-worlds") @@ -187,7 +187,12 @@ const level = { for (let i = 0; i < len; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "heal", false); } if (tech.interestRate > 0) { - const rate = ((level[level.levels[level.onLevel]].name === "final" || level[level.levels[level.onLevel]].name === "subway") ? 1 / 3 : 1) * tech.interestRate //this effect triggers extra times on these final levels + // const rate = ((level[level.levels[level.onLevel]].name === "final" || level[level.levels[level.onLevel]].name === "subway") ? 1 / 3 : 1) * tech.interestRate //this effect triggers extra times on these final levels + let rate = tech.interestRate + if (level.onLevel < level.levels.length - 1) {//make sure it's not on the lore level which has an undefined name + const levelName = level.levels[level.onLevel] + if (levelName === "final" || levelName === "subway") rate *= 1 / 3 + } let ammoSum = 0 for (let i = 0; i < b.inventory.length; i++) { @@ -315,10 +320,13 @@ const level = { } //update HUD with constraints let text = `${level.constraintDescription1}` + if (level.constraintDescription1) simulation.inGameConsole(`constraint: ${level.constraintDescription1}`) if (simulation.difficultyMode > 6 && level.constraintDescription2) { text += `
${level.constraintDescription2}` + if (level.constraintDescription2) simulation.inGameConsole(`constraint: ${level.constraintDescription2}`) } document.getElementById("right-HUD-constraint").innerHTML = text + if (level.constraintDescription1) { if (level.constraintDescription2) { document.getElementById("right-HUD").style.top = "80px"; @@ -2290,6 +2298,55 @@ const level = { }, } }, + fizzler(p1, p2) { + return { + isOn: true, + position: p1, + look: p2, + color: color, + query() { + if (!m.isTimeDilated) { + // let best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null } + // best = vertexCollision(this.position, this.look, [body]); + + const hits = Matter.Query.ray(body, this.position, this.look, 25) + for (let i = hits.length - 1; i > -1; i--) { + // console.log(what) + const what = hits[i].bodyA + simulation.drawList.push({ x: what.position.x, y: what.position.y, radius: 11, color: "rgba(0,160,255,0.7)", time: 10 }); + if (what === m.holdingTarget) m.drop() + for (let i = 0; i < body.length; i++) { + if (body[i] === what) { + body.splice(i, 1); + break + } + } + Matter.Composite.remove(engine.world, what); + } + //draw + ctx.beginPath(); + ctx.moveTo(this.position.x, this.position.y); + ctx.lineTo(this.look.x, this.look.y); + // ctx.strokeStyle = "rgba(50,200,255,0.3)"; + // ctx.lineWidth = 2 + 5 * Math.random() + // ctx.stroke(); + ctx.strokeStyle = "rgba(50,160,255,0.17)"; + ctx.lineWidth = 35 + 25 * Math.random() * Math.random(); + ctx.stroke(); + + //draw random dots in the path + if (Math.random() < 0.05) { + const r = Math.random(); + const where = { + x: this.position.x + r * (this.look.x - this.position.x) + 60 * (Math.random() - 0.5), + y: this.position.y + r * (this.look.y - this.position.y) + 60 * (Math.random() - 0.5) + }; + simulation.drawList.push({ x: where.x, y: where.y, radius: 6, color: "rgba(0,160,255,0.7)", time: 5 }); + } + } + }, + } + }, isHazardRise: false, hazard(x, y, width, height, damage = 0.002) { return { @@ -2474,6 +2531,19 @@ const level = { ctx.lineDashOffset = (-simulation.cycle * this.VxGoal) % 80; ctx.stroke(); ctx.setLineDash([0, 0]); + }, + drawFast() { + ctx.beginPath(); + const v = this.vertices; + ctx.moveTo(v[0].x + 2, v[0].y); + // for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y); + ctx.lineTo(v[1].x - 2, v[1].y); + ctx.strokeStyle = "#000" + ctx.lineWidth = 4; + ctx.setLineDash([60, 60]); + ctx.lineDashOffset = (-simulation.cycle * this.VxGoal) % 120; + ctx.stroke(); + ctx.setLineDash([0, 0]); } }); Matter.Body.setStatic(rect, true); //make static @@ -5410,7 +5480,7 @@ const level = { if (badBlocks[j] === body[i]) index = i } //remove block - console.log(index, j) + // console.log(index, j) if (index) { Matter.Composite.remove(engine.world, badBlocks[j]); body.splice(index, 1); @@ -7199,7 +7269,7 @@ const level = { let buildMapOutline = function () { //boxes center on zero,zero with deep walls to hide background - spawn.mapRect(2000, -2000, 2000, 4000); //right map wall + spawn.mapRect(2025, -2000, 1975, 4000); //right map wall spawn.mapRect(-4000, -2000, 2000, 4000); //left map wall spawn.mapRect(-4000, -5000, 8000, 3000); //map ceiling spawn.mapRect(-4000, 2000, 8000, 3000); //floor @@ -7233,7 +7303,7 @@ const level = { balance.push(level.rotor(-750, 1755, 400, 25, 0.01, Math.PI / 2, 0.5)) balance.push(level.rotor(-275, 1675, 550, 32, 0.01, 0, 0.5)) - lasers.push(level.laser({ x: -1625, y: -850 }, { x: 1980, y: -850 })) ////x, y, width, height, damage = 0.002) + lasers.push(level.laser({ x: 1610, y: -850 }, { x: -1625, y: -850 })) ////x, y, width, height, damage = 0.002) // spawn.mapRect(1980, -862, 25, 25); //laser entrance // balance.push(level.rotor(1000, -910, 550, 32, 0.01, 0, 0.5)) @@ -7263,9 +7333,9 @@ const level = { spawn.mapRect(1925, 800, 200, 200); spawn.mapRect(1925, 1300, 200, 200); - spawn.mapRect(1400, 1650, 200, 25); - spawn.mapRect(1400, 1125, 200, 25); - spawn.mapRect(1400, 600, 200, 25); + spawn.mapRect(1250, 1650, 500, 25); + spawn.mapRect(1300, 1125, 400, 25); + spawn.mapRect(1350, 600, 300, 25); spawn.mapRect(1400, 75, 200, 25); spawn.mapRect(650, 1287, 475, 50); @@ -7273,9 +7343,9 @@ const level = { spawn.mapRect(650, 150, 500, 225); spawn.mapRect(350, 1300, 800, 375); spawn.mapRect(350, 950, 150, 400); - spawn.mapRect(175, 950, 325, 100); - spawn.mapRect(150, 525, 350, 200); - spawn.mapRect(150, 75, 350, 200); + spawn.mapRect(-25, 950, 525, 100); + spawn.mapRect(-75, 525, 575, 200); + spawn.mapRect(-75, 75, 575, 200); spawn.mapRect(475, 1987, 550, 50); //ceiling zone @@ -7315,7 +7385,7 @@ const level = { balance.push(level.rotor(-750, -1755 - 25, 400, 25, 0.01, Math.PI / 2, 0.5)) balance.push(level.rotor(-250, -1675 - 32, 500, 32, 0.01, 0, 0.5)) - lasers.push(level.laser({ x: -1625, y: 850 }, { x: 1980, y: 850 })) ////x, y, width, height, damage = 0.002) + lasers.push(level.laser({ x: 1610, y: 850 }, { x: -1625, y: 850 })) ////x, y, width, height, damage = 0.002) // spawn.mapRect(1980, 862 - 25, 25, 25); //laser entrance // balance.push(level.rotor(1000, 910 - 32, 550, 32, 0.01, 0, 0.5)) @@ -7340,9 +7410,9 @@ const level = { spawn.mapRect(1925, -800 - 200, 200, 200); spawn.mapRect(1925, -1300 - 200, 200, 200); - spawn.mapRect(1400, -1650 - 25, 200, 25); - spawn.mapRect(1400, -1125 - 25, 200, 25); - spawn.mapRect(1400, -600 - 25, 200, 25); + spawn.mapRect(1250, -1650 - 25, 500, 25); + spawn.mapRect(1300, -1125 - 25, 400, 25); + spawn.mapRect(1350, -600 - 25, 300, 25); spawn.mapRect(1400, -75 - 25, 200, 25); spawn.mapRect(650, -1287 - 50, 475, 50); @@ -7350,11 +7420,10 @@ const level = { spawn.mapRect(650, -150 - 225, 500, 225); spawn.mapRect(350, -1300 - 375, 800, 375); spawn.mapRect(350, -950 - 400, 150, 400); - spawn.mapRect(175, -950 - 100, 325, 100); - spawn.mapRect(150, -525 - 200, 350, 200); - spawn.mapRect(150, -75 - 200, 350, 200); + spawn.mapRect(-25, -950 - 100, 525, 100); + spawn.mapRect(-75, -525 - 200, 575, 200); + spawn.mapRect(-75, -75 - 200, 575, 200); spawn.mapRect(475, -1987 - 50, 550, 50); - //ceiling zone spawn.mapRect(1200, 1575, 400, 25); spawn.mapRect(-75, 1700, 1075, 25); @@ -7463,16 +7532,16 @@ const level = { //spawn second wave of flipped mobs only once spawn.randomMob(-1500, -1425, 0); spawn.randomMob(-950, -1425, 0); - spawn.randomMob(-800, -1475, 0.1); - spawn.randomMob(-425, -1425, 0.1); - spawn.randomMob(850, -1750, 0.2); - spawn.randomMob(325, -850, 0.2); - spawn.randomMob(400, -400, 0.3); - spawn.randomMob(825, -475, 0.3); - spawn.randomMob(875, -1050, 0.4); - spawn.randomMob(1425, 1425, 0.5); - spawn.randomMob(675, 1450, 0.7); - spawn.randomMob(225, 1475, 0.9); + spawn.randomMob(-800, -1475, 0); + spawn.randomMob(-425, -1425, 0); + spawn.randomMob(850, -1750, 0.1); + spawn.randomMob(325, -850, 0.1); + spawn.randomMob(400, -400, 0.2); + spawn.randomMob(825, -475, 0.2); + spawn.randomMob(875, -1050, 0.3); + spawn.randomMob(1425, 1425, 0.4); + spawn.randomMob(675, 1450, 0.5); + spawn.randomMob(225, 1475, 0.6); spawn.randomMob(-275, 1425, 1); spawn.randomMob(-800, 1375, 1); @@ -7551,7 +7620,7 @@ const level = { ctx.fillRect(-1075, -2025, 450, 725); ctx.fillRect(-575, -2025, 450, 725); - ctx.fillRect(175, -250 - 725, 325, 725); + ctx.fillRect(-25, -250 - 725, 525, 725); ctx.fillRect(650, -350 - 975, 475, 975); ctx.fillRect(375, -1650 - 400, 750, 400); //ceiling @@ -7569,7 +7638,7 @@ const level = { ctx.fillRect(-1075, 1300, 450, 725); ctx.fillRect(-575, 1300, 450, 725); - ctx.fillRect(175, 250, 325, 725); + ctx.fillRect(-25, 250, 525, 725); ctx.fillRect(650, 350, 475, 975); ctx.fillRect(375, 1650, 750, 400); //ceiling @@ -7581,6 +7650,9 @@ const level = { ctx.fillRect(-1625, -2025, 475, 450); } }; + spawn.bodyRect(1325, -1775, 175, 175); + spawn.bodyRect(-375, -1725, 100, 75, 0.5); + spawn.bodyRect(-900, -1625, 125, 200, 0.5); spawn.bodyRect(-1662, 1325, 25, 175); spawn.bodyRect(-1662, 1825, 25, 175); @@ -7601,24 +7673,24 @@ const level = { spawn.randomMob(-1350, -1750, 0); spawn.randomMob(-875, -1575, 0); spawn.randomMob(500, -1875, 0); - spawn.randomMob(350, 825, 0.1); - spawn.randomMob(375, 400, 0.1); - spawn.randomMob(1500, -25, 0.2); - spawn.randomMob(650, -1950, 0.3); - spawn.randomMob(775, 700, 0.3); - spawn.randomMob(275, -50, 0.4); - spawn.randomMob(75, -1750, 0.5); - spawn.randomMob(1750, -1425, 0.5); - spawn.randomMob(950, 50, 0.6); - spawn.randomMob(-1375, 175, 0.6); - spawn.randomMob(-350, 175, 0.7); - spawn.randomMob(725, 1175, 0.7); - spawn.randomMob(-850, -1950, 0.8); - spawn.randomMob(-1400, -1725, 0.9); - spawn.randomMob(1400, -1700, 0.9); - spawn.randomMob(-800, 200, 0.9); - spawn.randomMob(1475, 1550, 1); - spawn.randomMob(1475, 500, 1); + spawn.randomMob(350, 825, 0); + spawn.randomMob(375, 400, 0); + spawn.randomMob(1500, -25, 0.1); + spawn.randomMob(650, -1950, 0.2); + spawn.randomMob(775, 700, 0.2); + spawn.randomMob(275, -50, 0.3); + spawn.randomMob(75, -1750, 0.3); + spawn.randomMob(1750, -1425, 0.4); + spawn.randomMob(950, 50, 0.4); + spawn.randomMob(-1375, 175, 0.4); + spawn.randomMob(-350, 175, 0.5); + spawn.randomMob(725, 1175, 0.5); + spawn.randomMob(-850, -1950, 0.6); + spawn.randomMob(-1400, -1725, 0.7); + spawn.randomMob(1400, -1700, 0.7); + spawn.randomMob(-800, 200, 0.7); + spawn.randomMob(1475, 1550, 0.8); + spawn.randomMob(1475, 500, 0.8); powerUps.spawnStartingPowerUps(-875, -1925); spawn.randomLevelBoss(-875, -200); @@ -8155,45 +8227,256 @@ const level = { powerUps.directSpawn(2100, 925, "heal"); powerUps.directSpawn(625, -100, "heal"); }, - cocoon() { + corridor() { // simulation.fallHeight = 4000 level.announceMobTypes() - level.setPosToSpawn(-3800, 950); - level.exit.x = 3750 - level.exit.y = -625 - level.defaultZoom = 2000 + level.defaultZoom = 2400 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d0d5d5"; color.map = "#444" + // level.isHorizontalFlipped = true + if (level.isHorizontalFlipped) { + level.setPosToSpawn(14075, -625); + level.exit.x = -350 + level.exit.y = 505 + spawn.bodyRect(13525, -675, 50, 100); + var color1 = "rgba(0,20,60,0.09)" + var color2 = "rgba(0,255,255,0.1)" + } else { + level.setPosToSpawn(-350, 475); + level.exit.x = 14025 + level.exit.y = -600 + spawn.bodyRect(-225, 475, 50, 50); + var color1 = "rgba(0,255,255,0.1)" + var color2 = "rgba(0,20,60,0.09)" + } + spawn.mapRect(14015, -585, 120, 75); //exit/entrance platform + const buttonLeft = level.button(-4100, 991) + const buttonRight = level.button(4050, 991) + buttonLeft.isUp = true + // const buttonCamera = level.button(940, -1545) + // buttonRight.isUp = false + const boosts = [] + boosts.push(level.boost(-3650, 990, 2700, 1.45)) + boosts.push(level.boost(3325, 990, 1600, 1.4)) + boosts.push(level.boost(7960, -1110, 1650, 2.3)) + boosts.push(level.boost(13345, -460, 2070, 2.35)) + const fizzlers = [] + fizzlers.push(level.fizzler({ x: -135, y: 265 }, { x: -135, y: 535 })) + fizzlers.push(level.fizzler({ x: -3850, y: 650 }, { x: -3850, y: 1025 })) + fizzlers.push(level.fizzler({ x: 3875, y: 675 }, { x: 3875, y: 1025 })) + fizzlers.push(level.fizzler({ x: 13425, y: -1275 }, { x: 13425, y: -550 })) + const movers = [] + const baseMoverSpeed = 15 + movers.push(level.mover(-3550, 995, 6875, 150, -baseMoverSpeed)) + movers.push(level.mover(225, -1190, 2450, 50, -baseMoverSpeed)) + movers.push(level.mover(-3000, -1190, 3000, 50, baseMoverSpeed)) + movers.push(level.mover(4000, -2025, 2000, 150, -23)) + movers.push(level.mover(8000, -1125, 2000, 150, -23)) + movers.push(level.mover(3775, -425, 1650, 150, 20)) + movers.push(level.mover(5425, -425, 1925, 150, 40)) + movers.push(level.mover(7350, -425, 6000, 150, 60)) + function setMoverDirection(index, VxGoal, force) { + movers[index].VxGoal = VxGoal + movers[index].force = force + } level.custom = () => { + // buttonCamera.query() + // if (!buttonCamera.isUp) { + // simulation.setCameraPosition(100, -1000, 0.29) + // //block spawner + // spawn.mapRect(0, -2375, 200, 100); + // if (!(simulation.cycle % 10) && !m.isTimeDilated && body.length < 200) { + // const where = { x: 112, y: -3800 } + // // simulation.drawList.push({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 100 * (Math.random() - 0.5), radius: 11, color: "rgba(0,160,255,0.5)", time: 10 }); + + // let makeBlock = function (where, size) { + // const sides = Math.floor(4 + 6 * Math.random() * Math.random()) + // body[body.length] = Matter.Bodies.polygon(where.x, where.y, sides, size, { + // friction: 0.05, + // frictionAir: 0.001, + // collisionFilter: { + // category: cat.body, + // mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet + // }, + // classType: "body", + // density: 0.001, + // }); + // const who = body[body.length - 1] + // Composite.add(engine.world, who); //add to world + // } + // makeBlock({ x: where.x, y: where.y }, Math.floor(20 + 35 * Math.random() * Math.random())) + // } + // } + ctx.fillStyle = "#c8cccc"//background color is "#d0d5d5" + ctx.fillRect(-2150, 675, 500, 400); + ctx.fillRect(-1050, 675, 500, 400); + ctx.fillRect(750, 675, 500, 400); + ctx.fillRect(1850, 675, 500, 400); + ctx.fillRect(-2250, -2425, 700, 1325); + ctx.fillRect(-1150, -2400, 700, 1300); + ctx.fillRect(650, -2375, 700, 1325); + ctx.fillRect(1750, -2375, 700, 1350); + ctx.fillRect(8000, -2425, 2000, 2225); + ctx.fillRect(4000, -2375, 2000, 2100); + ctx.fillRect(11125, -2425, 1000, 2150) level.exit.drawAndCheck(); level.enter.draw(); + if (buttonRight.isUp) { + buttonRight.query(); + if (!buttonRight.isUp) { + requestAnimationFrame(() => buttonLeft.isUp = true); + setMoverDirection(0, -baseMoverSpeed, -0.0005) + const list = Matter.Query.region(body, buttonLeft) //are any blocks colliding with this + if (list.length > 0) Matter.Body.setVelocity(list[0], { x: baseMoverSpeed, y: -20 }); + } + } else if (buttonLeft.isUp) { + buttonLeft.query(); + if (!buttonLeft.isUp) { + requestAnimationFrame(() => buttonRight.isUp = true); + setMoverDirection(0, 20, 0.0005) + const list = Matter.Query.region(body, buttonRight) //are any blocks colliding with this + if (list.length > 0) Matter.Body.setVelocity(list[0], { x: -15, y: -20 }); + } + } + buttonRight.draw(); + buttonLeft.draw(); + for (let i = 0; i < movers.length; i++) movers[i].push(); + for (let i = 0; i < boosts.length; i++) boosts[i].query(); }; level.customTopLayer = () => { - ctx.fillStyle = "rgba(0,255,255,0.1)" //"#d4f4f4" //exit - ctx.fillRect(3535, -1050, 500, 475); - + for (let i = 0; i < fizzlers.length; i++) fizzlers[i].query(); + ctx.fillStyle = color1 //exit + ctx.fillRect(13400, -1325, 1000, 825); //shadows - ctx.fillStyle = "rgba(0,20,60,0.09)" - // ctx.fillRect(-4025, -1050, 1750, 2275); + ctx.fillStyle = color2 + ctx.fillRect(-500, 225, 494, 350); + ctx.fillStyle = "rgba(0,5,10,0.06)" + ctx.beginPath(); + ctx.moveTo(0, -1180) + ctx.lineTo(225, -1180) + ctx.lineTo(3220, 669) + ctx.lineTo(3180, 1010) + ctx.lineTo(-2960, 1010) + ctx.lineTo(-2995, 674) + ctx.fill() + ctx.beginPath(); + //right button room + ctx.beginPath(); + ctx.moveTo(3780, 720) + ctx.lineTo(4325, 720) + ctx.lineTo(4325, 1010) + ctx.lineTo(3810, 1010) + ctx.fill() + //left button room + ctx.beginPath(); + ctx.moveTo(-3755, 675) + ctx.lineTo(-3785, 1010) + ctx.lineTo(-4250, 1010) + ctx.lineTo(-4250, 675) + ctx.fill() + ctx.fillStyle = "rgba(68, 68, 68,0.9)" + ctx.fillRect(-50, -4300, 325, 1950); + for (let i = 0; i < movers.length; i++) movers[i].draw(); }; - //boxes center on zero,zero with deep walls to hide background - spawn.mapRect(4000, -2000, 2000, 4000); //right map wall - spawn.mapRect(-6000, -2000, 2000, 4000); //left map wall - spawn.mapRect(-6000, -4000, 12000, 3000); //map ceiling spawn.mapRect(-6000, 1000, 12000, 3000); //floor + spawn.mapRect(-6000, -4300, 6020, 1950); + spawn.mapRect(205, -4300, 15120, 1950); + spawn.mapVertex(-250, 602.5, "-200 0 235 0 400 50 400 150 -200 150"); + spawn.mapVertex(-3675, -2275, "0 0 500 0 0 500"); + spawn.mapVertex(13275, -2275, "0 0 -500 0 0 500"); + spawn.mapRect(-525, -1175, 525, 1450); + spawn.mapRect(225, -1175, 3000, 1850); + spawn.mapRect(-3000, -1175, 2525, 1850); + spawn.mapRect(-4350, -2500, 600, 3175); + spawn.mapRect(-6000, -2350, 1775, 3350); + spawn.mapVertex(-1900, 675, "-350 0 -250 100 250 100 350 0"); + spawn.mapVertex(-800, 675, "-350 0 -250 100 250 100 350 0"); + spawn.mapVertex(1000, 675, "-350 0 -250 100 250 100 350 0"); + spawn.mapVertex(2100, 675, "-350 0 -250 100 250 100 350 0"); + + spawn.mapVertex(-1900, -1450, "-400 -40 -350 -90 350 -90 400 -40 400 40 350 90 -350 90 -400 40"); + spawn.mapVertex(-800, -1450, "-400 -40 -350 -90 350 -90 400 -40 400 40 350 90 -350 90 -400 40"); + spawn.mapVertex(1000, -1450, "-400 -40 -350 -90 350 -90 400 -40 400 40 350 90 -350 90 -400 40"); + spawn.mapVertex(2100, -1450, "-400 -40 -350 -90 350 -90 400 -40 400 40 350 90 -350 90 -400 40"); + + spawn.mapVertex(-1900, -2350, "-450 0 -350 100 350 100 450 0"); + spawn.mapVertex(-800, -2350, "-450 0 -350 100 350 100 450 0"); + spawn.mapVertex(1000, -2350, "-450 0 -350 100 350 100 450 0"); + spawn.mapVertex(2100, -2350, "-450 0 -350 100 350 100 450 0"); + spawn.mapRect(-1500, 840, 300, 20); + spawn.mapRect(1400, 840, 300, 20); + //ramp to catch blocks + spawn.mapVertex(3001, -1260, "0 0 400 -200 550 -200 550 75 0 75"); + spawn.mapVertex(4100, -1100, "-625 0 -600 -60 600 -60 625 0 600 60 -600 60"); + spawn.mapVertex(5550, -750, "-625 0 -600 -60 600 -60 625 0 600 60 -600 60"); + spawn.mapVertex(11625, -900, "-525 0 -500 -50 500 -50 525 0 500 50 -500 50"); + //base for mover + spawn.mapVertex(5000, -1935, "-1050 0 -1000 -90 1000 -90 1050 0 1000 90 -1000 90"); + spawn.mapVertex(9000, -1035, "-1050 0 -1000 -90 1000 -90 1050 0 1000 90 -1000 90"); + spawn.mapVertex(5000, -2370, "-1200 0 -1000 100 1000 100 1200 0"); + spawn.mapVertex(9000, -2310, "-1200 0 -1000 100 1000 100 1200 0"); + spawn.mapVertex(11625, -2310, "-600 0 -500 100 500 100 600 0"); + spawn.mapRect(3775, -400, 675, 1125); + spawn.mapRect(4300, -400, 11025, 4400); + //exit + spawn.mapRect(13400, -575, 1925, 300); + spawn.mapRect(14275, -2375, 1050, 2050); + spawn.mapRect(13400, -2375, 900, 1125); - // spawn.randomMob(2825, 75, 0.9); - // spawn.randomLevelBoss(2400, 600); - // spawn.secondaryBossChance(800, -300) - // powerUps.spawnStartingPowerUps(600, 375); - // powerUps.addResearchToLevel() //needs to run after mobs are spawned + //blocks on movers + spawn.bodyRect(-200, 950, 50, 50); + spawn.bodyRect(-1100, 925, 65, 75); + spawn.bodyRect(-2275, 975, 70, 25); + spawn.bodyRect(-3325, 925, 75, 75); + spawn.bodyRect(-2950, -1225, 90, 25); + spawn.bodyRect(-1425, -1275, 45, 75); + spawn.bodyRect(600, -1275, 70, 75); + spawn.bodyRect(1900, -1225, 90, 50); + spawn.bodyRect(4250, -2100, 115, 50); + spawn.bodyRect(2175, 900, 100, 65); + spawn.bodyRect(4075, -450, 75, 20); + spawn.bodyRect(8350, -1175, 90, 50); + spawn.bodyRect(6525, -525, 70, 100); + spawn.bodyRect(12025, -475, 130, 50); + spawn.bodyRect(625, 950, 55, 45); + spawn.bodyRect(6250, -450, 55, 25); + spawn.bodyRect(3950, -475, 46, 53); + //other blocks + spawn.bodyRect(3525, -1300, 100, 125, 0.6); + spawn.bodyRect(11550, -1150, 100, 200, 0.4); + + spawn.randomMob(-1775, -1650, 0); + spawn.randomMob(950, -1775, 0); + spawn.randomMob(1550, 775, 0); + spawn.randomMob(4500, -1250, 0); + spawn.randomMob(11400, -1300, 0); + spawn.randomMob(-800, -1675, 0); + spawn.randomMob(-1325, 775, 0.1); + spawn.randomMob(2050, -1625, 0.1); + spawn.randomMob(3100, -1475, 0.2); + spawn.randomMob(5400, -900, 0.2); + spawn.randomMob(11950, -1025, 0.3); + spawn.randomMob(-925, -1700, 0.3); + spawn.randomMob(2025, -1725, 0.4); + spawn.randomMob(1575, 775, 0.4); + spawn.randomMob(-1350, 775, 0.6); + spawn.randomMob(11925, -1275, 0.6); + spawn.randomMob(4325, -1425, 0.6); + spawn.randomMob(5425, -950, 0.6); + spawn.randomMob(3575, 375, 0.6); + spawn.randomGroup(5300, -1400, 1.3); + + spawn.randomLevelBoss(2025, -1825); + spawn.secondaryBossChance(-1900, -1800); + powerUps.spawnStartingPowerUps(11750, -1000); + powerUps.addResearchToLevel() //needs to run after mobs are spawned }, lock() { level.announceMobTypes() @@ -8930,9 +9213,9 @@ const level = { simulation.zoomTransition(level.defaultZoom) powerUps.spawnStartingPowerUps(4900, -500); //1 per level - spawn.debris(1000, 20, 1800, 3); //16 debris per level //but less here because a few mobs die from laser - spawn.debris(4830, -1330, 850, 3); //16 debris per level - spawn.debris(3035, -3900, 1500, 3); //16 debris per level + spawn.debris(1000, 20, 1800, 6); //16 debris per level + // spawn.debris(4830, -1330, 850, 3); //16 debris per level + // spawn.debris(3035, -3900, 1500, 3); //16 debris per level document.body.style.backgroundColor = "#dbdcde"; @@ -8998,6 +9281,11 @@ const level = { spawn.mapRect(4100, -3450, 100, 850); //left top shelf spawn.mapRect(4600, -3450, 100, 1850); + //steps up and down + spawn.mapVertex(4525, 250, "-650 0 -625 -20 625 -20 650 0"); + spawn.mapVertex(4525, 237, "-550 0 -525 -20 525 -20 550 0"); + // spawn.mapVertex(4525, 225, "-400 0 -375 -20 375 -20 400 0"); + spawn.randomSmallMob(4400, -3500); spawn.randomSmallMob(4800, -800); spawn.randomMob(800, -2600); @@ -36987,6 +37275,19 @@ const level = { level.enter.draw(); level.exit.drawAndCheck(); + + //check if blocks are in the exit zone and destroy them + for (let i = 0; i < body.length; i++) { + if (body[i].position.x > 1675) { + Matter.Composite.remove(engine.world, body[i]); + body.splice(i, 1); + break + } + } + //if no blocks left make a new one + if (body.length < 2) { //< 2 because the door is a body + spawn.bodyRect(1025, -550, 50, 50); + } }; level.customTopLayer = () => { buttonDoor.query(); @@ -37076,6 +37377,18 @@ const level = { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) + //check if blocks are in the exit zone and destroy them + for (let i = 0; i < body.length; i++) { + if (body[i].position.x > 1675 && body[i].position.y > -350) { + Matter.Composite.remove(engine.world, body[i]); + body.splice(i, 1); + break + } + } + //if no blocks left make a new one + if (body.length < 2) { //< 2 because the door is a body + spawn.bodyRect(1025, -550, 50, 50); + } }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall @@ -37136,6 +37449,19 @@ const level = { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) + + //check if blocks are in the exit zone and destroy them + for (let i = 0; i < body.length; i++) { + if (body[i].position.x > 1675 && body[i].position.y > -350) { + Matter.Composite.remove(engine.world, body[i]); + body.splice(i, 1); + break + } + } + //if no blocks left make a new one + if (body.length < 2) { //< 2 because the door is a body + spawn.bodyRect(1025, -550, 50, 50); + } }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall diff --git a/js/mob.js b/js/mob.js index 1c3af8a..30197db 100644 --- a/js/mob.js +++ b/js/mob.js @@ -41,23 +41,15 @@ const mobs = { ctx.fillRect(x, y, w, h); ctx.fillStyle = "rgba(255,0,0,0.7)"; ctx.fillRect(x, y, w * mob[i].health, h); + // if (mob[i].isInvulnerable) { + // ctx.strokeStyle = "rgba(255,255,255,1)"; + // ctx.lineWidth = 5 + // ctx.strokeRect(x, y, w, h); + // } } } }, - healthBar() { - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].seePlayer.recall && mob[i].showHealthBar) { - const h = mob[i].radius * 0.3; - const w = mob[i].radius * 2; - const x = mob[i].position.x - w / 2; - const y = mob[i].position.y - w * 0.7; - ctx.fillStyle = "rgba(100, 100, 100, 0.3)"; - ctx.fillRect(x, y, w, h); - ctx.fillStyle = "rgba(255,0,0,0.7)"; - ctx.fillRect(x, y, w * mob[i].health, h); - } - } - }, + healthBar() { }, statusSlow(who, cycles = 60) { applySlow(who) //look for mobs near the target @@ -1384,7 +1376,7 @@ const mobs = { //replace dead mob with a regular body replace(i) { //if there are too many bodies don't turn into blocks to help performance - if (this.leaveBody && body.length < mobs.maxMobBody && this.mass < 200 && this.radius > 18) { + if (this.leaveBody && body.length < mobs.maxMobBody && this.mass < 200 && this.mass > 2 && this.radius > 18) { let v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure if (v.length > 5 && body.length < 35 && Math.random() < 0.25) { const cutPoint = 3 + Math.floor((v.length - 6) * Math.random()) //Math.floor(v.length / 2) @@ -1397,6 +1389,8 @@ const mobs = { 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"; + body[len].frictionAir = 0.001 + body[len].friction = 0.05 Composite.add(engine.world, body[len]); //add to world const len2 = body.length; @@ -1406,6 +1400,8 @@ const mobs = { body[len2].collisionFilter.category = cat.body; body[len2].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; body[len2].classType = "body"; + body[len2].frictionAir = 0.001 + body[len2].friction = 0.05 Composite.add(engine.world, body[len2]); //add to world //large mobs shrink so they don't block paths @@ -1429,8 +1425,9 @@ const mobs = { 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"; + body[len].frictionAir = 0.001 + body[len].friction = 0.05 Composite.add(engine.world, body[len]); //add to world - //large mobs shrink so they don't block paths if (body[len].mass > 9) { const massLimit = 7 + 4 * Math.random() diff --git a/js/player.js b/js/player.js index d4502b1..83d4a47 100644 --- a/js/player.js +++ b/js/player.js @@ -782,7 +782,7 @@ const m = { defense() { let dmg = 1 if (powerUps.boost.isDefense && powerUps.boost.endCycle > simulation.cycle) dmg *= 0.3 - if (tech.isMaxHealthDefense && m.health === m.maxHealth) dmg *= 0.3 + if (tech.isMaxHealthDefense && m.health === m.maxHealth) dmg *= 0.2 if (tech.isDiaphragm) dmg *= 0.55 + 0.35 * Math.sin(m.cycle * 0.0075); if (tech.isZeno) dmg *= 0.15 if (tech.isFieldHarmReduction) dmg *= 0.6 @@ -1773,7 +1773,7 @@ const m = { tungsten() { m.hardLandCDScale = 2 m.hardLanding = 60 - m.coyoteCycles = 0 + // m.coyoteCycles = 0 m.isAltSkin = true m.color = { hue: 210, diff --git a/js/powerup.js b/js/powerup.js index 55f057e..213eb8d 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -785,7 +785,7 @@ const powerUps = { m.addHealth(heal); if (healOutput > 0) simulation.inGameConsole(`
  m.health += ${(healOutput).toFixed(3)}`) //
${m.health.toFixed(3)} if (tech.isOverHeal && overHeal > 0) { //tech quenching - tech.extraMaxHealth += 0.4 * overHeal //increase max health + tech.extraMaxHealth += 0.5 * overHeal //increase max health m.setMaxHealth(); simulation.inGameConsole(`
  m.maxHealth += ${(0.3 * overHeal).toFixed(3)}`) simulation.drawList.push({ //add dmg to draw queue diff --git a/js/simulation.js b/js/simulation.js index 55f696c..df22584 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -558,14 +558,14 @@ const simulation = { } }, nextGun() { - if (b.inventory.length > 1 && !tech.isGunCycle) { + if (b.inventory.length > 1 && !(tech.isGunCycle || tech.isGunChoice)) { b.inventoryGun++; if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0; simulation.switchGun(); } }, previousGun() { - if (b.inventory.length > 1 && !tech.isGunCycle) { + if (b.inventory.length > 1 && !(tech.isGunCycle || tech.isGunChoice)) { b.inventoryGun--; if (b.inventoryGun < 0) b.inventoryGun = b.inventory.length - 1; simulation.switchGun(); @@ -768,7 +768,7 @@ const simulation = { } }, setupCamera() { //makes the camera not scroll after changing locations - // //only works if velocity is zero + // only works if velocity is zero m.pos.x = player.position.x; m.pos.y = playerBody.position.y - m.yOff; const scale = 0.8; @@ -794,6 +794,20 @@ const simulation = { simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; }, + //for moving camera away from player + setCameraPosition(x, y, zoom = 1) { + ctx.restore(); + ctx.save(); + ctx.translate(canvas.width2, canvas.height2); //center + ctx.scale(zoom, zoom); //zoom in once centered + ctx.translate(- x, - y); //center + + // ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered + // ctx.translate(-canvas.width2, -canvas.height2); //translate + //calculate in game mouse position by undoing the zoom and translations + simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; + simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; + }, cameraNoLook() { ctx.save(); ctx.translate(canvas.width2, canvas.height2); //center diff --git a/js/spawn.js b/js/spawn.js index b2eb361..9b9f2a8 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1015,7 +1015,7 @@ const spawn = { return } } - if (simulation.testing || simulation.difficultyMode > 5) { + if (simulation.testing || simulation.difficultyMode > 6) { unlockExit() setTimeout(function () { simulation.inGameConsole(`level.levels.length = Infinite`); @@ -2704,7 +2704,10 @@ const spawn = { this.isInvulnerable = false this.damageReduction = this.startingDamageReduction for (let i = 0; i < this.babyList.length; i++) { - if (this.babyList[i].alive) this.babyList[i].damageReduction = this.startingDamageReduction + if (this.babyList[i].alive) { + this.babyList[i].isInvulnerable = false + this.babyList[i].damageReduction = this.startingDamageReduction + } } } } else if (this.invulnerabilityCountDown < 0) { @@ -6022,7 +6025,7 @@ const spawn = { simulation.drawList.push({ x: this.position.x, y: this.position.y, - radius: 3000, + radius: 5000, color: `rgba(0, 0, 0,${1 - 0.1 * i})`, time: (i + 2) * 4 }); diff --git a/js/tech.js b/js/tech.js index ce794fd..778fa1b 100644 --- a/js/tech.js +++ b/js/tech.js @@ -67,7 +67,7 @@ const tech = { tech.junkChance += percent if (tech.junkChance < 0.001 || tech.junkChance === undefined) tech.junkChance = 0 if (tech.junkChance > 1) tech.junkChance = 1 - simulation.inGameConsole(`+${(100 * percent).toFixed(0)}% JUNKtech chance (${(100 * tech.junkChance).toFixed(0)} total chance)`) + simulation.inGameConsole(`+${(100 * percent).toFixed(0)}% JUNKtech chance (${(100 * tech.junkChance).toFixed(0)}% total chance)`) // tech.junkChance += (1 - tech.junkChance) * percent return percent @@ -266,7 +266,7 @@ const tech = { damageFromTech() { let dmg = tech.damage * m.fieldDamage if (level.isNoDamage && (m.cycle - 180 < level.noDamageCycle)) dmg *= 0.3 - if (tech.isMaxHealthDamage && m.health === m.maxHealth) dmg *= 1.5 + if (tech.isMaxHealthDamage && m.health === m.maxHealth) dmg *= 2 if (tech.noDefenseSettingDamage && m.defense() === 1) dmg *= 2.5 if (tech.isImmunityDamage && m.immuneCycle > m.cycle) dmg *= 3 if (tech.isPowerUpDamage) dmg *= 1 + 0.07 * powerUp.length @@ -275,7 +275,7 @@ const tech = { if (tech.isDivisor && b.activeGun !== undefined && b.activeGun !== null && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.9 if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.9 : 2 if (tech.isDilate) dmg *= 1.9 + 1.1 * Math.sin(m.cycle * 0.01) - if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.3 * b.inventory.length + if (tech.isGunChoice) dmg *= 1 + 0.4 * b.inventory.length if (powerUps.boost.endCycle > simulation.cycle) dmg *= 1 + powerUps.boost.damage if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.025 * m.coupling if (tech.isVerlet) dmg *= 3 @@ -781,13 +781,16 @@ const tech = { { name: "pigeonhole principle", descriptionFunction() { - let info = "" - if (this.count > 0 && Number.isInteger(tech.buffedGun) && b.inventory.length) { - let gun = b.guns[b.inventory[tech.buffedGun]].name - info = `
this level: ${(1.3 * Math.max(0, b.inventory.length)).toFixed(2)}x damage for ${gun}` - } - return `a new ${powerUps.orb.gun()} in your inventory is chosen each level
if it's equipped, 1.3x damage per ${powerUps.orb.gun()} in your inventory${info}
` + return `1.4x damage per ${powerUps.orb.gun()}, but your equipped ${powerUps.orb.gun()}
cycles each level and you can't switch` }, + // descriptionFunction() { + // let info = "" + // if (this.count > 0 && Number.isInteger(tech.buffedGun) && b.inventory.length) { + // let gun = b.guns[b.inventory[tech.buffedGun]].name + // info = `
this level: ${(1.3 * Math.max(0, b.inventory.length)).toFixed(2)}x damage for ${gun}` + // } + // return `a new ${powerUps.orb.gun()} in your inventory is chosen each level
if it's equipped, 1.3x damage per ${powerUps.orb.gun()} in your inventory${info}
` + // }, maxCount: 1, count: 0, frequency: 1, @@ -807,7 +810,7 @@ const tech = { }, { name: "generalist", - description: `spawn 7 ${powerUps.orb.gun()}, but you can't switch ${powerUps.orb.gun()}
your equipped ${powerUps.orb.gun()} cycles after each level`, + description: `spawn 7 ${powerUps.orb.gun()}, but your equipped ${powerUps.orb.gun()}
cycles each level and you can't switch`, maxCount: 1, count: 0, frequency: 1, @@ -815,9 +818,9 @@ const tech = { isInstant: true, isBadRandomOption: true, allowed() { - return (b.inventory.length < b.guns.length - 5) && (b.inventory.length > 1) + return (b.inventory.length < b.guns.length - 5) && b.inventory.length > 1 }, - requires: "at least 2 guns, at least 5 unclaimed guns", + requires: "you have at least 2 guns and 5 unclaimed guns", effect() { tech.isGunCycle = true; for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun"); @@ -982,7 +985,7 @@ const tech = { if (this.count === 0) this.gun = Math.floor(Math.random() * (b.guns.length - 1)) //don't pick laser return `2x ammo per ${powerUps.orb.ammo(1)} for ${b.guns[this.gun].name}` }, - maxCount: 9, + maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, @@ -1432,7 +1435,7 @@ const tech = { name: "zoospore vector", link: `zoospore vector`, descriptionFunction() { - return `after mobs die there is a 10% chance
they grow ${b.guns[6].nameString('s')}` + return `after mobs die there is a 13% chance
they grow ${b.guns[6].nameString('s')}` }, // description: "after mobs die
they have a +10% chance to grow spores", maxCount: 9, @@ -1444,7 +1447,7 @@ const tech = { }, requires: "no other mob death tech", effect() { - tech.sporesOnDeath += 0.1; + tech.sporesOnDeath += 0.13; // if (tech.isSporeWorm) { // for (let i = 0; i < 4; i++) b.worm(m.pos) // } else { @@ -2890,7 +2893,7 @@ const tech = { }, { name: "overcharge", - description: "+88 maximum energy
+4% JUNK choices", + description: "+100 maximum energy
+5% JUNK choices", maxCount: 9, count: 0, frequency: 1, @@ -2900,9 +2903,9 @@ const tech = { }, requires: "", effect() { - tech.bonusEnergy += 0.88 + tech.bonusEnergy += 1 m.setMaxEnergy() - this.refundAmount += tech.addJunkTechToPool(0.04) + this.refundAmount += tech.addJunkTechToPool(0.05) }, refundAmount: 0, remove() { @@ -3063,7 +3066,7 @@ const tech = { { name: "stability", descriptionFunction() { - return `0.3x damage taken
while your health is at maximum` + return `0.2x damage taken
while your health is at maximum` }, maxCount: 1, count: 0, @@ -3103,7 +3106,7 @@ const tech = { { name: "control theory", descriptionFunction() { - return `1.5x damage
while your health is at maximum` + return `2x damage
while your health is at maximum` }, maxCount: 1, count: 0, @@ -3329,7 +3332,7 @@ const tech = { { name: "quenching", descriptionFunction() { - return `0.4x of ${powerUps.orb.heal()} overhealing
is added to maximum health` + return `0.5x of ${powerUps.orb.heal()} overhealing
is added to maximum health` }, maxCount: 1, count: 0, @@ -3455,7 +3458,7 @@ const tech = { return true }, requires: "", - rate: 0.06, + rate: 0.05, effect() { tech.interestRate += this.rate; }, @@ -4318,7 +4321,7 @@ const tech = { }, { name: "replication", - description: "+10% chance to duplicate spawned power ups
+15% JUNK choices", + description: "+10% chance to duplicate spawned power ups
+10% JUNK choices", maxCount: 9, count: 0, frequency: 1, @@ -4331,7 +4334,7 @@ const tech = { tech.duplicateChance += 0.1 powerUps.setPowerUpMode(); //needed after adjusting duplication chance if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.1); - this.refundAmount += tech.addJunkTechToPool(0.15) + this.refundAmount += tech.addJunkTechToPool(0.10) }, refundAmount: 0, remove() { @@ -5532,7 +5535,7 @@ const tech = { }, { name: "phase velocity", - description: "wave particles propagate faster as solids
1.4x wave damage", + description: "wave particles propagate faster as solids
1.5x wave damage", isGunTech: true, maxCount: 1, count: 0, @@ -5584,11 +5587,11 @@ const tech = { requires: "wave", effect() { tech.waveBeamSpeed *= 0.75; - tech.waveBeamDamage += 0.3 * 0.4 //this sets base wave damage + tech.waveBeamDamage *= 1.4 //this sets base wave damage }, remove() { tech.waveBeamSpeed = 11; - tech.waveBeamDamage = 0.3 //this sets base wave damage + tech.waveBeamDamage = 0.4 //this sets base wave damage } }, { diff --git a/style.css b/style.css index 2feb1f4..9b15685 100644 --- a/style.css +++ b/style.css @@ -1568,9 +1568,9 @@ summary { } .draw-lines4 { - stroke-dasharray: 300; - stroke-dashoffset: 300; - animation: dash 2.5s ease-in forwards; + stroke-dasharray: 500; + stroke-dashoffset: 500; + animation: dash 3.5s ease-in forwards; } diff --git a/todo.txt b/todo.txt index 4f149f2..7d47bf9 100644 --- a/todo.txt +++ b/todo.txt @@ -1,17 +1,45 @@ ******************************************************** NEXT PATCH ************************************************** -reworked focuser mobs to fire blue energy draining laser instead of charging player +new level corridor + new level element fizzler - it removes blocks +interferometer has wider platforms, a few helpful blocks, and fewer mobs +level constraints are announced in console + +foam gun no longer pushes the player back when firing +wave gun buffs + 1.2x base damage + 1.1x base ammo + 0.1->0.13x speed in map + 0.25->0.30x speed in blocks + tech: phase velocity 1.4->1.5x damage +pigeonhole principle gives 1.3->1.4 damage per gun + you can no longer switch guns, your gun cycles each level +quenching 0.4->0.5x overheal converts into max health +tungsten carbide no longer has reduced coyote cycles +control theory 1.5->2x damage at max health +stability 0.3->0.2 damage taken at max health +overcharge +88->100 max energy, 4->5% JUNK +zoospore vector 10->13% chance for spores on mob death +replication 15->10% JUNK +interest 6->5% of your power ups spawn each level + +updated "about" details menu + moved classic n-gon to here from settings + added links to community content in "about" + Are there more links I should add? + added an n-gon SVG head image + +bugs + fixed outline on splash screen doesn't sync right on safari browser + fixed possible lock out on training levels: "hold", "throw", "throwAt" + from losing block behind a door + shortcut sort buttons in experiment mode properly order tech without clicking sort + fixed/increased the horizontal velocity contribution for some guns + this makes bullets shot on moving platforms more realistic + nail gun, super balls, foam, harpoon ******************************************************** BUGS ******************************************************** - couple reports of crashes from many-worlds - around level 5-7 - for me crash on factory level 7 - might be linked to having all the guns? - the crash was in matter.js something about collisions and undefined - maybe too many things were spawned in the same spot? - also occurs when you just gain many random tech in testing mode - figure out why seeded random isn't making runs the same: shuffle is being used for a wide variety of things that don't need a seeded random make two shuffle functions? @@ -27,32 +55,17 @@ figure out why seeded random isn't making runs the same: doesn't seem to be determined by the seed... display future constraints in pause menu? -at start of level game go stuck in pause state - no crash or bug report - occur level 8 - after 2 levels of sending power ups to next level - auto drones grabbed a power up and game froze while in power up mode - running code to exit pause kinda worked - -ants marching outline on splash screen doesn't sync right on safari - player can become crouched while not touching the ground if they exit the ground while crouched *********************************************************** TODO ***************************************************** -new level - something with movers, rubber band blocks -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: demineralization - 0.2x damage taken, but it slowly reduces effect + increase to full: + at start of level? + when you get the tech + decrease: + over time + at start of new level !!conformal - similar rules for small and big scales linked to holographic principle !!holonomy - parallel transport of a vector leads to movement (applies to curved space) @@ -288,16 +301,6 @@ make a lemming that walks until it hits a wall and then turns around robotically body or mob? can't be killed? -use ephemera to replace some bad code - JUNK? - request animation stuff - simulation checks - damage and defense bars - disable and enable ephemera with settings - -perfect diamagnatism - invulnerable while field is active? - also drain energy while field is active? - mobs attack mines mines periodically set all mobs to have player location to be the mine is this going to work with all mob vision types? @@ -311,23 +314,8 @@ Tech: relativity wormhole tech - teleport away mobs with mass below 3 when they get too near the player short CD, small energy cost, only mobs below a mass -extend brainstorming animation timers to fps cap? - will it be smoother or choppier? - anything else needs to hit limited fps on a high fps monitor? - -perfect diamagnatism could bounce on mobs, or even map elements? - could work like a rocket jump? - tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy? - -make super balls with Zectron deflectable with field - but is there a simple way to do this? - -set mob health bar colors based on status effects? - make mob damage immunity a mob status effect? -tech: rail gun area damage effect, but for all harpoon mode - mob status effect - vulnerability mobs take 4x damage for __ time afterwards mobs go back to normal damage taken @@ -1242,6 +1230,7 @@ possible names for tech De Sitter space - simple model of universe related to general relativity (mass-energy?) active optics - something with lasers? maybe something with diffuse beam getting smaller Quintessence - related to dark energy + biofilm - something defensive? related to spores? ******************************************************* DESIGN ****************************************************** @@ -1277,12 +1266,13 @@ n-gon fork kgurchiek.github.io/n-gon-portal-gun 3xiondev.github.io/n-gon-upgraded coaldeficit.github.io/c-gon - c-rxxp-y.github.io/n-gon-enhanced + n-gon-enhanced.vercel.app bookmarlet github.com/Whyisthisnotavalable/n-scythe github.com/kgurchiek/n-gon-mobile github.com/kgurchiek/n-gon-controller + text ngon.fandom.com/wiki/N-gon github.com/3xionDev/n-docs \ No newline at end of file