diff --git a/index.html b/index.html index f4ad3af..7e4f908 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,8 @@
-
+
+
@@ -89,6 +90,7 @@ +
diff --git a/js/bullet.js b/js/bullet.js index 052abf1..b5ed3c1 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -85,11 +85,13 @@ const b = { if (tech.crouchAmmoCount && m.crouch) { if (tech.crouchAmmoCount % 2) { b.guns[b.activeGun].ammo--; + if (level.is2xAmmo && b.guns[b.activeGun].ammo > 0) b.guns[b.activeGun].ammo--; simulation.updateGunHUD(); } tech.crouchAmmoCount++ //makes the no ammo toggle off and on } else { b.guns[b.activeGun].ammo--; + if (level.is2xAmmo && b.guns[b.activeGun].ammo > 0) b.guns[b.activeGun].ammo--; simulation.updateGunHUD(); } }, @@ -1360,29 +1362,6 @@ const b = { ctx.lineWidth = 0.5 ctx.stroke(); - // ctx.lineTo(this.vertices[0].x, this.vertices[0].y); - // if (tech.isHookWire) { - // //draw wire - // const hitMob = Matter.Query.ray(mob, this.position, m.pos, 10) - // if (hitMob.length && m.immuneCycle < m.cycle) { - // for (let i = 0; i < hitMob.length; i++) { - // console.log(hitMob[i].bodyA) - // // simulation.drawList.push({ //add dmg to draw queue - // // x: path[path.length - 1].x, - // // y: path[path.length - 1].y, - // // radius: Math.sqrt(2000 * damage * best.who.damageReduction) + 2, - // // color: tech.laserColorAlpha, - // // time: simulation.drawTime - // // }); - // hitMob[i].bodyA.damage(0.001) - // } - // } - // //draw glow around wire - // ctx.strokeStyle = "rgba(0,255,255,0.2)" // "#0ce" - // ctx.lineWidth = 20 - // ctx.stroke(); - // } - if (this.powerUpDamage) { ctx.beginPath(); ctx.moveTo(this.vertices[0].x, this.vertices[0].y); @@ -1416,9 +1395,7 @@ const b = { beforeDmg(who) { if (tech.isShieldPierce && who.isShielded) { //disable shields who.isShielded = false - requestAnimationFrame(() => { - who.isShielded = true - }); + requestAnimationFrame(() => { who.isShielded = true }); } if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs if (tech.hookNails) { @@ -1501,8 +1478,10 @@ const b = { if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) this.collisionFilter.mask = 0//cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body //recoil on pulling grapple back - const mag = this.pickUpTarget ? Math.max(this.pickUpTarget.mass, 0.5) : 0.5 - const momentum = Vector.mult(Vector.sub(this.position, m.pos), mag * (m.crouch ? 0.0001 : 0.0002)) + // if (this.pickUpTarget.mass) console.log(this.pickUpTarget.mass) + const mag = this.pickUpTarget ? Math.min(5, Math.max(this.pickUpTarget.mass, 0.5)) : 0.5 + const unit = Vector.normalise(Vector.sub(this.position, m.pos)) + const momentum = Vector.mult(unit, mag * (m.crouch ? 0.1 : 0.2)) player.force.x += momentum.x player.force.y += momentum.y }, @@ -1511,7 +1490,9 @@ const b = { if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player this.endCycle = 0; //recoil on catching grapple - const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002)) + // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002)) + const unit = Vector.normalise(Vector.sub(this.velocity, player.velocity)) + const momentum = Vector.mult(unit, (m.crouch ? 0.0001 : 0.0002)) player.force.x += momentum.x player.force.y += momentum.y if (this.pickUpTarget) { @@ -1530,8 +1511,11 @@ const b = { // give block to player after it returns m.isHolding = true; //conserve momentum when player mass changes - totalMomentum = Vector.add(Vector.mult(player.velocity, player.mass), Vector.mult(Vector.normalise(this.velocity), 15 * Math.min(20, this.pickUpTarget.mass))) - Matter.Body.setVelocity(player, Vector.mult(totalMomentum, 1 / (m.defaultMass + this.pickUpTarget.mass))); + const blockMass = Math.min(5, this.pickUpTarget.mass) + const grappleMomentum = Vector.mult(Vector.normalise(this.velocity), 15 * blockMass) + const playerMomentum = Vector.mult(player.velocity, player.mass) + totalMomentum = Vector.add(playerMomentum, grappleMomentum) + Matter.Body.setVelocity(player, Vector.mult(totalMomentum, 1 / (m.defaultMass + blockMass))); m.definePlayerMass(m.defaultMass + this.pickUpTarget.mass * m.holdingMassScale) //make block collide with nothing @@ -1542,7 +1526,7 @@ const b = { } else { if (m.energy > this.drain) m.energy -= this.drain const sub = Vector.sub(this.position, m.pos) - const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player + const rangeScale = 1 + 0.000003 * Vector.magnitude(sub) //return faster when far from player const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass) this.force.x -= returnForce.x this.force.y -= returnForce.y @@ -1582,16 +1566,13 @@ const b = { //position block on hook Matter.Body.setPosition(this.pickUpTarget, Vector.add(this.vertices[2], this.velocity)) Matter.Body.setVelocity(this.pickUpTarget, { x: 0, y: 0 }) - } else { // if (!input.down) + } else { const blocks = Matter.Query.collides(this, body) 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 < 40) { this.retract() 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) @@ -1620,22 +1601,7 @@ const b = { 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.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) { - } } }, @@ -1665,41 +1631,17 @@ const b = { }, do() { if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5 - if (input.field) { //&& !Matter.Query.collides(this, body).length - // this.destroyBlocks() + if (input.field) { this.grabBlocks() this.grabPowerUp() - // if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down field, force retraction - // this.endCycle = simulation.cycle + 30 - // // m.fireCDcycle = m.cycle + 120 // cool down - // this.do = this.returnToPlayer - // Matter.Body.setDensity(this, 0.0005); //reduce density on return - // if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) - // this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body - // } } else { - //if not enough energy - // if (m.energy < 0.01) this.dropCaughtPowerUp() - // const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass) - // this.force.x -= returnForce.x - // this.force.y -= returnForce.y - // this.frictionAir = 0.002 - // this.do = () => { - // if (this.speed < 20) this.force.y += 0.0005 * this.mass; - // } - - // } else { - //return to player this.retract() - // } } //grappling hook 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.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) @@ -1709,22 +1651,14 @@ const b = { Matter.Body.setVelocity(this, { x: 0, y: 0 }); Matter.Sleeping.set(this, true) this.endCycle = simulation.cycle + 5 - // this.dropCaughtPowerUp() this.do = () => { if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5 - // if (this.caughtPowerUp) { - // Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity)) - // Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 }) - // } this.grabPowerUp() //between player nose and the grapple const sub = Vector.sub(this.vertices[0], { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }) let dist = Vector.magnitude(sub) if (input.field) { - // m.fireCDcycle = m.cycle + 30; // cool down if out of energy - // m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05) - // if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5 this.endCycle = simulation.cycle + 10 if (input.down) { //down this.isSlowPull = true @@ -1738,52 +1672,18 @@ const b = { // pulling friction that allowed a slight swinging, but has high linear pull at short dist const drag = 1 - 30 / Math.min(Math.max(100, dist), 700) - 0.1 * (player.speed > 66) - // console.log(player.speed) Matter.Body.setVelocity(player, { x: player.velocity.x * drag, y: player.velocity.y * drag }); - const pullScale = 0.0004 - const pull = Vector.mult(Vector.normalise(sub), pullScale * Math.min(Math.max(15, dist), this.isSlowPull ? 70 : 200)) + const pull = Vector.mult(Vector.normalise(sub), 0.0004 * Math.min(Math.max(15, dist), this.isSlowPull ? 70 : 200)) //original pulling force with high friction and very linear pull // Matter.Body.setVelocity(player, { x: player.velocity.x * 0.85, y: player.velocity.y * 0.85 }); // const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), this.isSlowPull ? 100 : 200)) player.force.x += pull.x player.force.y += pull.y - if (dist > 500) { - m.energy -= this.drain - // if (m.energy < 0) this.endCycle = 0; - } - - // if (tech.isImmuneGrapple && m.immuneCycle < m.cycle + 10) { - // m.immuneCycle = m.cycle + 10; - // if (m.energy > 0.001) { - // m.energy -= 0.001 - // } else { //out of energy - // Matter.Sleeping.set(this, false) - // this.collisionFilter.category = 0 - // this.collisionFilter.mask = 0 - // this.do = this.returnToPlayer - // this.endCycle = simulation.cycle + 60 - // // m.fireCDcycle = m.cycle + 120; //fire cooldown - // if (m.fieldCDcycle < m.cycle + 120) m.fieldCDcycle = m.cycle + 120 - - // //recoil on catching - // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002)) - // player.force.x += momentum.x - // player.force.y += momentum.y - // } - // } + if (dist > 500) m.energy -= this.drain } else { Matter.Sleeping.set(this, false) this.retract() - // Matter.Sleeping.set(this, false) - // this.collisionFilter.category = 0 - // this.collisionFilter.mask = 0 - // this.do = this.returnToPlayer - // this.endCycle = simulation.cycle + 60 - // //recoil on catching - // const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002)) - // player.force.x += momentum.x - // player.force.y += momentum.y } this.draw(); } @@ -1976,6 +1876,7 @@ const b = { // refund ammo if (isReturnAmmo) { b.guns[9].ammo++; + if (level.is2xAmmo) b.guns[9].ammo++; simulation.updateGunHUD(); // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun // if (b.guns[i].name === "harpoon") { @@ -3101,13 +3002,13 @@ const b = { cd: simulation.cycle + 10, dmg: 0, setDamage() { //dmg is set to zero after doing damage once, and set back to normal after jumping - this.dmg = radius * (tech.isMutualism ? 2.9 : 1) //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18 + this.dmg = radius * (tech.isMutualism ? 3.3 : 1.1) //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18 }, beforeDmg(who) { Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target this.cd = simulation.cycle + this.delay; - if (!who.isInvulnerable) { - this.endCycle -= 130 + if (!who.isInvulnerable && this.dmg !== 0) { + this.endCycle -= 110 if (tech.isSporeFreeze) mobs.statusSlow(who, 90) if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) { setTimeout(() => { @@ -3164,10 +3065,7 @@ const b = { if (tech.isSporeFollow && !this.lockedOn && Matter.Query.ray(map, this.position, m.pos).length === 0) { this.lockedOn = { //make target player if there are no mobs to target position: m.pos, - velocity: { - x: 0, - y: 0 - } + velocity: { x: 0, y: 0 } } } if (this.lockedOn) { //hop towards mob target @@ -3189,10 +3087,7 @@ const b = { } this.force.y = -(0.03 + 0.08 * Math.random()) * this.mass } - Matter.Body.setVelocity(this, { - x: 0, - y: 0 - }); + Matter.Body.setVelocity(this, { x: 0, y: 0 }); this.setDamage() //after jumping damage is no longer zero } } @@ -3262,26 +3157,26 @@ const b = { Matter.Body.setVelocity(this, { x: unit.x, y: unit.y }); this.lockedOn = null } else { - if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) { - const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0) - b.explosion(this.position, max * 0.14 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end - if (tech.isForeverDrones) { - this.endCycle = 0 - b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) - bullet[bullet.length - 1].endCycle = Infinity - } else { - this.endCycle -= max - } - } else { - //move away from target after hitting - const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) - Matter.Body.setVelocity(this, { x: unit.x, y: unit.y }); - this.lockedOn = null - if (this.endCycle > simulation.cycle + this.deathCycles) { - this.endCycle -= 60 - if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles - } + // if (tech.isIncendiary && simulation.cycle + this.deathCycles < this.endCycle && !tech.isForeverDrones) { + // const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0) + // b.explosion(this.position, max * 0.14 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end + // if (tech.isForeverDrones) { + // this.endCycle = 0 + // b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) + // bullet[bullet.length - 1].endCycle = Infinity + // } else { + // this.endCycle -= max + // } + // } else { + //move away from target after hitting + const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) + Matter.Body.setVelocity(this, { x: unit.x, y: unit.y }); + this.lockedOn = null + if (this.endCycle > simulation.cycle + this.deathCycles) { + this.endCycle -= 60 + if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles } + // } } }, onEnd() { @@ -3344,8 +3239,15 @@ const b = { const scale = 0.995; Matter.Body.scale(this, scale, scale); }, + hasExploded: false, do() { if (simulation.cycle + this.deathCycles > this.endCycle) { + if (tech.isIncendiary && !this.hasExploded) { + this.hasExploded = true + // const max = Math.max(Math.min(this.endCycle - simulation.cycle - this.deathCycles, 1500), 0) + // this.endCycle -= max + b.explosion(this.position, 200 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end + } this.restitution = 0.2; if (tech.isDroneRespawn) { this.do = this.doRespawning @@ -3749,8 +3651,7 @@ const b = { bullet[me] = Bodies.polygon(where.x, where.y, 12, radius, b.fireAttributes(dir, false)); Composite.add(engine.world, bullet[me]); //add bullet to world Matter.Body.setVelocity(bullet[me], velocity); - bullet[me].calcDensity = function () { return 0.0007 + 0.0007 * tech.isSuperHarm + 0.0007 * tech.isBulletTeleport } - Matter.Body.setDensity(bullet[me], bullet[me].calcDensity()); + Matter.Body.setDensity(bullet[me], 0.0007 + 0.0007 * tech.isSuperHarm + 0.0007 * tech.isBulletTeleport); bullet[me].endCycle = simulation.cycle + Math.floor(270 + 90 * Math.random()); bullet[me].minDmgSpeed = 0; bullet[me].restitution = 1; @@ -3812,7 +3713,7 @@ const b = { this.endCycle = 0 } else if (tech.isSuperBounce) { const cycle = () => { - Matter.Body.setDensity(bullet[me], bullet[me].calcDensity() * 1.33);//33% more density and damage + Matter.Body.setDensity(this, (0.0007 + 0.0007 * tech.isSuperHarm + 0.0007 * tech.isBulletTeleport) * 1.33);//33% more density and damage this.endCycle = simulation.cycle + Math.floor(300 + 90 * Math.random()); //reset to full duration of time Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(this.velocity), 60)); //reset to high velocity let count = 5 @@ -4614,31 +4515,31 @@ const b = { for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.soundBotCount; i++) b.soundBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) - }) + }, !level.isSlowBots) for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) @@ -5067,8 +4968,8 @@ const b = { lookFrequency: 17 + Math.floor(7 * Math.random()) - 3 * tech.isSoundBotUpgrade, cd: 0, fireCount: 0, - fireLimit: 5 + 3 * tech.isSoundBotUpgrade, - delay: Math.floor((140 + (tech.isSoundBotUpgrade ? 0 : 50))),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade, + fireLimit: 5, + delay: Math.floor(140),// + 30 - 20 * tech.isFoamBotUpgrade,//20 + Math.floor(85 * b.fireCDscale) - 20 * tech.isFoamBotUpgrade, acceleration: (isKeep ? 0.005 : 0.001) * (1 + 0.5 * Math.random()), range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots() + !isKeep * 100, //how far from the player the bot will move endCycle: Infinity, @@ -5092,11 +4993,11 @@ const b = { arc: halfArc * 2, radius: 25, resonanceCount: 0, - dmg: (tech.isUpgraded ? 3.5 : 1.5) * m.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage * (tech.isBulletTeleport ? 1.5 : 1), + dmg: (tech.isUpgraded ? 9 : 1.5) * m.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage * (tech.isBulletTeleport ? 1.5 : 1), }) }, fire() { - if (!(simulation.cycle % (6 - 2 * tech.isSoundBotUpgrade))) { + if (!(simulation.cycle % 6)) { this.fireCount++ if (this.fireCount > this.fireLimit) { this.fireCount = 0 diff --git a/js/index.js b/js/index.js index 5275bee..e1f2b9a 100644 --- a/js/index.js +++ b/js/index.js @@ -443,7 +443,7 @@ const build = { build.generatePauseLeft() //makes the left side of the pause menu with the tech build.generatePauseRight() //makes the right side of the pause menu with the tech // build.sortTech('') //sorts tech into the order the player got them using tech.tech[i].cycle = m.cycle - document.getElementById("tech").style.display = "none" + document.getElementById("right-HUD").style.display = "none" document.getElementById("guns").style.display = "none" document.getElementById("field").style.display = "none" document.getElementById("health").style.display = "none" @@ -496,7 +496,7 @@ const build = { mass ${player.mass.toFixed(1)} ${m.coupling ? `
` + m.couplingDescription(m.coupling) + ` from ${(m.coupling).toFixed(0)} ${powerUps.orb.coupling(1)}` : ""}
duplication ${(tech.duplicationChance() * 100).toFixed(0)}% -JUNK ${(100 * tech.junkChance).toFixed(0)}% +JUNK ${(100 * (tech.junkChance + level.junkAdded)).toFixed(0)}% ${botText}

${level.levelAnnounce()} @@ -518,15 +518,16 @@ ${simulation.isCheating ? "

lore disabled" : ""}
difficulty parameters
- ${simulation.difficultyMode > 0 ? `
0.87x damage done per level
1.22x damage taken per level
` : " "} - ${simulation.difficultyMode > 1 ? `
-5 initial power ups
faster mobs and more mobs
` : " "} - ${simulation.difficultyMode > 2 ? `
0.87x damage done per level
1.22x damage taken per level
` : " "} - ${simulation.difficultyMode > 3 ? `
+1 boss per level
-1 ${powerUps.orb.tech()} per boss
` : " "} - ${simulation.difficultyMode > 4 ? `
0.87x damage done per level
1.22x damage taken per level
` : " "} - ${simulation.difficultyMode > 5 ? `
3x chance for shielded mobs
-3 initial power ups
` : " "} + ${simulation.difficultyMode > 0 ? `
0.87x damage, 1.2x damage taken per level
+1 boss on each level
` : " "} + ${simulation.difficultyMode > 1 ? `
more mob per level
faster mobs per level
` : " "} + ${simulation.difficultyMode > 2 ? `
0.87x damage, 1.2x damage taken per level
+1 random constraint on each level
` : " "} + ${simulation.difficultyMode > 3 ? `
+1 boss on each level
bosses spawn 1 fewer ${powerUps.orb.tech()}
` : " "} + ${simulation.difficultyMode > 4 ? `
0.87x damage, 1.2x damage taken per level
+1 random constraint on each level
` : " "} + ${simulation.difficultyMode > 5 ? `
0.5x initial damage
2x initial damage taken
` : " "}
-` +${simulation.difficultyMode > 2 ? `
active constraints
${level.constraintDescription1}
${level.constraintDescription2}
` : ""} + ` if (!localSettings.isHideHUD) text += `
console log @@ -577,6 +578,7 @@ ${simulation.isCheating ? "

lore disabled" : ""} document.getElementById("simulation-variables-details").open = localSettings.pauseMenuDetailsOpen[0] document.getElementById("difficulty-parameters-details").open = localSettings.pauseMenuDetailsOpen[1] document.getElementById("console-log-details").open = localSettings.pauseMenuDetailsOpen[2] + if (document.getElementById("constraints-details")) document.getElementById("constraints-details").open = localSettings.pauseMenuDetailsOpen[3] } }); }, @@ -742,6 +744,7 @@ ${simulation.isCheating ? "

lore disabled" : ""} if (document.getElementById("simulation-variables-details")) localSettings.pauseMenuDetailsOpen[0] = document.getElementById("simulation-variables-details").open if (document.getElementById("difficulty-parameters-details")) localSettings.pauseMenuDetailsOpen[1] = document.getElementById("difficulty-parameters-details").open if (document.getElementById("console-log-details")) localSettings.pauseMenuDetailsOpen[2] = document.getElementById("console-log-details").open + if (document.getElementById("constraints-details")) localSettings.pauseMenuDetailsOpen[3] = document.getElementById("constraints-details").open localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } @@ -755,7 +758,7 @@ ${simulation.isCheating ? "

lore disabled" : ""} document.getElementById("health-bg").style.display = "inline" } if (!localSettings.isHideHUD) { - document.getElementById("tech").style.display = "inline" + document.getElementById("right-HUD").style.display = "inline" document.getElementById("defense-bar").style.display = "inline" document.getElementById("damage-bar").style.display = "inline" } @@ -1404,7 +1407,6 @@ window.addEventListener("keydown", function (event) { simulation.previousGun(); break case input.key.pause: - if (input.isPauseKeyReady && m.alive && !build.isExperimentSelection) { input.isPauseKeyReady = false setTimeout(function () { input.isPauseKeyReady = true }, 300); @@ -1464,7 +1466,7 @@ window.addEventListener("keydown", function (event) { break case input.key.testing: if (m.alive && localSettings.loreCount > 0 && !simulation.paused && !build.isExperimentSelection) { - if (simulation.difficultyMode > 4) { + if (simulation.difficultyMode > 5) { simulation.inGameConsole("testing mode disabled for this difficulty"); break } @@ -1686,7 +1688,7 @@ window.addEventListener("keydown", function (event) { case "l": document.getElementById("field").style.display = "none" document.getElementById("guns").style.display = "none" - document.getElementById("tech").style.display = "none" + document.getElementById("right-HUD").style.display = "none" break } } @@ -1841,7 +1843,7 @@ if (localSettings.isAllowed && !localSettings.isEmpty) { lore.setTechGoal() if (localSettings.pauseMenuDetailsOpen === undefined) { - localSettings.pauseMenuDetailsOpen = [true, false, false] + localSettings.pauseMenuDetailsOpen = [true, false, false, true] localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } } else { @@ -1865,7 +1867,7 @@ if (localSettings.isAllowed && !localSettings.isEmpty) { key: undefined, isHideImages: true, //default to hide images isHideHUD: false, - pauseMenuDetailsOpen: [true, false, false] + pauseMenuDetailsOpen: [true, false, false, true] }; input.setDefault() if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage diff --git a/js/level.js b/js/level.js index 7a65370..7642005 100644 --- a/js/level.js +++ b/js/level.js @@ -36,29 +36,29 @@ const level = { // 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("shotgun") //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("spores") //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 // tech.laserColor = "#fff" // tech.laserColorAlpha = "rgba(255, 255, 255, 0.5)" // b.guns[8].ammo = 100000000 // requestAnimationFrame(() => { tech.giveTech("stimulated emission") }); - // tech.giveTech("1st ionization energy") - // for (let i = 0; i < 1; ++i) tech.giveTech("emergence") - // for (let i = 0; i < 1; ++i) tech.giveTech("foam-bot") - // for (let i = 0; i < 1; ++i) tech.giveTech("Bitter electromagnet") + // tech.giveTech("Hilbert space") + // for (let i = 0; i < 1; ++i) tech.giveTech("decoherence") + // for (let i = 0; i < 1; ++i) tech.giveTech("mass-energy equivalence") + // for (let i = 0; i < 1; ++i) tech.giveTech("depolarization") // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("wikipedia") }); // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("field coupling") }); - // for (let i = 0; i < 1; i++) tech.giveTech("Verlet integration") + // 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, "tech"); - // for (let i = 0; i < 1; i++) powerUps.directSpawn(m.pos.x, m.pos.y - 50, "difficulty", false); - // spawn.mapRect(575, -700, 25, 425); //block mob line of site on testing - // level.testing(); + // for (let i = 0; i < 3; i++) powerUps.directSpawn(m.pos.x + 200, m.pos.y - 50, "boost", false); + // spawn.bodyRect(575, -700, 150, 150); //block mob line of site on testing + // level.satellite(); level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** - // for (let i = 0; i < 1; ++i) spawn.powerUpBoss(1900, -500) + // for (let i = 0; i < 1; ++i) spawn.revolutionBoss(1900, -500) // for (let i = 0; i < 3; i++) spawn.starter(1900, -500) //ghosters need to spawn after the map loads // for (let i = 0; i < 1; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "entanglement"); @@ -96,10 +96,6 @@ const level = { if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } } - if (!simulation.isTraining) { - document.title = "n-gon: " + level.levelAnnounce(); - simulation.inGameConsole(`level.onLevel = "${level.levels[level.onLevel]}"`); - } simulation.setupCamera(player.position); simulation.setZoom(); level.addToWorld(); //add bodies to game engine @@ -133,6 +129,29 @@ const level = { powerUps.directSpawn(flip * localSettings.entanglement.position.x, localSettings.entanglement.position.y, "entanglement", false); } level.newLevelOrPhase() + if (!simulation.isTraining) { + simulation.inGameConsole(`level.onLevel = "${level.levels[level.onLevel]}"`); + document.title = "n-gon: " + level.levelAnnounce(); + } + + level.setConstraints() + if (!localSettings.isHideHUD) { + requestAnimationFrame(() => { + //grow and get bright + document.getElementById("right-HUD-constraint").style.opacity = 1 + document.getElementById("right-HUD-constraint").style.fontSize = "23px" + document.getElementById("right-HUD-constraint").style.top = simulation.difficultyMode > 4 ? "6px" : "9px" + setTimeout(() => { + if (m.alive) { + //fade to background + document.getElementById("right-HUD-constraint").style.opacity = 0.35 + document.getElementById("right-HUD-constraint").style.fontSize = "20px" + document.getElementById("right-HUD-constraint").style.top = "12px" + } + }, 5000); + }); + } + }, newLevelOrPhase() { //runs on each new level but also on final boss phases //used for generalist and pigeonhole principle @@ -161,12 +180,23 @@ const level = { } 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 - if (b.activeGun !== null && b.activeGun !== undefined && b.guns[b.activeGun].ammo !== Infinity) { - const ammoPerOrb = b.guns[b.activeGun].ammoPack - const a = Math.ceil(rate * b.guns[b.activeGun].ammo / ammoPerOrb) - powerUps.spawnDelay("ammo", a, 4); - simulation.inGameConsole(`${(rate * 100).toFixed(0)}% interest on ammo = ${a > 20 ? a + powerUps.orb.ammo(1) : powerUps.orb.ammo(a)}`) + + let ammoSum = 0 + for (let i = 0; i < b.inventory.length; i++) { + if (b.guns[b.inventory[i]].ammo !== Infinity) ammoSum += b.guns[b.inventory[i]].ammo / b.guns[b.inventory[i]].ammoPack } + if (ammoSum > 0 && b.inventory.length > 0) { + const amount = Math.ceil(rate * ammoSum / b.inventory.length) + powerUps.spawnDelay("ammo", amount, 4); + simulation.inGameConsole(`${(rate * 100).toFixed(0)}% interest on ammo = ${amount > 20 ? amount + powerUps.orb.ammo(1) : powerUps.orb.ammo(amount)}`) + } + + // if (b.activeGun !== null && b.activeGun !== undefined && b.guns[b.activeGun].ammo !== Infinity) { + // const ammoPerOrb = b.guns[b.activeGun].ammoPack + // const a = Math.ceil(rate * b.guns[b.activeGun].ammo / ammoPerOrb) + // powerUps.spawnDelay("ammo", a, 4); + // simulation.inGameConsole(`${(rate * 100).toFixed(0)}% interest on ammo = ${a > 20 ? a + powerUps.orb.ammo(1) : powerUps.orb.ammo(a)}`) + // } if (powerUps.research.count > 0) { const r = Math.ceil(rate * powerUps.research.count) simulation.inGameConsole(`${(rate * 100).toFixed(0)}% interest on research = ${r > 20 ? r + powerUps.orb.research(1) : powerUps.orb.research(r)}`) @@ -199,7 +229,6 @@ const level = { index = i } } - console.log(index) if (index) { //eject it const effect = Math.pow(1.1, tech.tech[index].count) simulation.inGameConsole(`${(effect).toFixed(2)}x damage //from obsolescence`, 360) @@ -221,23 +250,6 @@ const level = { simulation.difficulty = level.levelsCleared * simulation.difficultyMode if (simulation.isTraining) simulation.difficulty = 1 - // old - // normal mode m.dmgScale = 1, 0.81, 0.63, 0.5 - // why mode m.dmgScale = 1, 0.56, 0.3, 0.17 - // new - //constraint 0,1 m.dmgScale = 1, 0.8, 0.6, 0.5 - //constraint 2,3 m.dmgScale = 1, - //constraint 4,5 m.dmgScale = 1, 0.5, 0.3, 0.15 - - // old - //normal: simulation.dmgScale = 0.1, 0.5 ,1 ,1.5 ,2 ,2.5 - //hard: simulation.dmgScale = 0.1, 1 ,2 ,3 ,4 ,5 - //why: simulation.dmgScale = 0.1, 1.25 ,2.5 ,3.75 ,5 ,6.25 - // new - //0,1: simulation.dmgScale = 0.1, 0.5 ,1 ,1.5 ,2 ,2.5 - //2,3: simulation.dmgScale = 0.1, 1 ,2 ,3 ,4 ,5 - //3,4: simulation.dmgScale = 0.1, 1.25 ,2.5 ,3.75 ,5 ,6.25 - let scale = 1 if (simulation.difficultyMode > 3) { scale = 3 @@ -245,9 +257,12 @@ const level = { scale = 2 } m.dmgScale = Math.pow(0.87, level.levelsCleared * scale) - simulation.dmgScale = Math.max(0.1, 0.22 * level.levelsCleared * scale) //damage done by mobs scales with total levels + simulation.dmgScale = Math.max(0.1, 0.22 * level.levelsCleared * scale) //damage done by mobs scales with total levels //a bigger number means the player takes more damage + if (simulation.difficultyMode === 6) { + m.dmgScale *= 0.5 + simulation.dmgScale *= 2 + } - // simulation.healScale = 1 / (1 + simulation.difficulty * 0.043) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; if (simulation.difficultyMode === 1) { simulation.accelScale = 1.1 @@ -257,17 +272,283 @@ const level = { simulation.CDScale = Math.max(0.15, Math.pow(0.964, simulation.difficulty)) } }, - // difficultyIncrease(num = 1) { - // for (let i = 0; i < num; i++) { - // simulation.difficulty++ - // m.dmgScale *= 0.89; //damage done by player decreases each level - // if (simulation.accelScale < 6) simulation.accelScale *= 1.024 //mob acceleration increases each level - // if (simulation.CDScale > 0.15) simulation.CDScale *= 0.964 //mob CD time decreases each level - // } - // simulation.dmgScale = Math.max(0.1, 0.25 * simulation.difficulty) //damage done by mobs scales with total levels - // simulation.healScale = 1 / (1 + simulation.difficulty * 0.043) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; - // // console.log(`CD = ${simulation.CDScale}`) - // }, + constraintIndex: 0, + setConstraints() { + //populate array with possible constraints and reset constraints + level.constraintDescription1 = level.constraintDescription2 = "" + const possible = [] + for (let i = 0; i < level.constraint.length; i++) { + level.constraint[i].remove() + possible.push(i) + } + if (level.levels[level.onLevel] !== "null" && level.levels[level.onLevel] !== "initial" && !simulation.isTraining && m.alive && level.levelsCleared) { + if (simulation.difficultyMode > 2 && possible.length) { + //choose a random constraint from possible array and remove it from that array + // const index = possible[Math.floor(possible.length * Math.random())] + // const index = level.constraintIndex + // level.constraintIndex = 0 //REMOVE THIS FROM LIVE GAME, FOR TESTING ONLY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + level.constraint[level.constraintIndex].effect() + possible.splice(level.constraintIndex, 1) + //generate text to describe the active constraints for the pause menu + level.constraintDescription1 = level.constraint[level.constraintIndex].description + // simulation.inGameConsole(`${level.constraint[level.constraintIndex].description}`, 900); + + level.constraintIndex++ + if (level.constraintIndex > level.constraint.length - 1) level.constraintIndex = 0 + + if (simulation.difficultyMode > 4 && possible.length) { + // const index = possible[Math.floor(possible.length * Math.random())] + level.constraint[level.constraintIndex].effect() + possible.splice(level.constraintIndex, 1) + level.constraintDescription2 += level.constraint[level.constraintIndex].description + // simulation.inGameConsole(`${level.constraint[level.constraintIndex].description}`, 900); + + level.constraintIndex++ + if (level.constraintIndex > level.constraint.length - 1) level.constraintIndex = 0 + } + document.getElementById("right-HUD-constraint").style.display = "block"; + } else { + document.getElementById("right-HUD-constraint").style.display = "none"; + } + } else { + document.getElementById("right-HUD-constraint").style.display = "none"; + } + //update HUD with constraints + let text = `${level.constraintDescription1}` + if (simulation.difficultyMode > 4 && level.constraintDescription2) { + text += `
${level.constraintDescription2}` + } + document.getElementById("right-HUD-constraint").innerHTML = text + if (level.constraintDescription1) { + if (level.constraintDescription2) { + document.getElementById("right-HUD").style.top = "80px"; + } else { + document.getElementById("right-HUD").style.top = "57px"; //make room for tech list in "right-HUD" + } + } else { + document.getElementById("right-HUD").style.top = "15px"; + } + }, + constraintDescription1: "", //used in pause menu and console + constraintDescription2: "", + constraint: [ + { + description: "0.5x max health", + effect() { + level.isReducedHealth = true + m.setMaxHealth() + }, + remove() { + if (level.isReducedHealth) { + level.isReducedHealth = false + m.setMaxHealth() + m.addHealth(level.reducedHealthLost); + level.reducedHealthLost = 0 + } else { + level.isReducedHealth = false + } + + } + }, + { + description: "periodically spawn WIMPs", + effect() { + simulation.ephemera.push({ + name: "WIMPS", + time: 0, + levelName: level.levels[level.onLevel], + do() { + this.time++ + if (level.levels[level.onLevel] === this.levelName) { + if (!(this.time % 900)) spawn.WIMP(level.enter.x, level.enter.y) + } else { + simulation.removeEphemera(this.name); + } + }, + }) + }, + remove() { + + } + }, + { + description: "0.1x damage after getting power ups", + effect() { + level.isNoDamage = true + level.noDamageCycle = 0 + }, + remove() { + level.isNoDamage = false + level.noDamageCycle = 0 + } + }, + { + description: "mobs heal for your lost health", + effect() { + level.isMobHealPlayerDamage = true + }, + remove() { + level.isMobHealPlayerDamage = false + } + }, + { + description: "mob death heals nearby mobs", + effect() { + level.isMobDeathHeal = true + }, + remove() { + level.isMobDeathHeal = false + } + }, + { + description: "full damage taken after boss dies", + // description: "after boss dies damage taken = 1", + effect() { + level.noDefenseSetting = 1 //defense goes to zero once equal to 2 + }, + remove() { + level.noDefenseSetting = 0 + } + }, + { + description: "4x shielded mobs", + effect() { + level.isMobShields = true + }, + remove() { + level.isMobShields = false + } + }, + { + description: "50% JUNK chance", + effect() { + level.junkAdded = 0.5 + }, + remove() { + level.junkAdded = 0 + } + }, + { + description: "-1 choice", + effect() { + level.fewerChoices = true + }, + remove() { + level.fewerChoices = false + } + }, + { + description: "power ups in stasis", + effect() { + level.isNextLevelPowerUps = true + //remove all current power ups + for (let i = powerUp.length - 1; i > -1; i--) { + powerUps.powerUpStorage.push({ name: powerUp[i].name, size: powerUp[i].size }) + Matter.Composite.remove(engine.world, powerUp[i]); + powerUp.splice(i, 1) + } + }, + remove() { + level.isNextLevelPowerUps = false + if (powerUps.powerUpStorage.length) { + const delay = 5 + let i = 0 + let cycle = () => { + if (powerUps.powerUpStorage.length && m.alive && powerUp.length < 300) { + requestAnimationFrame(cycle); + if (!simulation.paused && !simulation.isChoosing) { + if (!(simulation.cycle % delay)) { + const where = { x: m.pos.x + 70 * (Math.random() - 0.5), y: m.pos.y + 70 * (Math.random() - 0.5) } + powerUps.directSpawn(where.x, where.y, powerUps.powerUpStorage[i].name, true, powerUps.powerUpStorage[i].size); + powerUps.powerUpStorage.splice(i, 1); + } + } + } else { + powerUps.powerUpStorage = [] + } + } + requestAnimationFrame(cycle); + } + } + }, + { + description: "33% of mobs respawn", + effect() { + level.isMobRespawn = true + }, + remove() { + level.isMobRespawn = false + } + }, + { + description: "0 duplication", + effect() { + level.isNoDuplicate = true + }, + remove() { + level.isNoDuplicate = false + } + }, + { + description: "2x ammo cost", + effect() { + level.is2xAmmo = true + }, + remove() { + level.is2xAmmo = false + } + }, + { + description: "0.5x max energy", + effect() { + level.isReducedEnergy = true + m.setMaxEnergy() + }, + remove() { + if (level.isReducedEnergy) { + level.isReducedEnergy = false + m.setMaxEnergy() + } else { + level.isReducedEnergy = false + } + + } + }, + { + description: "slow bots", + effect() { + level.isSlowBots = true + b.clearPermanentBots(); + b.respawnBots(); + }, + remove() { + if (level.isSlowBots) { + level.isSlowBots = false + b.clearPermanentBots(); + b.respawnBots(); + } else { + level.isSlowBots = false + } + + } + }, + ], + isMobShields: false, + junkAdded: 0, + isNextLevelPowerUps: false, + isMobRespawn: false, + fewerChoices: false, + isNoDuplicate: false, + is2xAmmo: false, + isReducedEnergy: false, + isSlowBots: false, + noDefenseSetting: 0, + isMobDeathHeal: false, + isMobHealPlayerDamage: false, + isNoDamage: false, + noDamageCycle: 0, + reducedHealthLost: 0, + isReducedHealth: false, levelAnnounce() { const cheating = simulation.isCheating ? "(testing)" : "" if (level.levelsCleared === 0) { @@ -310,8 +591,6 @@ const level = { } else { if (level.onLevel > level.levels.length - 1) level.onLevel = 0; } - - //reset lost tech display for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].isLost) tech.tech[i].isLost = false; @@ -321,7 +600,8 @@ const level = { 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 //|| level.levels[level.onLevel] === "subway" - if (!localSettings.isHideHUD && !simulation.isCheating && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor")) { + if (!localSettings.isHideHUD && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor")) { + // if (!localSettings.isHideHUD && m.alive) { //pause if (!simulation.paused) { simulation.paused = true; @@ -330,7 +610,8 @@ const level = { //build level info document.getElementById("choose-grid").style.gridTemplateColumns = "250px" //onclick="level.unPause()" - let text = `
` + // if (level.levels[level.onLevel] === "final") { //|| level.levels[level.onLevel] === "reactor" + let text = `
` for (let i = 0; i < level.levels.length; i++) { if (i < level.levelsCleared) { text += `
${level.levels[i]}
` @@ -345,14 +626,14 @@ const level = { // text += `
` } } - text += `
` + text += `
` document.getElementById("choose-grid").innerHTML = text //show level info document.getElementById("choose-grid").style.opacity = "1" document.getElementById("choose-grid").style.transitionDuration = "0.25s"; //how long is the fade in on document.getElementById("choose-grid").style.visibility = "visible" - + // } simulation.draw.cons(); simulation.draw.body(); level.customTopLayer(); @@ -386,37 +667,6 @@ const level = { } 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() { @@ -515,21 +765,6 @@ const level = { level.exit.x = -level.exit.x - 100 //minus the 100 because of the width of the graphic }, exitCount: 0, - // playerExitCheck() { - // if ( - // player.position.x > level.exit.x && - // player.position.x < level.exit.x + 100 && - // player.position.y > level.exit.y - 150 && - // player.position.y < level.exit.y - 40 && - // player.velocity.y < 0.1 - // ) { - // level.exitCount++ - // if (level.exitCount > 120) { - // level.exitCount = 0 - // level.nextLevel() - // } - // } - // }, setPosToSpawn(xPos, yPos) { m.spawnPos.x = m.pos.x = xPos; m.spawnPos.y = m.pos.y = yPos; @@ -626,7 +861,7 @@ const level = { let text = `

training

- Begin the guided tutorial that shows you how to use your ${powerUps.field()} and ${powerUps.orb.gun()}. + Begin the guided tutorial that shows you how to use your ${powerUps.orb.field()} and ${powerUps.orb.gun()}.

play

@@ -1296,10 +1531,7 @@ const level = { y: list[0].position.y }) } - Matter.Body.setVelocity(list[0], { - x: 0, - y: 0 - }); + Matter.Body.setVelocity(list[0], { x: 0, y: 0 }); } } this.isUp = false; @@ -2714,8 +2946,13 @@ const level = { spawn.mapRect(3000, -2800, 2600, 4600); //right wall // spawn.mapRect(-250, 0, 3600, 1800); //ground - spawn.mapRect(-250, 0, 2300, 1800); //split roof - spawn.mapRect(2150, 0, 1200, 1800); //split roof + spawn.mapRect(-250, 0, 2300, 1800); //ground + + Matter.Body.setVelocity(map[map.length - 1], { + x: 10, + y: -10 + }); + spawn.mapRect(2150, 0, 1200, 1800); //ground spawn.mapRect(2025, -3, 25, 15); //lip on power up chamber spawn.mapRect(2150, -3, 25, 15); //lip on power up chamber @@ -2923,7 +3160,6 @@ const level = { level.exit.x = 0; level.exit.y = -9000; // spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump disabled for performance - const stationWidth = 9000 let stationNumber = 0; let stationCustom = () => { } @@ -3004,6 +3240,7 @@ const level = { if (isExitOpen) { level.exit.x = x - 50; level.exit.y = -260; + if (simulation.difficultyMode < 6) powerUps.spawn(level.exit.x, level.exit.y - 100, "tech"); } else { var gateButton = level.button(x - 62, -237, 125, false) //x, y, width = 126, isSpawnBase = true gateButton.isUp = true @@ -4178,8 +4415,7 @@ const level = { // powerUps.spawnBossPowerUp(-3600, -100) powerUps.spawn(-3650, -50, "tech") powerUps.spawn(-3650, -150, "tech") - powerUps.spawn(-3650, -300, "tech") - // if (player.position.x < 2760 && player.position.x > 210) {} + if (simulation.difficultyMode < 6) powerUps.spawn(-3650, -300, "tech") } } }; @@ -4669,6 +4905,23 @@ const level = { if (!buttonLeft.isUp) { setMoverDirection(7) buttonRight.isUp = true //flip the other button up + + //remove any blocks on top of right button + const badBlocks = Matter.Query.region(body, buttonRight) + //figure out block's index + for (let j = 0; j < badBlocks.length; j++) { + let index = null + for (let i = 0; i < body.length; i++) { + if (badBlocks[j] === body[i]) index = i + } + //remove block + console.log(index, j) + if (index) { + Matter.Composite.remove(engine.world, badBlocks[j]); + body.splice(index, 1); + } + } + } } else if (buttonRight.isUp) { buttonRight.query(); @@ -4690,7 +4943,7 @@ const level = { } } - if (button1.isUp) { + if (button1.isUp) { //opens up secondary zone button1.query(); if (!button1.isUp) { isPowerLeft = false @@ -5375,7 +5628,7 @@ const level = { powerUps.directSpawn(x + 998, y - 333, "tech", false); } const powerUp1 = powerUp[powerUp.length - 1] - powerUp1.holdPosition = { x: powerUp1.position.x, y: powerUp1.position.y } + if (powerUp1) powerUp1.holdPosition = { x: powerUp1.position.x, y: powerUp1.position.y } let isSpawnedMobs = false doCustom.push( () => { @@ -5384,7 +5637,7 @@ const level = { // if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2000 && m.pos.y > y - 1300 && m.pos.y < y) { //is player inside this room? // isInRoom = true // } else - if (powerUp1.velocity.y !== 0) { //don't run this code if power up is gone //hack: powerUp1.velocity.y !== 0 seems to only be true if the power up up doesn't exist and is no longer being affected by gravity + if (powerUp1 && powerUp1.velocity.y !== 0) { //don't run this code if power up is gone //hack: powerUp1.velocity.y !== 0 seems to only be true if the power up doesn't exist and is no longer being affected by gravity ctx.strokeStyle = "#f0f" ctx.lineWidth = 2; if (Vector.magnitudeSquared(Vector.sub(m.pos, powerUp1.position)) < 90000) { //zone radius is 300 @@ -5446,10 +5699,7 @@ const level = { x: powerUp1.holdPosition.x + 4 * Math.random(), //1300 -2 y: powerUp1.holdPosition.y + 4 * Math.random() //335 -2 }); - Matter.Body.setVelocity(powerUp1, { - x: 0, - y: 0 - }); + Matter.Body.setVelocity(powerUp1, { x: 0, y: 0 }); } else if (!isSpawnedMobs) { isSpawnedMobs = true if (chamberY === -650) { //lower chamber @@ -7226,7 +7476,7 @@ const level = { }, rooftops() { level.announceMobTypes() - level.fallMode = "start"; + // level.fallPosition = { x: 5000, y:-4000} const elevator = level.elevator(1450, -990, 235, 45, -2000) const boost1 = level.boost(4950, 0, 1100) @@ -7267,6 +7517,9 @@ const level = { simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; + + + // level.fallMode = "start"; let isBackwards = false if (Math.random() < 0.75) { //normal direction start in top left @@ -7410,6 +7663,12 @@ const level = { } }; } + level.fallMode = "position"; //must set level.fallModeBounds in this mode to prevent player getting stuck left or right + if (level.enter.x > level.exit.x) { + level.fallModeBounds = { left: level.exit.x, right: level.enter.x } //used with level.fallMode = "position"; + } else { + level.fallModeBounds = { left: level.enter.x, right: level.exit.x } //used with level.fallMode = "position"; + } }, aerie() { level.announceMobTypes() @@ -10318,8 +10577,8 @@ const level = { }, vats() { // Made by Dablux#6610 on Discord simulation.inGameConsole(`vats by Dablux`); - - simulation.zoomScale = 1500; + level.defaultZoom = 1500 + simulation.zoomTransition(level.defaultZoom) level.setPosToSpawn(4400, -1060) spawn.mapRect(level.enter.x, level.enter.y + 30, 100, 20) level.exit.x = 3900; @@ -11481,8 +11740,8 @@ const level = { let isButtonTapped = false; // if (b.inventory.length < 5) powerUps.spawn(3800, -3200, "gun"); - powerUps.spawn(3900, -3100, "heal", true, null, 30); - powerUps.spawn(3900, -3100, "heal", true, null, 30); + powerUps.spawn(3900, -3100, "heal", true, 30); + powerUps.spawn(3900, -3100, "heal", true, 30); // path to the third room spawn.mapRect(2000, -1850, 50, 200); @@ -12445,7 +12704,7 @@ const level = { // applying forces to player doesn't seem to work inside this method, not sure why powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); - if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); + if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); }; me.damageReduction = 0.25 me.do = function () { @@ -12548,7 +12807,7 @@ const level = { me.onDeath = function () { powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); - if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); + if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); }; me.damageReduction = 0.25 me.do = function () { @@ -13380,8 +13639,8 @@ const level = { relocateWIMPs(level.exit.x, level.exit.y); relocateTo(50, -2050); simulation.fallHeight = -1000; - // simulation.setZoom(1800); - simulation.zoomTransition(1800) + level.defaultZoom = 1800 + simulation.zoomTransition(level.defaultZoom) templePlayer.startAnim = -1; templePlayer.drawExit = false; @@ -34012,7 +34271,7 @@ const level = { powerUps.addResearchToLevel() powerUps.directSpawn(-775, 125, "tech"); - powerUp[powerUp.length - 1].collisionFilter.mask = cat.map | cat.body | cat.powerUp + if (!level.isNextLevelPowerUps && powerUp[powerUp.length - 1]) powerUp[powerUp.length - 1].collisionFilter.mask = cat.map | cat.body | cat.powerUp spawn.bodyRect(-875, 75, 25, 100); let hardBody = body[body.length - 1]; hardBody.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.powerUp diff --git a/js/mob.js b/js/mob.js index 1c0d185..d4ecd86 100644 --- a/js/mob.js +++ b/js/mob.js @@ -794,27 +794,6 @@ const mobs = { } } }, - // invulnerability() { - // if (this.isInvulnerable) { - // if (this.invulnerabilityCountDown > 0) { - // this.invulnerabilityCountDown-- - // //graphics //draw a super shield? - // ctx.beginPath(); - // let vertices = this.vertices; - // ctx.moveTo(vertices[0].x, vertices[0].y); - // for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y); - // ctx.lineTo(vertices[0].x, vertices[0].y); - // ctx.lineWidth = 20; - // // ctx.fillStyle = `rgba(${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},0.5)` - // // ctx.fill(); - // ctx.strokeStyle = "rgba(255,255,255,0.4)"; - // ctx.stroke(); - // } else { - // this.isInvulnerable = false - // this.damageReduction = this.startingDamageReduction - // } - // } - // }, grow() { if (this.seePlayer.recall) { if (this.radius < 80) { @@ -926,10 +905,7 @@ const mobs = { spawn.bomb(this.position.x, this.position.y + this.radius * 0.7, 9 + Math.ceil(this.radius / 15), 5); //add spin and speed Matter.Body.setAngularVelocity(mob[mob.length - 1], (Math.random() - 0.5) * 0.5); - Matter.Body.setVelocity(mob[mob.length - 1], { - x: this.velocity.x, - y: this.velocity.y - }); + Matter.Body.setVelocity(mob[mob.length - 1], { x: this.velocity.x, y: this.velocity.y }); //spin for mob as well Matter.Body.setAngularVelocity(this, (Math.random() - 0.5) * 0.25); } @@ -1164,11 +1140,22 @@ const mobs = { // console.log(this.shieldCount) if (this.isDropPowerUp) { - // if (true) { - // //killing a mob heals for the last damage you took - - - // } + if (level.isMobDeathHeal) { + for (let i = 0; i < mob.length; i++) { + if (Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < 1000000 && mob[i].alive) { //1000 + if (mob[i].health < 1) { + mob[i].health = 1 + simulation.drawList.push({ + x: mob[i].position.x, + y: mob[i].position.y, + radius: mob[i].radius + 20, + color: "rgba(0,255,100,0.5)", + time: 10 + }); + } + } + } + } if (this.isSoonZombie) { //spawn zombie on death this.leaveBody = false; let count = 5 //delay spawn cycles @@ -1198,6 +1185,34 @@ const mobs = { }); } } + if (level.isMobRespawn && !this.isBoss && 0.33 > Math.random()) { + simulation.drawList.push({ + x: this.position.x, + y: this.position.y, + radius: 30, + color: `#fff`, + time: 20 + }); + simulation.drawList.push({ + x: this.position.x, + y: this.position.y, + radius: 20, + color: `#fff`, + time: 40 + }); + simulation.drawList.push({ + x: this.position.x, + y: this.position.y, + radius: 10, + color: `#fff`, + time: 60 + }); + setTimeout(() => { + const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; + const size = 16 + Math.ceil(Math.random() * 15) + spawn[pick](this.position.x, this.position.y, size); + }, 1000); + } if (tech.healSpawn && Math.random() < tech.healSpawn) { powerUps.spawn(this.position.x + 20 * (Math.random() - 0.5), this.position.y + 20 * (Math.random() - 0.5), "heal"); simulation.drawList.push({ @@ -1289,6 +1304,9 @@ const mobs = { tech.cloakDuplication -= 0.01 powerUps.setPowerUpMode(); //needed after adjusting duplication chance } + if (level.noDefenseSetting && this.isBoss) { + level.noDefenseSetting = 2 + } } else if (tech.isShieldAmmo && this.shield && this.shieldCount === 1) { let type = tech.isEnergyNoAmmo ? "heal" : "ammo" if (Math.random() < 0.4) { diff --git a/js/player.js b/js/player.js index f8f1b25..90fe921 100644 --- a/js/player.js +++ b/js/player.js @@ -97,6 +97,7 @@ const m = { hardLanding: 130, squirrelFx: 1, squirrelJump: 1, + velocitySmooth: { x: 0, y: 0 },//use for drawing skin's velocity gel tail standingOn: undefined, numTouching: 0, crouch: false, @@ -536,6 +537,10 @@ const m = { baseHealth: 1, setMaxHealth(isMessage) { m.maxHealth = m.baseHealth + tech.extraMaxHealth + 4 * tech.isFallingDamage + if (level.isReducedHealth) { + level.reducedHealthLost = Math.max(0, m.health - m.maxHealth * 0.5) + m.maxHealth *= 0.5 + } document.getElementById("health-bg").style.width = `${Math.floor(300 * m.maxHealth)}px` if (isMessage) simulation.inGameConsole(`m.maxHealth = ${m.maxHealth.toFixed(2)}`) if (m.health > m.maxHealth) m.health = m.maxHealth; @@ -546,6 +551,7 @@ const m = { lastCalculatedDamage: 0, //used to decided if damage bar needs to be redrawn (in simulation.checks) lastCalculatedDefense: 0, //used to decided if defense bar needs to be redrawn (in simulation.checks) defense() { + if (level.noDefenseSetting === 2) return 1 //zero defense constraint let dmg = 1 if (tech.isMaxHealthDefense && m.health === m.maxHealth) dmg *= 0.3 if (tech.isDiaphragm) dmg *= 0.55 + 0.35 * Math.sin(m.cycle * 0.0075); @@ -556,7 +562,7 @@ const m = { if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.973 ** m.coupling if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.3 if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1 - if (tech.isSpeedHarm && (tech.speedAdded + player.speed) > 0.1) dmg *= 1 - Math.min((tech.speedAdded + player.speed) * 0.0193, 0.8) //capped at speed of 55 + if (tech.isSpeedHarm && (tech.speedAdded + player.speed) > 0.1) dmg *= 1 - Math.min((tech.speedAdded + player.speed) * 0.01583, 0.95) //capped at speed of 55 if (tech.isHarmReduce && input.field) dmg *= 0.1 if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05 if (tech.isBotArmor) dmg *= 0.96 ** b.totalBots() @@ -778,6 +784,21 @@ const m = { simulation.fpsInterval = 1000 / simulation.fpsCap; } m.defaultFPSCycle = m.cycle + if (level.isMobHealPlayerDamage) { + for (let i = 0; i < mob.length; i++) { + if (mob[i].health < 1 && mob[i].isDropPowerUp && mob[i].alive) { + simulation.drawList.push({ + x: mob[i].position.x, + y: mob[i].position.y, + radius: mob[i].radius + 20, + color: "rgba(0,255,100,0.5)", + time: 10 + }); + mob[i].health += dmg * 10 + if (mob[i].health > 1) mob[i].health = 1 + } + } + } // if (tech.isSlowFPS) { // slow game // simulation.fpsCap = 30 //new fps // simulation.fpsInterval = 1000 / simulation.fpsCap; @@ -830,6 +851,9 @@ const m = { }, draw() { }, isAltSkin: false, + drawBoost() { + + }, resetSkin() { simulation.isAutoZoom = true; m.hardLandCDScale = 1 @@ -841,8 +865,8 @@ const m = { m.hardLanding = 130 m.squirrelFx = 1; m.squirrelJump = 1; + m.velocitySmooth = { x: 0, y: 0 } requestAnimationFrame(() => { m.setMovement() }) - m.color = { hue: 0, sat: 0, @@ -973,6 +997,30 @@ const m = { m.setMovement() m.draw = function () { + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) + ctx.beginPath(); + const radius = 39 + const mag = 14 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + + // const time = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + + ctx.fillStyle = `rgba(0,0,0,${0.04 + 0.3 * time})` + ctx.fill() + // ctx.strokeStyle = "#333" + // ctx.lineWidth = 1 + // ctx.stroke(); + ctx.restore(); + } + m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20) @@ -992,7 +1040,6 @@ const m = { ctx.stroke(); ctx.restore(); m.yOff = m.yOff * 0.75 + m.yOffGoal * 0.25; //smoothly move leg height towards height goal - powerUps.boost.draw() } m.drawLeg = function (stroke) { if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) { @@ -1150,8 +1197,38 @@ const m = { m.isAltSkin = true m.yOffWhen.stand = 52 m.yOffWhen.jump = 72 - + // m.speedSmooth = 0 + // m.smoothAngle = 0 m.draw = function () { + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) + ctx.beginPath(); + const radius = 40 + const mag = 9 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + + // const time = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + + // ctx.fillStyle = `rgba(255,0,200,${0.4 * time})` + // ctx.fill() + // ctx.strokeStyle = "#f09" + + ctx.fillStyle = `rgba(255,255,255,${0.3 + time})`; + ctx.fill() + ctx.strokeStyle = "#446" + ctx.lineWidth = 0.2 + 4 * time + // ctx.lineWidth = 1 + ctx.stroke(); + ctx.restore(); + } + m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20) @@ -1161,7 +1238,6 @@ const m = { m.calcLeg(0, 0); m.drawLeg("#446"); - ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); @@ -1175,6 +1251,15 @@ const m = { ctx.lineWidth = 2; ctx.stroke(); + //fire outline directed opposite player look direction + // ctx.beginPath(); + // const radius = 40 + // const extend = -50 + // ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + // ctx.bezierCurveTo(extend, radius, extend, 0, -100, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + // ctx.bezierCurveTo(extend, 0, extend, -radius, 0, -radius); + // ctx.fillStyle = "rgba(255,0,255,0.3)"; + // ctx.fill() ctx.beginPath(); ctx.moveTo(13, 0) ctx.lineTo(20, 0) @@ -1183,7 +1268,6 @@ const m = { ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() } m.drawLeg = function (stroke) { // if (simulation.mouseInGame.x > m.pos.x) { @@ -1242,6 +1326,30 @@ const m = { } m.setFillColors(); m.draw = function () { + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) + ctx.beginPath(); + const radius = 40 + const mag = 10 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + + // const time = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + + ctx.fillStyle = `hsla(184,100%,70%,${0.1 + 1.5 * time})` + ctx.fill() + ctx.strokeStyle = "#035"//"hsl(184,100%,70%)" + ctx.lineWidth = 0.2 + 3 * time + ctx.stroke(); + ctx.restore(); + } + ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); @@ -1254,8 +1362,8 @@ const m = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.strokeStyle = "rgba(0,255,255,0.22)"; - ctx.lineWidth = 12; + ctx.strokeStyle = "rgba(0,255,255,0.25)"; + ctx.lineWidth = 15; ctx.stroke(); ctx.fillStyle = 'hsl(184,100%,85%)' //m.fillColor; //"#9ff" //m.bodyGradient ctx.fill(); @@ -1264,10 +1372,9 @@ const m = { ctx.arc(17, 0, 5.5, 0, 2 * Math.PI); ctx.fillStyle = "#357" ctx.fill(); - ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() } m.drawLeg = function (stroke) { // if (simulation.mouseInGame.x > m.pos.x) { @@ -1466,6 +1573,26 @@ const m = { m.bodyGradient = grd m.draw = function () { + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) + ctx.beginPath(); + const radius = 40 + const mag = 12 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + // const time = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + + ctx.fillStyle = `hsla(${simulation.cycle},100%,70%,${0.1 + 2 * time})` + ctx.fill() + ctx.restore(); + } + ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); @@ -1486,7 +1613,6 @@ const m = { // ctx.stroke(); ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() } m.drawLeg = function (stroke) { // if (simulation.mouseInGame.x > m.pos.x) { @@ -1571,11 +1697,31 @@ const m = { ctx.stroke(); ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() + + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) + ctx.beginPath(); + const radius = 39 + const mag = 6 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + // ctx.fillStyle = `hsla(${simulation.cycle * 0.5},100%,70%,0.4)` + // ctx.fill() + ctx.strokeStyle = "#345" + // const time = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + + ctx.lineWidth = 0.2 + 4 * time + ctx.stroke(); + ctx.restore(); + } //zoom camera in and out - - // console.log(simulation.zoomScale) simulation.setZoom(1800 + 400 * Math.sin(m.cycle * 0.01)) } }, @@ -1611,7 +1757,30 @@ const m = { // ctx.stroke(); ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() + + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) + ctx.beginPath(); + const radius = 39 + const mag = 6 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + // ctx.fillStyle = `hsla(${simulation.cycle * 0.5},100%,70%,0.4)` + // ctx.fill() + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + + ctx.strokeStyle = "#345" + ctx.lineWidth = 0.2 + 7 * time + // ctx.lineWidth = (4 + 3 * Math.sin(m.cycle * 0.01 + Math.PI)) * time; + ctx.stroke(); + ctx.restore(); + } + simulation.setZoom(1800 + 400 * amplitude) } m.drawLeg = function (stroke) { @@ -1672,7 +1841,6 @@ const m = { grd.addColorStop(1, m.fillColor); // grd.addColorStop(1, m.fillColor); m.bodyGradient = grd - m.draw = function () { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; @@ -1748,7 +1916,6 @@ const m = { }, verlet() { m.isAltSkin = true - m.draw = function () { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; @@ -1764,7 +1931,6 @@ const m = { ctx.arc(0, 0, 30, 0, 2 * Math.PI); ctx.fillStyle = m.bodyGradient ctx.fill(); - const rate = 0.09 ctx.strokeStyle = "#000"; ctx.lineWidth = 1; @@ -1832,6 +1998,264 @@ const m = { ctx.restore(); } }, + stubs() { + m.isAltSkin = true + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20) + ctx.translate(m.pos.x, m.pos.y); + m.calcLeg(Math.PI, -3); + m.drawLeg("#555"); + m.calcLeg(0, 0); + m.drawLeg("#333"); + ctx.rotate(m.angle); + ctx.beginPath(); + ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.arc(15, 0, 4, 0, 2 * Math.PI); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 2; + ctx.stroke(); + ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() + } + m.drawLeg = function (stroke) { + // if (simulation.mouseInGame.x > m.pos.x) { + if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) { + m.flipLegs = 1; + } else { + m.flipLegs = -1; + } + ctx.save(); + ctx.scale(m.flipLegs, 1); //leg lines + ctx.beginPath(); + ctx.moveTo(m.hip.x, m.hip.y); + ctx.lineTo(m.knee.x, m.knee.y); + ctx.lineTo(m.foot.x, m.foot.y + 5); + ctx.strokeStyle = stroke; + ctx.lineWidth = 6; + ctx.stroke(); + ctx.restore(); + } + }, + Sleipnir() { + m.isAltSkin = true + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 + ctx.translate(m.pos.x, m.pos.y); + for (let i = 0; i < 16; i++) { + m.calcLeg(Math.PI * i / 8, -3 * i / 16) + m.drawLeg("#444") + } + ctx.rotate(m.angle); + ctx.beginPath(); + ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.arc(15, 0, 4, 0, 2 * Math.PI); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 2; + ctx.stroke(); + ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() + } + }, + diegesis() { + m.isAltSkin = true + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 + ctx.translate(m.pos.x, m.pos.y); + m.calcLeg(Math.PI, -3); + m.drawLeg("#4a4a4a"); + m.calcLeg(0, 0); + m.drawLeg("#333"); + ctx.rotate(m.angle - (m.fireCDcycle !== Infinity ? m.flipLegs * 0.25 * Math.pow(Math.max(m.fireCDcycle - m.cycle, 0), 0.5) : 0)); + + ctx.beginPath(); + ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.arc(15, 0, 4, 0, 2 * Math.PI); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 2; + ctx.stroke(); + ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() + } + }, + cat() { + m.isAltSkin = true + m.coyoteCycles = 10 + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 + ctx.translate(m.pos.x, m.pos.y); + m.calcLeg(Math.PI, -3); + m.drawLeg("#4a4a4a"); + if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) { + ctx.scale(1, -1); + ctx.rotate(Math.PI); + } + ctx.beginPath(); + ctx.moveTo(-30, 0); + ctx.bezierCurveTo(-65, -75, + -5, 150 + (5 * Math.sin(simulation.cycle / 10)), + -70 + (10 * Math.sin(simulation.cycle / 10)), 0 + (10 * Math.sin(simulation.cycle / 10))); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 4; + ctx.stroke(); + + if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) { + ctx.scale(1, -1); + ctx.rotate(0 - Math.PI); + } + m.calcLeg(0, 0); + m.drawLeg("#333"); + + ctx.rotate(m.angle); + if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1); + ctx.beginPath(); + ctx.moveTo(5, -30); + ctx.lineTo(20, -40); + ctx.lineTo(20, -20); + ctx.lineWidth = 2; + ctx.fillStyle = "#f3f"; + ctx.fill(); + ctx.stroke(); + + ctx.beginPath(); + ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.stroke(); + ctx.moveTo(19, 0); + ctx.arc(15, 0, 4, Math.PI, 2 * Math.PI); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(24.3, 6, 5, Math.PI * 2, Math.PI); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(30, 6); + ctx.lineTo(32, 0); + ctx.lineTo(26, 0); + ctx.lineTo(30, 6); + ctx.fillStyle = "#f3f"; + ctx.fill(); + ctx.stroke(); + + ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() + } + }, + pareidolia() { + m.isAltSkin = true + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.7 + ctx.translate(m.pos.x, m.pos.y); + m.calcLeg(Math.PI, -3); + m.drawLeg("#4a4a4a"); + m.calcLeg(0, 0); + m.drawLeg("#333"); + ctx.rotate(m.angle); + ctx.beginPath(); + ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 2; + if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1); //here is the flip + ctx.stroke(); + ctx.beginPath(); + ctx.arc(2, -6, 7, 0, 2 * Math.PI); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(25, -6, 7, 0.25 * Math.PI, 1.6 * Math.PI); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(2, -10, 9, 1.25 * Math.PI, 1.75 * Math.PI); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(25, -10, 9, 1.25 * Math.PI, 1.4 * Math.PI); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(18, 13, 10, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient; + ctx.fill(); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(18, 13, 6, 0, 2 * Math.PI); + ctx.fillStyle = "#555"; + ctx.fill(); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(3, -6, 3, 0, 2 * Math.PI); + ctx.fill(); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(26, -6, 3, 0, 2 * Math.PI); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; + powerUps.boost.draw() + } + }, + flipFlop() { + m.isAltSkin = true + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + + //draw body + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 + ctx.translate(m.pos.x, m.pos.y); + + m.calcLeg(Math.PI, -3); + m.drawLeg("#4a4a4a"); + m.calcLeg(0, 0); + m.drawLeg("#333"); + + ctx.rotate(m.angle); + ctx.beginPath(); + ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.arc(15, 0, 4, 0, 2 * Math.PI); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 2; + ctx.stroke(); + //draw eye + ctx.beginPath(); + ctx.arc(15, 0, 3.5, 0, 2 * Math.PI); + ctx.fillStyle = m.eyeFillColor; + ctx.fill() + ctx.restore(); + + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() + } + }, hexagon() { m.isAltSkin = true @@ -1922,262 +2346,6 @@ const m = { ctx.restore(); } }, - stubs() { - m.isAltSkin = true - m.draw = function () { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; - ctx.save(); - ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20) - ctx.translate(m.pos.x, m.pos.y); - m.calcLeg(Math.PI, -3); - m.drawLeg("#555"); - m.calcLeg(0, 0); - m.drawLeg("#333"); - ctx.rotate(m.angle); - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient - ctx.fill(); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 2; - ctx.stroke(); - ctx.restore(); - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() - } - m.drawLeg = function (stroke) { - // if (simulation.mouseInGame.x > m.pos.x) { - if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) { - m.flipLegs = 1; - } else { - m.flipLegs = -1; - } - ctx.save(); - ctx.scale(m.flipLegs, 1); //leg lines - ctx.beginPath(); - ctx.moveTo(m.hip.x, m.hip.y); - ctx.lineTo(m.knee.x, m.knee.y); - ctx.lineTo(m.foot.x, m.foot.y + 5); - ctx.strokeStyle = stroke; - ctx.lineWidth = 6; - ctx.stroke(); - ctx.restore(); - } - }, - Sleipnir() { - m.isAltSkin = true - m.draw = function () { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; - ctx.save(); - ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 - ctx.translate(m.pos.x, m.pos.y); - for (let i = 0; i < 16; i++) { - m.calcLeg(Math.PI * i / 8, -3 * i / 16) - m.drawLeg("#444") - } - ctx.rotate(m.angle); - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient - ctx.fill(); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 2; - ctx.stroke(); - ctx.restore(); - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - } - }, - diegesis() { - m.isAltSkin = true - m.draw = function () { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; - - ctx.save(); - ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 - ctx.translate(m.pos.x, m.pos.y); - m.calcLeg(Math.PI, -3); - m.drawLeg("#4a4a4a"); - m.calcLeg(0, 0); - m.drawLeg("#333"); - ctx.rotate(m.angle - (m.fireCDcycle !== Infinity ? m.flipLegs * 0.25 * Math.pow(Math.max(m.fireCDcycle - m.cycle, 0), 0.5) : 0)); - - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient - ctx.fill(); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 2; - ctx.stroke(); - ctx.restore(); - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - } - }, - cat() { - m.isAltSkin = true - m.coyoteCycles = 10 - m.draw = function () { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; - ctx.save(); - ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 - ctx.translate(m.pos.x, m.pos.y); - m.calcLeg(Math.PI, -3); - m.drawLeg("#4a4a4a"); - - - if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) { - ctx.scale(1, -1); - ctx.rotate(Math.PI); - } - ctx.beginPath(); - ctx.moveTo(-30, 0); - ctx.bezierCurveTo(-65, -75, - -5, 150 + (5 * Math.sin(simulation.cycle / 10)), - -70 + (10 * Math.sin(simulation.cycle / 10)), 0 + (10 * Math.sin(simulation.cycle / 10))); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 4; - ctx.stroke(); - - if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) { - ctx.scale(1, -1); - ctx.rotate(0 - Math.PI); - } - m.calcLeg(0, 0); - m.drawLeg("#333"); - - ctx.rotate(m.angle); - if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1); - ctx.beginPath(); - ctx.moveTo(5, -30); - ctx.lineTo(20, -40); - ctx.lineTo(20, -20); - ctx.lineWidth = 2; - ctx.fillStyle = "#f3f"; - ctx.fill(); - ctx.stroke(); - - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient - ctx.fill(); - ctx.stroke(); - ctx.moveTo(19, 0); - ctx.arc(15, 0, 4, Math.PI, 2 * Math.PI); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(24.3, 6, 5, Math.PI * 2, Math.PI); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(30, 6); - ctx.lineTo(32, 0); - ctx.lineTo(26, 0); - ctx.lineTo(30, 6); - ctx.fillStyle = "#f3f"; - ctx.fill(); - ctx.stroke(); - - ctx.restore(); - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - } - }, - pareidolia() { - m.isAltSkin = true - m.draw = function () { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; - ctx.save(); - ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.7 - ctx.translate(m.pos.x, m.pos.y); - m.calcLeg(Math.PI, -3); - m.drawLeg("#4a4a4a"); - m.calcLeg(0, 0); - m.drawLeg("#333"); - ctx.rotate(m.angle); - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient - ctx.fill(); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 2; - if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1); //here is the flip - ctx.stroke(); - ctx.beginPath(); - ctx.arc(2, -6, 7, 0, 2 * Math.PI); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(25, -6, 7, 0.25 * Math.PI, 1.6 * Math.PI); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(2, -10, 9, 1.25 * Math.PI, 1.75 * Math.PI); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(25, -10, 9, 1.25 * Math.PI, 1.4 * Math.PI); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(18, 13, 10, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient; - ctx.fill(); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(18, 13, 6, 0, 2 * Math.PI); - ctx.fillStyle = "#555"; - ctx.fill(); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(3, -6, 3, 0, 2 * Math.PI); - ctx.fill(); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(26, -6, 3, 0, 2 * Math.PI); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; - } - }, - flipFlop() { - m.isAltSkin = true - m.draw = function () { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; - - //draw body - ctx.save(); - ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 - ctx.translate(m.pos.x, m.pos.y); - - m.calcLeg(Math.PI, -3); - m.drawLeg("#4a4a4a"); - m.calcLeg(0, 0); - m.drawLeg("#333"); - - ctx.rotate(m.angle); - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = m.bodyGradient - ctx.fill(); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 2; - ctx.stroke(); - //draw eye - ctx.beginPath(); - ctx.arc(15, 0, 3.5, 0, 2 * Math.PI); - ctx.fillStyle = m.eyeFillColor; - ctx.fill() - ctx.restore(); - - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - powerUps.boost.draw() - } - } }, // ********************************************* // **************** fields ********************* @@ -2275,6 +2443,7 @@ const m = { }, setMaxEnergy(isMessage = true) { m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 3 * tech.isGroundState + 1.5 * (m.fieldMode === 1) + (m.fieldMode === 0 || m.fieldMode === 1) * 0.05 * m.coupling + 0.77 * tech.isStandingWaveExpand + if (level.isReducedEnergy) m.maxEnergy *= 0.5 if (isMessage) simulation.inGameConsole(`m.maxEnergy = ${(m.maxEnergy.toFixed(2))}`) }, fieldMeterColor: "#0cf", @@ -2542,7 +2711,7 @@ const m = { tech.tokamakHealCount++ let massScale = Math.min(65 * Math.sqrt(m.maxHealth), 14 * Math.pow(m.holdingTarget.mass, 0.4)) if (powerUps.healGiveMaxEnergy) massScale = powerUps["heal"].size() - powerUps.spawn(m.pos.x, m.pos.y, "heal", true, null, massScale * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1))) // spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { + powerUps.spawn(m.pos.x, m.pos.y, "heal", true, massScale * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1))) // spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { } } else { //normal throw //bullet-like collisions @@ -2587,6 +2756,7 @@ const m = { }); m.definePlayerMass() //return to normal player mass + if (tech.isStaticBlock) m.holdingTarget.isStatic = true if (tech.isAddBlockMass) { const expand = function (that, massLimit) { if (that.mass < massLimit) { @@ -3000,7 +3170,7 @@ const m = { case 9: //wormhole return `after eating blocks +${(2 * couple).toFixed(0)} energy` case 10: //grappling hook - return `${powerUps.orb.ammo(1)} give ${(4 * couple).toFixed(0)}% more ammo` + return `${powerUps.orb.ammo(1)} give ${(4 * couple).toFixed(0)}% more ammo` } }, couplingChange(change = 0) { diff --git a/js/powerup.js b/js/powerup.js index d855d8d..3bc1718 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -373,7 +373,7 @@ const powerUps = { //build level info document.getElementById("choose-grid").classList.add('choose-grid-no-images'); document.getElementById("choose-grid").classList.remove('choose-grid'); - document.getElementById("choose-grid").style.gridTemplateColumns = "405px" //adjust this to increase the width of the whole menu, but mostly the center column + document.getElementById("choose-grid").style.gridTemplateColumns = "505px" //adjust this to increase the width of the whole menu, but mostly the center column let text = `
@@ -389,12 +389,12 @@ const powerUps = {
-
0.87x damage done per level
1.22x damage taken per level
-
-5 initial power ups
faster mobs and more mobs
-
0.87x damage done per level
1.22x damage taken per level
-
+1 boss per level
-1 ${powerUps.orb.tech()} per boss
-
0.87x damage done per level
1.22x damage taken per level
-
3x chance for shielded mobs
-3 initial power ups
+
0.87x damage, 1.22x damage taken per level
+1 boss on each level
+
more mob per level
faster mobs per level
+
0.87x damage, 1.22x damage taken per level
+1 random constraint on each level
+
+1 boss on each level
bosses spawn 1 fewer ${powerUps.orb.tech()}
+
0.87x damage, 1.22x damage taken per level
+1 random constraint on each level
+
0.5x initial damage
2x initial damage taken
${localSettings.difficultyCompleted[1] ? "⚆" : " "}
@@ -434,7 +434,7 @@ const powerUps = { } }); - let setConstraintText = function (isReset = true) { + let setDifficultyText = function (isReset = true) { for (let i = 1; i < 7; i++) { const id = document.getElementById("constraint-" + i) if (simulation.difficultyMode < i) { @@ -451,17 +451,19 @@ const powerUps = { if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } } - setConstraintText(false) + setDifficultyText(false) document.getElementById("difficulty-slider").value = simulation.difficultyMode document.getElementById("difficulty-slider").addEventListener("input", () => { simulation.difficultyMode = document.getElementById("difficulty-slider").value - setConstraintText() + setDifficultyText() + level.setConstraints() }); for (let i = 1; i < 7; i++) { document.getElementById("constraint-" + i).addEventListener("click", () => { simulation.difficultyMode = i document.getElementById("difficulty-slider").value = simulation.difficultyMode - setConstraintText() + setDifficultyText() + level.setConstraints() }); } }, @@ -503,17 +505,38 @@ const powerUps = { damage: null, //set by "tech: band gap" effect() { powerUps.animatePowerUpGrab('rgba(255, 0, 0, 0.5)') - powerUps.boost.endCycle = m.cycle + Math.floor(Math.max(0, powerUps.boost.endCycle - m.cycle) * 0.6) + powerUps.boost.duration //duration+seconds plus 2/3 of current time left + powerUps.boost.endCycle = simulation.cycle + Math.floor(Math.max(0, powerUps.boost.endCycle - simulation.cycle) * 0.6) + powerUps.boost.duration //duration+seconds plus 2/3 of current time left }, draw() { // console.log(this.endCycle) - if (powerUps.boost.endCycle > m.cycle) { - ctx.strokeStyle = "rgba(255,0,0,0.8)" //m.fieldMeterColor; //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + // if (powerUps.boost.endCycle > m.cycle) { + // ctx.strokeStyle = "rgba(255,0,0,0.8)" //m.fieldMeterColor; //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + // ctx.beginPath(); + // const arc = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + // ctx.arc(m.pos.x, m.pos.y, 28, m.angle - Math.PI * arc, m.angle + Math.PI * arc); //- Math.PI / 2 + // ctx.lineWidth = 4 + // ctx.stroke(); + // } + + if (powerUps.boost.endCycle > simulation.cycle) { + //gel that acts as if the wind is blowing it when player moves + ctx.save(); + ctx.translate(m.pos.x, m.pos.y); + m.velocitySmooth = Vector.add(Vector.mult(m.velocitySmooth, 0.8), Vector.mult(player.velocity, 0.2)) + ctx.rotate(Math.atan2(m.velocitySmooth.y, m.velocitySmooth.x)) ctx.beginPath(); - const arc = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration - ctx.arc(m.pos.x, m.pos.y, 28, m.angle - Math.PI * arc, m.angle + Math.PI * arc); //- Math.PI / 2 - ctx.lineWidth = 4 + const radius = 40 + const mag = 8 * Vector.magnitude(m.velocitySmooth) + radius + ctx.arc(0, 0, radius, -Math.PI / 2, Math.PI / 2); + ctx.bezierCurveTo(-radius, radius, -radius, 0, -mag, 0); // bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) + ctx.bezierCurveTo(-radius, 0, -radius, -radius, 0, -radius); + const time = Math.min(0.5, (powerUps.boost.endCycle - simulation.cycle) / powerUps.boost.duration) + ctx.fillStyle = `rgba(255,0,200,${time})` + ctx.fill() + ctx.strokeStyle = "#f09" + ctx.lineWidth = 0.3 + 4 * time ctx.stroke(); + ctx.restore(); } }, }, @@ -533,7 +556,7 @@ const powerUps = { if (amount !== 0) powerUps.research.count += amount if (tech.isRerollBots && !this.isMakingBots) { let cycle = () => { - const cost = 2 + Math.floor(0.2 * b.totalBots()) + const cost = 2 + Math.floor(0.25 * b.totalBots()) if (m.alive && powerUps.research.count >= cost) { requestAnimationFrame(cycle); this.isMakingBots = true @@ -647,7 +670,7 @@ const powerUps = { // }); } else if (overHeal > 0.13) { //if leftover heals spawn a new spammer heal power up requestAnimationFrame(() => { - powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, Math.min(1, overHeal) * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { + powerUps.directSpawn(this.position.x, this.position.y, "heal", true, Math.min(1, overHeal) * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, name, moving = true, mode = null, size = powerUps[name].size()) { }); } if (tech.isHealBrake) { @@ -699,9 +722,9 @@ const powerUps = { } }, spawn(x, y, size) { //used to spawn a heal with a specific size / heal amount, not normally used - powerUps.directSpawn(x, y, "heal", false, null, size) - if (Math.random() < tech.duplicationChance()) { - powerUps.directSpawn(x, y, "heal", false, null, size) + powerUps.directSpawn(x, y, "heal", false, size) + if (!level.isNextLevelPowerUps && Math.random() < tech.duplicationChance()) { + powerUps.directSpawn(x, y, "heal", false, size) powerUp[powerUp.length - 1].isDuplicated = true } } @@ -717,22 +740,22 @@ const powerUps = { if (b.inventory.length > 0) { powerUps.animatePowerUpGrab('rgba(68, 102, 119,0.25)') if (tech.isAmmoForGun && b.activeGun !== null) { //give extra ammo to one gun only with tech logistics - const target = b.guns[b.activeGun] - if (target.ammo !== Infinity) { + const name = b.guns[b.activeGun] + if (name.ammo !== Infinity) { if (tech.ammoCap) { - target.ammo = Math.ceil(2 * target.ammoPack * tech.ammoCap * couplingExtraAmmo) + name.ammo = Math.ceil(2 * name.ammoPack * tech.ammoCap * couplingExtraAmmo) } else { - target.ammo += Math.ceil(2 * (Math.random() + Math.random()) * target.ammoPack * couplingExtraAmmo) + name.ammo += Math.ceil(2 * (Math.random() + Math.random()) * name.ammoPack * couplingExtraAmmo) } } } else { //give ammo to all guns in inventory for (let i = 0, len = b.inventory.length; i < len; i++) { - const target = b.guns[b.inventory[i]] - if (target.ammo !== Infinity) { + const name = b.guns[b.inventory[i]] + if (name.ammo !== Infinity) { if (tech.ammoCap) { - target.ammo = Math.ceil(target.ammoPack * tech.ammoCap * couplingExtraAmmo) + name.ammo = Math.ceil(name.ammoPack * tech.ammoCap * couplingExtraAmmo) } else { //default ammo behavior - target.ammo += Math.ceil((Math.random() + Math.random()) * target.ammoPack * couplingExtraAmmo) + name.ammo += Math.ceil((Math.random() + Math.random()) * name.ammoPack * couplingExtraAmmo) } } } @@ -844,9 +867,9 @@ const powerUps = { gunText(choose, click) { const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/gun/${b.guns[choose].name}.webp');"` return `
-
-
  ${b.guns[choose].name}
- ${b.guns[choose].descriptionFunction()}
` +
+
  ${b.guns[choose].name}
+ ${b.guns[choose].descriptionFunction()}
` }, fieldText(choose, click) { const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/field/${m.fieldUpgrades[choose].name}${choose === 0 ? Math.floor(Math.random() * 10) : ""}.webp');"` @@ -1034,13 +1057,13 @@ const powerUps = { } // console.log(options.length) if (options.length > 0 || !tech.isSuperDeterminism) { - let totalChoices = 2 + tech.extraChoices + 3 * (m.fieldMode === 8) + let totalChoices = 2 + tech.extraChoices + 3 * (m.fieldMode === 8) - level.fewerChoices if (tech.isCancelTech && tech.cancelTechCount === 1) { totalChoices *= 3 tech.cancelTechCount++ } if (tech.isDeterminism) totalChoices = 1 - totalChoices = Math.min(options.length, totalChoices) + totalChoices = Math.min(totalChoices, options.length) function removeOption(index) { for (let i = 0; i < options.length; i++) { if (options[i] === index) { @@ -1101,13 +1124,13 @@ const powerUps = { for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter if (i !== m.fieldMode) options.push(i); } - let totalChoices = 2 + tech.extraChoices + 3 * (m.fieldMode === 8) + let totalChoices = 2 + tech.extraChoices + 3 * (m.fieldMode === 8) - level.fewerChoices if (tech.isCancelTech && tech.cancelTechCount === 1) { totalChoices *= 3 tech.cancelTechCount++ } if (tech.isDeterminism) totalChoices = 1 - totalChoices = Math.min(options.length, totalChoices) + totalChoices = Math.max(1, Math.min(totalChoices, options.length)) function removeOption(index) { for (let i = 0; i < options.length; i++) { if (options[i] === index) { @@ -1181,13 +1204,13 @@ const powerUps = { } } //set total choices - let totalChoices = 3 + tech.extraChoices + 3 * (m.fieldMode === 8) + let totalChoices = 3 + tech.extraChoices + 3 * (m.fieldMode === 8) - level.fewerChoices if (tech.isCancelTech && tech.cancelTechCount === 1) { totalChoices *= 3 tech.cancelTechCount++ } if (tech.isDeterminism) totalChoices = 1 - totalChoices = Math.min(options.length, totalChoices) + totalChoices = Math.max(1, Math.min(totalChoices, options.length)) if (optionLengthNoDuplicates < totalChoices + 1) { //if not enough options for all the choices totalChoices = optionLengthNoDuplicates @@ -1220,11 +1243,11 @@ const powerUps = { const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options if (tech.isBanish) { tech.tech[choose].isBanished = true - if (i === 0) simulation.inGameConsole(`options.length = ${optionLengthNoDuplicates} //tech removed from pool by decoherence`) + if (i === 0) simulation.inGameConsole(`options.length = ${optionLengthNoDuplicates} //removed from pool by decoherence`) } removeOption(choose) //move from future options pool to avoid repeats on this selection tech.tech[choose].isRecentlyShown = true //this flag prevents this option from being shown the next time you pick up a tech power up - if (Math.random() < tech.junkChance) { // choose is set to a random JUNK tech + if (Math.random() < tech.junkChance + level.junkAdded) { // choose is set to a random JUNK tech const list = [] for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].isJunk) list.push(i) @@ -1433,6 +1456,7 @@ const powerUps = { b.mine(who.position, { x: 0, y: 0 }, 0) } } + if (level.isNoDamage) level.noDamageCycle = m.cycle }, spawnRandomPowerUp(x, y) { //mostly used after mob dies, doesn't always return a power up if (!tech.isEnergyHealth && (Math.random() * Math.random() - 0.3 > Math.sqrt(m.health)) || Math.random() < 0.04) { //spawn heal chance is higher at low health @@ -1447,10 +1471,6 @@ const powerUps = { powerUps.spawn(x, y, "gun"); return; } - // if (Math.random() < 0.005 * (10 - level.levelsCleared)) { //a new tech has a low chance that decreases in later levels - // powerUps.spawn(x, y, "tech"); - // return; - // } if (Math.random() < 0.0016) { powerUps.spawn(x, y, "field"); return; @@ -1459,35 +1479,28 @@ const powerUps = { powerUps.spawn(x, y, "coupling"); return; } - if (tech.isBoostPowerUps && Math.random() < 0.14) { + if (Math.random() < 0.02 || (tech.isBoostPowerUps && Math.random() < 0.14)) { powerUps.spawn(x, y, "boost"); return; } - // if (Math.random() < 0.01) { - // powerUps.spawn(x, y, "research"); - // return; - // } }, randomPowerUpCounter: 0, isFieldSpawned: false, //makes it so a field spawns once but not more times spawnBossPowerUp(x, y) { //boss spawns field and gun tech upgrades if (level.levels[level.onLevel] !== "final") { - // if (level.levelsCleared === 1) powerUps.spawn(x, y, "field") - // if (m.fieldMode === 0 && !m.coupling) { if (!powerUps.isFieldSpawned) { powerUps.isFieldSpawned = true powerUps.spawn(x, y, "field") } else { - powerUps.randomPowerUpCounter++; - powerUpChance(Math.max(level.levelsCleared, 10) * 0.1) + powerUpChance() } - if (!(simulation.difficultyMode > 2 && level.levelsCleared > 1)) { - powerUps.randomPowerUpCounter += 0.6; - powerUpChance(Math.max(level.levelsCleared, 6) * 0.1) + if (simulation.difficultyMode < 4) {//don't spawn second power up on difficulties with a second boss + powerUpChance() } - function powerUpChance(chanceToFail) { - if (Math.random() * chanceToFail < powerUps.randomPowerUpCounter) { - powerUps.randomPowerUpCounter = 0; + function powerUpChance() { + powerUps.randomPowerUpCounter++ + if (powerUps.randomPowerUpCounter > Math.max(level.levelsCleared, 9) * 0.1 * Math.random()) { + powerUps.randomPowerUpCounter = 0; //reset odds if (Math.random() < 0.97) { powerUps.spawn(x, y, "tech") } else { @@ -1528,14 +1541,14 @@ const powerUps = { }, addResearchToLevel() { //add a random power up to a location that has a mob, mostly used to give each level a research // if (simulation.difficultyMode < 4 && mob.length) { //don't spawn on higher difficulty settings - if (level.levelsCleared < 13 - simulation.difficultyMode * 2 && mob.length) { //don't spawn late game + if ((level.levelsCleared < 17 - simulation.difficultyMode * 3) && mob.length) { //don't spawn late game const index = Math.floor(Math.random() * mob.length) powerUps.spawn(mob[index].position.x, mob[index].position.y, "research"); } }, spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun if (level.levelsCleared < 4) { //runs on first 4 levels on all difficulties - if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech") + if (level.levelsCleared > 1 && simulation.difficultyMode < 6) powerUps.spawn(x, y, "tech") if (b.inventory.length === 0) { powerUps.spawn(x, y, "gun", false); //first gun } else if (tech.totalCount === 0) { //first tech @@ -1574,7 +1587,6 @@ const powerUps = { for (let i = 0; i < tech.tech[choose].count; i++) { powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); - // powerUp[powerUp.length - 1].isDuplicated = true } // remove a random tech from the list of tech you have tech.removeCount += tech.tech[choose].count @@ -1593,7 +1605,6 @@ const powerUps = { for (let i = 0; i < tech.tech[choose].count; i++) { powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); - // powerUp[powerUp.length - 1].isDuplicated = true } // remove a random tech from the list of tech you have tech.tech[choose].remove(); @@ -1675,7 +1686,28 @@ const powerUps = { powerUp.splice(index, 1); } }, - directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size(), isDuplicated = false) { + spawn(x, y, name, moving = true, size = powerUps[name].size()) { + if ( + (!tech.isSuperDeterminism || (name !== 'research')) && + !(tech.isEnergyNoAmmo && name === 'ammo') + ) { + if (tech.isBoostReplaceAmmo && name === 'ammo') { + name = 'boost' + size = powerUps[name].size() + } + powerUps.directSpawn(x, y, name, moving, size) + if (!level.isNextLevelPowerUps && Math.random() < tech.duplicationChance()) { + powerUps.directSpawn(x, y, name, moving, size, true) + powerUp[powerUp.length - 1].isDuplicated = true + if (tech.isDupEnergy) m.energy *= 2 + } + } + }, + directSpawn(x, y, name, moving = true, size = powerUps[name].size(), isDuplicated = false) { + if (level.isNextLevelPowerUps) { + powerUps.powerUpStorage.push({ name: name, size: size }) + return + } let index = powerUp.length; let properties = { density: 0.001, @@ -1686,9 +1718,9 @@ const powerUps = { category: cat.powerUp, mask: cat.map | cat.powerUp }, - color: powerUps[target].color, - effect: powerUps[target].effect, - name: powerUps[target].name, + color: powerUps[name].color, + effect: powerUps[name].effect, + name: powerUps[name].name, size: size } let polygonSides @@ -1700,26 +1732,8 @@ const powerUps = { polygonSides = 12 } powerUp[index] = Matter.Bodies.polygon(x, y, polygonSides, size, properties); - if (mode) powerUp[index].mode = mode if (moving) Matter.Body.setVelocity(powerUp[index], { x: (Math.random() - 0.5) * 15, y: Math.random() * -9 - 3 }); Composite.add(engine.world, powerUp[index]); }, - spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { - if ( - (!tech.isSuperDeterminism || (target !== 'research')) && - !(tech.isEnergyNoAmmo && target === 'ammo') - ) { - if (tech.isBoostReplaceAmmo && target === 'ammo') { - target = 'boost' - size = powerUps[target].size() - } - powerUps.directSpawn(x, y, target, moving, mode, size) - if (Math.random() < tech.duplicationChance()) { - powerUps.directSpawn(x, y, target, moving, mode, size, true) - powerUp[powerUp.length - 1].isDuplicated = true - // if (tech.isPowerUpsVanish) powerUp[powerUp.length - 1].endCycle = simulation.cycle + 300 - if (tech.isDupEnergy) m.energy *= 2 - } - } - }, + powerUpStorage: [],//used when power ups are sent to the next level (for the constraint, level.isNextLevelPowerUps) }; \ No newline at end of file diff --git a/js/simulation.js b/js/simulation.js index 72eb1c7..c991fab 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -419,15 +419,6 @@ const simulation = { simulation.boldActiveGunHUD(); }, updateTechHUD() { - - // tech.tech.sort((a, b) => { - // console.log(a.cycle, b.cycle) - // if (a.cycle === undefined && b.cycle !== undefined) return -1; - // if (a.cycle !== undefined && b.cycle === undefined) return 1; - // if (a.cycle === undefined && b.cycle === undefined) return 0; - // if (a.cycle !== b.cycle) return a.cycle - b.cycle; - // }); - let text = "" for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech if (tech.tech[i].isLost) { @@ -436,21 +427,55 @@ const simulation = { } else if (tech.tech[i].count > 0 && !tech.tech[i].isInstant) { if (text) text += "
" //add a new line, but not on the first line text += tech.tech[i].name - // if (tech.tech[i].nameInfo) { - // text += tech.tech[i].nameInfo - // tech.tech[i].addNameInfo(); - // } if (tech.tech[i].count > 1) text += ` (${tech.tech[i].count}x)` } } - document.getElementById("tech").innerHTML = text + document.getElementById("right-HUD").innerHTML = text + + + // let text = "" + // if (simulation.difficultyMode > 2 && level.constraintDescription1) { + // text += `${level.constraintDescription1}` + // // text += `${level.constraintDescription1}` + // } + // if (simulation.difficultyMode > 4 && level.constraintDescription2) { + // text += `
${level.constraintDescription2}` + // } + // for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech + // if (tech.tech[i].isLost) { + // if (text) text += "
" //add a new line, but not on the first line + // text += `${tech.tech[i].name}` + // } else if (tech.tech[i].count > 0 && !tech.tech[i].isInstant) { + // if (text) text += "
" //add a new line, but not on the first line + // text += tech.tech[i].name + // if (tech.tech[i].count > 1) text += ` (${tech.tech[i].count}x)` + // } + // } + // document.getElementById("right-HUD").innerHTML = text + + // let constraints = "" + // if (simulation.difficultyMode > 2 && level.constraintDescription1) { + // constraints += `${level.constraintDescription1}` + // // text += `${level.constraintDescription1}` + // } + // if (simulation.difficultyMode > 4 && level.constraintDescription2) { + // constraints += `
${level.constraintDescription2}` + // } + // let text = "" + // for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech + // if (tech.tech[i].isLost) { + // if (text) text += "
" //add a new line, but not on the first line + // text += `${tech.tech[i].name}` + // } else if (tech.tech[i].count > 0 && !tech.tech[i].isInstant) { + // if (text) text += "
" //add a new line, but not on the first line + // text += tech.tech[i].name + // if (tech.tech[i].count > 1) text += ` (${tech.tech[i].count}x)` + // } + // } + // document.getElementById("right-HUD").innerHTML = constraints + `
` + text + `
` }, lastLogTime: 0, isTextLogOpen: true, - // - // SVGleftMouse: ' ', - // SVGrightMouse: ' ', inGameConsole(text, time = 240) { if (!localSettings.isHideHUD && simulation.isTextLogOpen && !build.isExperimentSelection) { if (simulation.lastLogTime > m.cycle) { //if there is an older message @@ -757,11 +782,11 @@ const simulation = { document.getElementById("health").style.display = "inline" document.getElementById("health-bg").style.display = "inline"; if (!localSettings.isHideHUD) { - document.getElementById("tech").style.display = "inline" + document.getElementById("right-HUD").style.display = "inline" document.getElementById("defense-bar").style.display = "inline" document.getElementById("damage-bar").style.display = "inline" } else { - document.getElementById("tech").style.display = "none" + document.getElementById("right-HUD").style.display = "none" document.getElementById("defense-bar").style.display = "none" document.getElementById("damage-bar").style.display = "none" } @@ -787,10 +812,11 @@ const simulation = { } else { Composite.add(engine.world, [player]) } + shuffle(level.constraint) level.populateLevels() - input.endKeySensing(); simulation.ephemera = [] + powerUps.powerUpStorage = [] tech.setupAllTech(); //sets tech to default values b.resetAllGuns(); tech.duplication = 0; @@ -843,6 +869,7 @@ const simulation = { level.onLevel = 0; level.levelsCleared = 0; level.updateDifficulty() + // level.setConstraints() simulation.clearNow = true; document.getElementById("text-log").style.display = "none" @@ -948,7 +975,7 @@ const simulation = { }, }) const before = { x: player.position.x, y: player.position.y, } - let posXClamped = Math.min(Math.max(level.fallModeBounds.left, player.position.x), level.fallModeBounds.right) + const posXClamped = Math.min(Math.max(level.fallModeBounds.left, player.position.x), level.fallModeBounds.right) Matter.Body.setPosition(player, { x: posXClamped, y: level.enter.y - 4000 }); // translate camera smoothly to preserve illusion to endless fall @@ -1042,7 +1069,6 @@ const simulation = { }, }) } - if (tech.isZeno) { if (tech.isEnergyHealth) { m.energy *= 0.95 @@ -1054,28 +1080,41 @@ const simulation = { } if (tech.cyclicImmunity && m.immuneCycle < m.cycle + tech.cyclicImmunity) m.immuneCycle = m.cycle + tech.cyclicImmunity; //player is immune to damage for 60 cycles - fallCheck = function (who, save = false) { - let i = who.length; - while (i--) { - if (who[i].position.y > simulation.fallHeight) { - if (save) { - Matter.Body.setVelocity(who[i], { x: 0, y: 0 }); - Matter.Body.setPosition(who[i], { - x: level.exit.x + 30 * (Math.random() - 0.5), - y: level.exit.y + 30 * (Math.random() - 0.5) - }); - } else { - Matter.Composite.remove(engine.world, who[i]); - who.splice(i, 1); - } + + + let i = body.length; + while (i--) { + if (body[i].position.y > simulation.fallHeight) { + Matter.Composite.remove(engine.world, body[i]); + body.splice(i, 1); + } + } + i = powerUp.length + while (i--) { + if (powerUp[i].position.y > simulation.fallHeight) { + Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 }); + if (level.fallMode === "position") { + const posXClamped = Math.min(Math.max(level.fallModeBounds.left, powerUp[i].position.x), level.fallModeBounds.right) + Matter.Body.setPosition(powerUp[i], { x: posXClamped, y: level.enter.y - 3000 }); + } else { + Matter.Body.setPosition(powerUp[i], { + x: level.exit.x + 30 * (Math.random() - 0.5), + y: level.exit.y + 30 * (Math.random() - 0.5) + }); } } - }; - fallCheck(body); - fallCheck(powerUp, true); - let i = mob.length; + } + i = mob.length; while (i--) { - if (mob[i].position.y > simulation.fallHeight) mob[i].death(); + if (mob[i].position.y > simulation.fallHeight) { + if (mob[i].isBoss && level.fallMode === "position") { + Matter.Body.setVelocity(mob[i], { x: 0, y: 0 }); + const posXClamped = Math.min(Math.max(level.fallModeBounds.left, mob[i].position.x), level.fallModeBounds.right) + Matter.Body.setPosition(mob[i], { x: posXClamped, y: level.enter.y - 3000 }); + } else { + mob[i].death(); + } + } } } diff --git a/js/spawn.js b/js/spawn.js index 9694499..98f6775 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -114,7 +114,7 @@ const spawn = { } }, secondaryBossChance(x, y) { - if (simulation.difficultyMode > 2 && level.levelsCleared > 2) { + if (simulation.difficultyMode > 3 && level.levelsCleared > 1) { spawn.randomLevelBoss(x, y); powerUps.directSpawn(x - 30, y, "ammo"); powerUps.directSpawn(x + 30, y, "ammo"); @@ -1014,7 +1014,7 @@ const spawn = { return } } - if (simulation.testing || simulation.difficultyMode > 4) { + if (simulation.testing || simulation.difficultyMode > 5) { unlockExit() setTimeout(function () { simulation.inGameConsole(`level.levels.length = Infinite`); @@ -2347,7 +2347,7 @@ const spawn = { ctx.fill(); } } - if (simulation.difficultyMode === 6) spawn.shield(me, x, y); + if (level.isMobShields) spawn.shield(me, x, y); }, // timeBoss(x, y, radius = 25) { // mobs.spawn(x, y, 12, radius, "#000"); @@ -7726,7 +7726,7 @@ const spawn = { }; }, //chance = Math.min(0.02 + simulation.difficulty * 0.005, 0.2) + tech.duplicationChance() - shield(target, x, y, chance = (simulation.difficultyMode === 6 ? 3 : 1) * Math.min(0.02 + simulation.difficulty * 0.005, 0.2)) { + shield(target, x, y, chance = (level.isMobShields ? 3.25 : 1) * Math.min(0.02 + simulation.difficulty * 0.005, 0.2)) { if (this.allowShields && Math.random() < chance) { mobs.spawn(x, y, 9, target.radius + 30, "rgba(220,220,255,0.9)"); let me = mob[mob.length - 1]; @@ -8086,7 +8086,7 @@ const spawn = { if (this.freeOfWires) { this.gravity(); } else { - if (m.pos.x > breakingPoint) { + if (m.pos.x > breakingPoint || simulation.isCheating) { this.freeOfWires = true; this.fill = "#000" this.force.x += -0.003; @@ -8158,7 +8158,7 @@ const spawn = { if (this.freeOfWires) { this.gravity(); } else { - if (m.pos.x > breakingPoint) { + if (m.pos.x > breakingPoint || simulation.isCheating) { this.freeOfWires = true; this.force.x -= 0.0004; this.fill = "#222"; @@ -8210,7 +8210,7 @@ const spawn = { if (this.freeOfWires) { this.gravity(); } else { - if (m.pos.x > breakingPoint) { + if (m.pos.x > breakingPoint || simulation.isCheating) { this.freeOfWires = true; this.force.x += -0.0003; this.fill = "#333"; @@ -8261,7 +8261,7 @@ const spawn = { if (this.freeOfWires) { this.gravity(); } else { - if (m.pos.x > breakingPoint) { + if (m.pos.x > breakingPoint || simulation.isCheating) { this.freeOfWires = true; this.force.x += -0.0006; this.fill = "#111"; @@ -8312,7 +8312,7 @@ const spawn = { if (this.freeOfWires) { this.gravity(); } else { - if (m.pos.x > breakingPoint) { + if (m.pos.x > breakingPoint || simulation.isCheating) { this.freeOfWires = true; this.force.x += -0.0005; this.fill = "#222"; diff --git a/js/tech.js b/js/tech.js index 1b541e5..1b2c526 100644 --- a/js/tech.js +++ b/js/tech.js @@ -188,13 +188,13 @@ const tech = { console.log(introArray[wordNumber]) if (introArray[wordNumber]) { if (answer && answer.toLowerCase() === introArray[wordNumber].toLowerCase().replace(/[^a-zA-Z]/g, '')) { - powerUps.spawnDelay("research", 5) + powerUps.spawnDelay("research", 4) simulation.inGameConsole(`correct!`, 360) } else { simulation.inGameConsole(`${answer} is wrong, it was ${introArray[wordNumber]}`, 360) } let text = `"` - for (let i = 0; i < wordLimit; i++) { + for (let i = 0; i < wordLimit + 3; i++) { if (i === wordNumber) { text += `${introArray[i]} ` } else { @@ -204,7 +204,7 @@ const tech = { simulation.inGameConsole(text + `..."`, 360) } else { simulation.inGameConsole(`hmmm I'm not sure the answer, so I'll say it's correct!`, 360) - powerUps.spawnDelay("research", 5) + powerUps.spawnDelay("research", 3) } } }, 1000); // Check every 1 second @@ -271,9 +271,10 @@ const tech = { damage: 1, //used for tech changes to player damage that don't have complex conditions damageFromTech() { let dmg = tech.damage * m.fieldDamage + if (level.isNoDamage && (m.cycle - 180 < level.noDamageCycle)) dmg *= 0.1 if (tech.isMaxHealthDamage && m.health === m.maxHealth) dmg *= 1.5 - if (tech.isNoDefenseDamage && m.defense() === 1) dmg *= 2 - if (tech.isImmunityDamage && m.immuneCycle > m.cycle) dmg *= 4 + if (tech.noDefenseSettingDamage && m.defense() === 1) dmg *= 2 + if (tech.isImmunityDamage && m.immuneCycle > m.cycle) dmg *= 3 if (tech.isPowerUpDamage) dmg *= 1 + 0.07 * powerUp.length if (tech.isDamageCooldown) dmg *= m.lastKillCycle + tech.isDamageCooldownTime > m.cycle ? 0.4 : 4 if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 2 @@ -281,7 +282,7 @@ const tech = { 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 (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage + if (powerUps.boost.endCycle > simulation.cycle) dmg *= 1 + powerUps.boost.damage if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.015 * m.coupling if (tech.isVerlet) dmg *= 3 if (tech.isTechDebt) dmg *= tech.totalCount > 20 ? Math.pow(0.85, tech.totalCount - 20) : 4 - 0.15 * tech.totalCount @@ -297,16 +298,17 @@ const tech = { if (tech.energyDamage) dmg *= 1 + m.energy * 0.23 * tech.energyDamage; if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.01 if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 - if (tech.isSpeedDamage) dmg *= 1 + Math.min(1, (tech.speedAdded + player.speed) * 0.0193) + if (tech.isSpeedDamage) dmg *= 1 + Math.min(2, ((tech.speedAdded + player.speed) * 0.033))//1 + Math.min(1, (tech.speedAdded + player.speed) * 0.0193) if (tech.isAxion && tech.isHarmDarkMatter) dmg *= ((tech.isMoveDarkMatter || tech.isNotDarkMatter) ? 3.2 : 2) if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3; if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit // if (tech.isLowHealthDmg) dmg *= 1 + 0.6 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health)) if (tech.isLowHealthDmg) dmg *= 1 + 0.6 * Math.max(0, (tech.isEnergyHealth ? m.maxEnergy - m.energy : m.maxHealth - m.health)) - if (tech.isJunkDNA) dmg *= 1 + 2 * tech.junkChance + if (tech.isJunkDNA) dmg *= 1 + 2 * (tech.junkChance + level.junkAdded) return dmg }, duplicationChance() { + if (level.isNoDuplicate) return 0 return Math.min(1, Math.max(0, (tech.isPowerUpsVanish ? 0.13 : 0) + (tech.isStimulatedEmission ? 0.2 : 0) + tech.duplication + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + 0.08 * tech.isDuplicateMobs + 0.03 * tech.isMassProduction + 0.04 * tech.isHealAttract + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.6 : 0) + 0.06 * tech.isDupEnergy)) }, setTechFrequency(name, frequency) { @@ -1162,67 +1164,6 @@ const tech = { tech.restDamage = 1; } }, - { - name: "Newtons 1st law", - descriptionFunction() { - return `damage taken is proportional to your speed
up to 0.2x damage taken at 55 speed (${(1 - Math.min((tech.speedAdded + player.speed) * 0.0193, 0.8)).toFixed(2)}x)` - }, - description: "", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return true - }, - requires: "", - effect() { - tech.isSpeedHarm = true //max at speed = 40 - }, - remove() { - tech.isSpeedHarm = false - } - }, - { - name: "Newtons 2nd law", - descriptionFunction() { - return `damage is proportional to your speed
up to 2x damage at 55 speed (${(1 + Math.min(1, ((tech.speedAdded + player.speed) * 0.0193))).toFixed(2)}x)` - }, - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return true - }, - requires: "", - effect() { - tech.isSpeedDamage = true //max at speed = 40 - }, - remove() { - tech.isSpeedDamage = false - } - }, - { - name: "modified Newtonian dynamics", - descriptionFunction() { - return `your speed counts as +20 higher
(for Newton's 1st and 2nd laws)` - }, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.isSpeedDamage || tech.isSpeedHarm - }, - requires: "Newtons 1st or 2nd law", - effect() { - tech.speedAdded = 20 - }, - remove() { - tech.speedAdded = 0 - } - }, { name: "kinetic bombardment", description: "far away mobs take more damage
up to 1.3x damage at 3000 displacement", @@ -1501,7 +1442,7 @@ const tech = { { name: "exciton", descriptionFunction() { - return `after mobs die they have a 14% chance to
spawn ${powerUps.orb.boost(1)} that give ${(1 + powerUps.boost.damage).toFixed(2)}x damage for ${(powerUps.boost.duration / 60).toFixed(0)} seconds
` + return `after mobs die they have a +14% chance to
spawn ${powerUps.orb.boost(1)} that give ${(1 + powerUps.boost.damage).toFixed(2)}x damage for ${(powerUps.boost.duration / 60).toFixed(0)} seconds
` }, maxCount: 1, count: 0, @@ -1823,7 +1764,7 @@ const tech = { { name: "sound-bot upgrade", link: `sound-bot upgrade`, - description: "convert your bots to sound-bots
2x wave fire rate, damage, and duration", + description: "convert your bots to sound-bots
6x wave damage", maxCount: 1, count: 0, frequency: 3, @@ -2139,7 +2080,7 @@ const tech = { name: "bot fabrication", link: `bot fabrication`, descriptionFunction() { - return `after you collect ${powerUps.orb.research(2 + Math.floor(0.1666 * b.totalBots()))}use them
to construct a random bot (+1 cost every 5 bots)` + return `after you collect ${powerUps.orb.research(2 + Math.floor(0.25 * b.totalBots()))}use them
to construct a random bot (+1 cost every 4 bots)` }, // description: `if you collect ${powerUps.orb.research(2)}use them to build a
random bot (+1 cost every 5 bots)`, maxCount: 1, @@ -2657,7 +2598,9 @@ const tech = { }, { name: "ablative drones", - description: "after losing health there is a chance
to rebuild your broken parts as drones", + descriptionFunction() { + return `after losing ${tech.isEnergyHealth ? "energy" : "health"} there is a chance
to rebuild your broken parts as drones` + }, maxCount: 1, count: 0, frequency: 1, @@ -2715,7 +2658,7 @@ const tech = { }, { name: "Pauli exclusion", - description: `for 8 seconds after mob collisions
become invulnerable and inhibit energy regen`, + description: `for 7 seconds after mob collisions
become invulnerable and inhibit energy regen`, maxCount: 9, count: 0, frequency: 1, @@ -2770,7 +2713,7 @@ const tech = { }, { name: "abelian group", - description: `4x damage while invulnerable`, + description: `3x damage while invulnerable`, maxCount: 1, count: 0, frequency: 2, @@ -3115,10 +3058,10 @@ const tech = { }, requires: "", effect() { - tech.isNoDefenseDamage = true; + tech.noDefenseSettingDamage = true; }, remove() { - tech.isNoDefenseDamage = false; + tech.noDefenseSettingDamage = false; } }, { @@ -4009,7 +3952,7 @@ const tech = { { name: "junk DNA", descriptionFunction() { - return `increase damage by twice the
JUNK chance (${(1 + 2 * tech.junkChance).toFixed(2)}x)` + return `increase damage by twice the
JUNK chance (${(1 + 2 * (tech.junkChance + level.junkAdded)).toFixed(2)}x)` }, maxCount: 1, count: 0, @@ -7930,8 +7873,8 @@ const tech = { requires: "negative mass", effect() { tech.isNeutronium = true - tech.baseFx *= 0.8 - tech.baseJumpForce *= 0.8 + tech.baseFx *= 0.86 + tech.baseJumpForce *= 0.87 m.setMovement() }, //also removed in m.setHoldDefaults() if player switches into a bad field @@ -8002,6 +7945,68 @@ const tech = { remove() { tech.isFlyFaster = false; } + }, { + name: "Newtons 1st law", + descriptionFunction() { + return `damage taken reduces as your speed increases
up to 0.05x damage taken at 60 speed (${(1 - Math.min((tech.speedAdded + player.speed) * 0.01583, 0.95)).toFixed(2)}x)` + }, + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return m.fieldMode === 3 || m.fieldMode === 10 + }, + requires: "negative mass, grappling hook", + effect() { + tech.isSpeedHarm = true //max at speed = 40 + }, + remove() { + tech.isSpeedHarm = false + } + }, + { + name: "Newtons 2nd law", + descriptionFunction() { + return `damage increases proportional to your speed
up to 3x damage at 60 speed (${(1 + Math.min(2, ((tech.speedAdded + player.speed) * 0.033))).toFixed(2)}x)` + }, + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return m.fieldMode === 3 || m.fieldMode === 10 + }, + requires: "negative mass, grappling hook", + effect() { + tech.isSpeedDamage = true //max at speed = 40 + }, + remove() { + tech.isSpeedDamage = false + } + }, + { + name: "modified Newtonian dynamics", + descriptionFunction() { + return `your speed counts as +20 higher
(for Newton's 1st and 2nd laws)` + }, + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isSpeedDamage || tech.isSpeedHarm + }, + requires: "Newtons 1st or 2nd law", + effect() { + tech.speedAdded = 20 + }, + remove() { + tech.speedAdded = 0 + } }, { name: "additive manufacturing", @@ -8235,7 +8240,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (m.fieldMode === 10 || m.fieldMode === 5 || m.fieldMode === 8) //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 + return (m.fieldMode === 10 || m.fieldMode === 5 || m.fieldMode === 8) }, requires: "plasma torch, grappling hook, pilot wave", effect() { @@ -9413,7 +9418,7 @@ const tech = { effect() { // tech.damage *= 1.33 setInterval(() => { - if (powerUps.boost.endCycle < m.cycle && !simulation.paused && m.alive) { + if (powerUps.boost.endCycle < simulation.cycle && !simulation.paused && m.alive) { for (let i = 0; i < mob.length; i++) { if (mob[i].distanceToPlayer2() < 400000) { //650 canvas.requestPointerLock(); @@ -9596,12 +9601,6 @@ const tech = { mob[i].death(); } } - // for (let i = powerUp.length - 1; i > -1; i--) { - // if (powerUp[i].name !== "ammo") { - // Matter.Composite.remove(engine.world, powerUp[i]); - // powerUp.splice(i, 1); - // } - // } }, remove() { } }, @@ -10098,12 +10097,31 @@ const tech = { }, requires: "not pilot wave, tokamak, wormhole", effect() { - + m.throwBlock = m.throwSelf }, remove() { m.throwBlock = m.throwBlockDefault } }, + { + name: "stationary", + description: "thrown blocks can't move,
but somehow they still have momentum...", + maxCount: 1, + count: 0, + frequency: 0, + // isInstant: true, + isJunk: true, + allowed() { + return m.fieldMode !== 8 && m.fieldMode !== 9 && !tech.isTokamak + }, + requires: "not pilot wave, tokamak, wormhole", + effect() { + tech.isStaticBlock = true + }, + remove() { + tech.isStaticBlock = false + } + }, { name: "spinor", description: "the direction you aim is determined by your position", @@ -10724,7 +10742,7 @@ const tech = { }, { name: "expert system", - description: "spawn JUNK
+50% JUNK chance", + description: `spawn ${powerUps.orb.tech()}
+50% JUNK chance`, maxCount: 9, count: 0, frequency: 0, @@ -11430,7 +11448,7 @@ const tech = { }, { name: "wikipedia", - description: `After you get ${powerUps.orb.tech()} you have 7 seconds to study for a quiz. If you ace the quiz you get ${powerUps.orb.research(5)}`, + description: `After you get ${powerUps.orb.tech()} you have 7 seconds to study for a quiz. If you ace the quiz you get ${powerUps.orb.research(4)}`, maxCount: 1, count: 0, frequency: 0, @@ -12053,8 +12071,9 @@ const tech = { isImmunityDamage: null, isMobDeathImmunity: null, isMaxHealthDefense: null, - isNoDefenseDamage: null, + noDefenseSettingDamage: null, isMaxHealthDamage: null, isEjectOld: null, isWiki: null, + isStaticBlock: null, } \ No newline at end of file diff --git a/style.css b/style.css index 5c0ab6e..965a2fb 100644 --- a/style.css +++ b/style.css @@ -694,22 +694,44 @@ summary { border-radius: 5px; } -#tech { +#right-HUD { position: absolute; top: 15px; right: 15px; z-index: 2; font-size: 20px; - color: #222; text-align: right; - opacity: 0.35; line-height: 120%; - background-color: rgba(255, 255, 255, 0.4); user-select: none; pointer-events: none; + /*border: 2px solid rgba(0, 0, 0, 0.4);*/ + color: #222; padding: 0px 5px 0px 5px; border-radius: 5px; - /*border: 2px solid rgba(0, 0, 0, 0.4);*/ + opacity: 0.35; + background-color: rgba(255, 255, 255, 0.4); +} + +#right-HUD-constraint { + position: absolute; + top: 12px; + right: 15px; + z-index: 2; + font-size: 20px; + text-align: right; + line-height: 120%; + user-select: none; + pointer-events: none; + padding: 5px 10px 5px 10px; + border-radius: 8px; + color: #624; + opacity: 0.35; + background-color: rgba(255, 215, 241, 0.4); + /* color: rgb(141, 23, 88); + opacity: 0.35; + background-color: rgba(141, 23, 88, 0.1); */ + /* font-weight: 400; */ + transition: all 0.5s linear; } #text-log { @@ -727,6 +749,12 @@ summary { user-select: none; } +.constraint { + color: rgb(141, 23, 88); + /* font-weight: 100; */ + /* text-decoration: underline; */ +} + .color-text { color: #000; } diff --git a/todo.txt b/todo.txt index 504eece..5f1086c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,55 +1,137 @@ ******************************************************** NEXT PATCH ************************************************** -JUNK: wikipedia - After you get a new tech you have 7 seconds to study before a quiz, 4 research if you aces the quiz. - this code for this works 80% of the time every time +difficulty + difficulty level 6 adds flat damage and damage taken + bonus tech no longer spawns on level 2 and 3 on difficulty level 6 + at the end of subway you get 1 tech, but not on difficulty level 6 + difficulty level 3 and 5 add a random constraint that changes each level +constraints are effects that only last until the level ends + 50% JUNK chance + 4x shielded mob chance + power ups are sent to next level + +33% chance for mobs to respawn + -1 choice + 2x ammo costs + duplication is set to zero + 50% max energy + 50% max health + bots follow slow + full damage taken after boss dies + 0.1x damage after a power up + mob death heals mobs + mobs heal for your lost health + periodically spawn WIMPs + +exciton damage boost power up has a chance to spawn without the tech (~3%/mob) + damage boost has a unique gel/hair aura for each skin + damage boost timer no longer ticks with time dilation field +JUNK tech: stationary - thrown blocks can't move, but they still have momentum +added a classic n-gon link for the previous patch in settings + but images are disabled to save space +on levels where you can fall endlessly, power ups will also fall endlessly + they no longer teleport to the exit, sorry -renamed propagator->Verlet integration it's now a skin tech - 1.6->3x damage - slightly increased the time skip amount -on some skins the feet will hang lower while player is in the air -on some skins the upper legs are skinnier -mouse over on orbs for tech, field, and gun has a tooltip with text -added keyword CSS style for "bot" -added an aura around powerUpBoss so you can kinda see it inside walls - -quenching just gives max health from over healing instead of damaging you first -depolarization does 0.5->0.4x damage when on cooldown -many-worlds spawns a tech and also 3 coupling at the start of each new level -dynamic equilibrium does 1.15x more damage and only stacks to 9->3 -orbital bots collide with a 1.2x larger range -Zectron no longer drains energy when balls hit you, but the balls still stop -supply chain just gives a gun and a flat 10 ammo - -polyurethane foam will only trigger up to 55 total foam per harpoon - to prevent a huge number of foam bubbles causing lag - no cap for super balls for now -fixed bug with planned obsolescence + instant tech -fixed bug with ice crystal nucleation -applied science gives each gunTech with a short delay - this helps with sorting and maybe other rare bugs -fixed bug with delivery drones and path integration -you can no longer deflect snakeBoss, but it moves a bit slower +Newton's 1st and 2nd laws are field tech, and they give twice the effect +abelian group 4->3x damage while invulnerable +bot fabrication price increases after 5->4 bots +wikipedia 4->3 research per correct quiz +upgraded sound bots fire fewer waves but do more damage per wave + not much changed except improved performance, I think +incendiary ammunition drones explode when they run out of durability not on the first hit + this allows better synergy with other drone tech +grappling hook retract momentum no longer scales with distance + this should give you more control +pressing the 3rd button in factory will remove blocks resting on the second block + preventing an endless toggle +bug fixes + fleas no longer die early after hitting a high health target only once + something with super ball density calculations for tech rebound + grabbing a big block can make grappling hook go flying + added 3 potential fixes, but the bug is too rare know if it's fixed ******************************************************** BUGS ******************************************************** +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? + check which of these is working + level order + is flipped + constraint order + mob type order + boss order + gun, field, tech options + make field options offered precalculated so it doesn't depend on player choices? + generate all constraints at the start of the game + 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 ***************************************************** +each difficulty setting adds a chance for a random effect + make some effects only possible on certain levels, or with certain bosses? + not implemented random constraint ideas________________________ + if player takes too long on a level + spawn mobs at the end of player's history + give a warning before they spawn + black holes, sneakers, bullets + mob death spawns something + bullets + bosses heals nearby mobs + ammo power ups give 0.7x ammo + 2x energy costs + 0.5x energy regen from all sources + 2x research costs + mobs slowly regen health + exit door takes 10x time to open, + and while door is opening (ghosters, suckers) attack? + can't pause while choosing tech, gun, field similar to eternalism + can't have more then 15 bullets + bots do 0.5x damage + remove 2 random tech and return them next level + too niche + player damage is 0.25x while player is invulnerable + all hazards: lasers and slime do 3x damage + player lasers and radiation do 0.5x damage + explosions do 0.5x damage + freeze effects last 0.25x time + +tech: - randomize constraints somehow + in pause interface or power up selection menu? + each time you research the current constraints also randomize? + only allowed if difficulty is high enough + +tech: - when you get a bot, get a second bot + +tech: - boost power ups also give 0.1x damage taken + tech: - tech have +3 choices to eject your tech tech name no description? +copy negative-player as a boss? or a JUNK tech? + code is in community map (not sure which) + harpoon tech: - after firing 4 harpoons your next harpoon has 4x damage need to track number fired -JUNK tech - similar to cosmogonic myth, open and close tabs - after you learn a new tech open it's wiki and spawn a few research? - open the wiki for each tech you have, - tabs close after 1 minute, and you have to learn something and answer a prompt to get a reward +tech: - after killing a Boss + heal to full + gain 3x damage for the rest of the level + +tech: clicking on this tech in the pause menu will teleport you to the next level tech: - instead of reeling in grappling hook teleport to the hook after releasing field button this might need another buff? @@ -57,6 +139,11 @@ tech: - instead of reeling in grappling hook teleport to the hook after releas new level - rework testChamber +skin with wheel instead of legs + +Boss (or mob) that quickly moves towards player, but they moves perpendicularly to player, like dodging + could respond to when player presses fire key or to when it takes damage + new snakeBoss type that eats mobs each time it eats: heal? @@ -80,13 +167,6 @@ Boss mob - records the position of mobs every few cycles gives mobs short snake tails, like snakeBoss brings 1 mob back to life every few seconds - -merge multiple power ups of the same type if nearby - 5-10 ammo, research, coupling can merge to form a slightly larger power up version - check for merger possibility every 60 seconds? - adjust mass spawns to just spawn larger power ups versions and change? - spawnDelay - tech: atomic pile - lose 1 health if you are above the maximum energy generate energy for each nearby mob? do damage? @@ -160,9 +240,6 @@ after picking up research gain ____ tech: Energy generation increases with you velocity Newtons' 3rd law? -after clicking on a new tech (or getting it in any way) animate adding the tech to your collection - fade in on right side text list? - tech - getting caught in an explosion gives you _____ damage for 10 seconds? heals @@ -1310,6 +1387,9 @@ possible names for tech Coalescence - things merging together like clouds. maybe mergin power ups? trihydrogen cation - common molecule in space, dark matter tech? superradiance - laser tech + cryocoolers - freezing effects + metaphysics - maybe this changes something deep and universal about physics? not sure + cork - used as a heat shield for rockets ******************************************************* DESIGN ******************************************************