diff --git a/.DS_Store b/.DS_Store index dd7f993..4df85bd 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/js/bullet.js b/js/bullet.js index 55af9b6..d7e5b8d 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -216,18 +216,18 @@ const b = { } }, fireProps(cd, speed, dir, me) { - m.fireCDcycle = m.cycle + Math.floor(cd * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(cd * b.fireCDscale); // cool down Matter.Body.setVelocity(bullet[me], { x: m.Vx / 2 + speed * Math.cos(dir), y: m.Vy / 2 + speed * Math.sin(dir) }); World.add(engine.world, bullet[me]); //add bullet to world }, - fireCD: 1, + fireCDscale: 1, setFireCD() { - b.fireCD = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage / tech.fastTime - if (tech.isFireRateForGuns) b.fireCD *= Math.pow(0.86, b.inventory.length) - if (tech.isFireMoveLock) b.fireCD *= 0.5 + b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage / tech.fastTime + if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.86, b.inventory.length) + if (tech.isFireMoveLock) b.fireCDscale *= 0.5 }, fireAttributes(dir, rotate = true) { if (rotate) { @@ -2435,7 +2435,7 @@ const b = { // friction: 0.2, // restitution: 0.2, dmg: 0, //damage on impact - damage: tech.isFastFoam ? 0.048 : 0.012, //damage done over time + damage: (tech.isFastFoam ? 0.048 : 0.012) * (tech.isFoamTeleport ? 1.66 : 1), //damage done over time scale: 1 - 0.006 / tech.isBulletsLastLonger * (tech.isFastFoam ? 1.6 : 1), classType: "bullet", collisionFilter: { @@ -2449,6 +2449,8 @@ const b = { target: null, targetVertex: null, targetRelativePosition: null, + portFrequency: 5 + Math.floor(5 * Math.random()), + nextPortCycle: Infinity, //disabled unless you have the teleport tech beforeDmg(who) { if (!this.target && who.alive) { this.target = who; @@ -2494,6 +2496,8 @@ const b = { if (this.radius < 8) this.endCycle = 0; } + + if (this.target && this.target.alive) { //if stuck to a target const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector if (this.target.isVerticesChange) { @@ -2577,9 +2581,15 @@ const b = { } } } + if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isFoamTeleport + this.nextPortCycle = simulation.cycle + this.portFrequency + const range = 10 * Math.sqrt(this.radius) * Math.random() + Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random()))) + } } } }); + if (tech.isFoamTeleport) bullet[me].nextPortCycle = simulation.cycle + bullet[me].portFrequency World.add(engine.world, bullet[me]); //add bullet to world Matter.Body.setVelocity(bullet[me], velocity); }, @@ -3502,9 +3512,9 @@ const b = { fireNormal() { if (this.nextFireCycle + 1 < m.cycle) this.startingHoldCycle = m.cycle //reset if not constantly firing const CD = Math.max(11 - 0.06 * (m.cycle - this.startingHoldCycle), 2) //CD scales with cycles fire is held down - this.nextFireCycle = m.cycle + CD * b.fireCD //predict next fire cycle if the fire button is held down + this.nextFireCycle = m.cycle + CD * b.fireCDscale //predict next fire cycle if the fire button is held down - m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCDscale); // cool down this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / CD) }, fireNeedles() { @@ -3575,13 +3585,13 @@ const b = { } if (m.crouch) { - m.fireCDcycle = m.cycle + 45 * b.fireCD; // cool down + m.fireCDcycle = m.cycle + 45 * b.fireCDscale; // cool down makeNeedle() for (let i = 1; i < 4; i++) { //4 total needles setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i); } } else { - m.fireCDcycle = m.cycle + 25 * b.fireCD; // cool down + m.fireCDcycle = m.cycle + 25 * b.fireCDscale; // cool down makeNeedle() for (let i = 1; i < 3; i++) { //3 total needles setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i); @@ -3595,7 +3605,7 @@ const b = { // makeNeedle(m.angle - spread) }, fireRivets() { - m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCDscale); // cool down const me = bullet.length; const size = tech.rivetSize * 7.5 @@ -3640,13 +3650,13 @@ const b = { fireNailFireRate() { if (this.nextFireCycle + 1 < m.cycle) this.startingHoldCycle = m.cycle //reset if not constantly firing const CD = Math.max(7.5 - 0.06 * (m.cycle - this.startingHoldCycle), 2) //CD scales with cycles fire is held down - this.nextFireCycle = m.cycle + CD * b.fireCD //predict next fire cycle if the fire button is held down + this.nextFireCycle = m.cycle + CD * b.fireCDscale //predict next fire cycle if the fire button is held down - m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCDscale); // cool down this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / CD) }, fireInstantFireRate() { - m.fireCDcycle = m.cycle + Math.floor(2 * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(2 * b.fireCDscale); // cool down this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / 2) }, baseFire(angle) { @@ -3685,18 +3695,18 @@ const b = { let knock, spread if (m.crouch) { spread = 0.65 - m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCD); // cool down - if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(58 * b.fireCD)) m.immuneCycle = m.cycle + Math.floor(58 * b.fireCD); //player is immune to damage for 30 cycles + m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCDscale); // cool down + if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(58 * b.fireCDscale)) m.immuneCycle = m.cycle + Math.floor(58 * b.fireCDscale); //player is immune to damage for 30 cycles knock = 0.01 } else { - m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCD); // cool down - if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(47 * b.fireCD)) m.immuneCycle = m.cycle + Math.floor(47 * b.fireCD); //player is immune to damage for 30 cycles + m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale); // cool down + if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(47 * b.fireCDscale)) m.immuneCycle = m.cycle + Math.floor(47 * b.fireCDscale); //player is immune to damage for 30 cycles spread = 1.3 knock = 0.1 } if (tech.isShotgunRecoil) { - m.fireCDcycle -= 0.66 * (45 * b.fireCD) + m.fireCDcycle -= 0.66 * (45 * b.fireCDscale) player.force.x -= 2 * knock * Math.cos(m.angle) player.force.y -= 2 * knock * Math.sin(m.angle) //reduce knock back in vertical direction to stop super jumps } else { @@ -3848,7 +3858,7 @@ const b = { do() {}, fireOne() { const SPEED = m.crouch ? 43 : 36 - m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCDscale); // cool down let dir = m.angle const me = bullet.length; bullet[me] = Bodies.polygon(m.pos.x + 30 * Math.cos(m.angle), m.pos.y + 30 * Math.sin(m.angle), 12, 21 * tech.bulletSize, b.fireAttributes(dir, false)); @@ -3875,7 +3885,7 @@ const b = { }, fireMulti() { const SPEED = m.crouch ? 43 : 36 - m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCDscale); // cool down const SPREAD = m.crouch ? 0.08 : 0.13 let dir = m.angle - SPREAD * (tech.superBallNumber - 1) / 2; for (let i = 0; i < tech.superBallNumber; i++) { @@ -3908,7 +3918,7 @@ const b = { const dir = m.angle const x = m.pos.x + 30 * Math.cos(m.angle) const y = m.pos.y + 30 * Math.sin(m.angle) - const delay = Math.floor((m.crouch ? 18 : 12) * b.fireCD) + const delay = Math.floor((m.crouch ? 18 : 12) * b.fireCDscale) m.fireCDcycle = m.cycle + delay; // cool down for (let i = 0; i < tech.superBallNumber; i++) { @@ -3960,7 +3970,7 @@ const b = { do() { if (this.wavePacketCycle && !input.fire) { this.wavePacketCycle = 0; - m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCDscale); // cool down } }, damage: 1, @@ -4060,7 +4070,7 @@ const b = { //fire a packet of bullets then delay for a while this.wavePacketCycle++ if (this.wavePacketCycle > tech.wavePacketLength) { - m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCDscale); // cool down this.wavePacketCycle = 0; } } @@ -4076,7 +4086,7 @@ const b = { fire() { const countReduction = Math.pow(0.9, tech.missileCount) if (m.crouch) { - m.fireCDcycle = m.cycle + 10 * b.fireCD / countReduction; // cool down + m.fireCDcycle = m.cycle + 10 * b.fireCDscale / countReduction; // cool down // for (let i = 0; i < tech.missileCount; i++) { // b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2, Math.sqrt(countReduction)) @@ -4102,7 +4112,7 @@ const b = { b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5), -2) } } else { - m.fireCDcycle = m.cycle + 50 * b.fireCD / countReduction; // cool down + m.fireCDcycle = m.cycle + 50 * b.fireCDscale / countReduction; // cool down const direction = { x: Math.cos(m.angle), y: Math.sin(m.angle) @@ -4147,7 +4157,7 @@ const b = { // bullet[bullet.length - 1].force.x -= 0.015 * (i - 1); // } // } else { - // m.fireCDcycle = m.cycle + 80 * b.fireCD; // cool down + // m.fireCDcycle = m.cycle + 80 * b.fireCDscale; // cool down // const direction = { // x: Math.cos(m.angle), // y: Math.sin(m.angle) @@ -4164,7 +4174,7 @@ const b = { // } // } else { // if (m.crouch) { - // m.fireCDcycle = m.cycle + 10 * b.fireCD; // cool down + // m.fireCDcycle = m.cycle + 10 * b.fireCDscale; // cool down // const off = Math.random() - 0.5 // b.missile({ // x: m.pos.x, @@ -4174,7 +4184,7 @@ const b = { // bullet[bullet.length - 1].force.x += off * 0.03; // // bullet[bullet.length - 1].force.y += push.y * (i - 1); // } else { - // m.fireCDcycle = m.cycle + 55 * b.fireCD; // cool down + // m.fireCDcycle = m.cycle + 55 * b.fireCDscale; // cool down // // bullet[bullet.length - 1].force.y += 0.01; //a small push down at first to make it seem like the missile is briefly falling // } @@ -4189,7 +4199,7 @@ const b = { have: false, do() {}, fire() { - m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 40 : 30) * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 40 : 30) * b.fireCDscale); // cool down b.grenade() }, }, { @@ -4218,7 +4228,7 @@ const b = { y: speed * Math.sin(m.angle) }, 0, tech.isMineAmmoBack) } - m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 50 : 25) * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 50 : 25) * b.fireCDscale); // cool down } }, { name: "spores", @@ -4362,18 +4372,18 @@ const b = { if (tech.isDroneRadioactive) { if (m.crouch) { b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45) - m.fireCDcycle = m.cycle + Math.floor(5 * 13 * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(5 * 13 * b.fireCDscale); // cool down } else { b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 10) - m.fireCDcycle = m.cycle + Math.floor(5 * 6 * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(5 * 6 * b.fireCDscale); // cool down } } else { if (m.crouch) { b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45) - m.fireCDcycle = m.cycle + Math.floor(13 * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(13 * b.fireCDscale); // cool down } else { b.drone() - m.fireCDcycle = m.cycle + Math.floor(6 * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(6 * b.fireCDscale); // cool down } } } @@ -4388,10 +4398,10 @@ const b = { // fire() { // if (m.crouch) { // b.iceIX(10, 0.3) - // m.fireCDcycle = m.cycle + Math.floor(8 * b.fireCD); // cool down + // m.fireCDcycle = m.cycle + Math.floor(8 * b.fireCDscale); // cool down // } else { // b.iceIX(2) - // m.fireCDcycle = m.cycle + Math.floor(3 * b.fireCD); // cool down + // m.fireCDcycle = m.cycle + Math.floor(3 * b.fireCDscale); // cool down // } // } @@ -4427,7 +4437,7 @@ const b = { }, fire() { this.charge++ - m.fireCDcycle = m.cycle + Math.floor((1 + 0.35 * this.charge) * b.fireCD); + m.fireCDcycle = m.cycle + Math.floor((1 + 0.35 * this.charge) * b.fireCDscale); }, fireFoam() { const spread = (m.crouch ? 0.05 : 0.6) * (Math.random() - 0.5) @@ -4517,7 +4527,7 @@ const b = { if (tech.isCapacitor) { if ((m.energy > 0.16 || tech.isRailEnergyGain)) { //&& m.immuneCycle < m.cycle m.energy += 0.16 * (tech.isRailEnergyGain ? 6 : -1) - m.fireCDcycle = m.cycle + Math.floor(30 * b.fireCD); + m.fireCDcycle = m.cycle + Math.floor(30 * b.fireCDscale); const me = bullet.length; bullet[me] = Bodies.rectangle(m.pos.x + 50 * Math.cos(m.angle), m.pos.y + 50 * Math.sin(m.angle), 60, 14, { density: 0.005, //0.001 is normal @@ -4552,7 +4562,7 @@ const b = { } }, onEnd() {}, - drawCycle: Math.floor(10 * b.fireCD), + drawCycle: Math.floor(10 * b.fireCDscale), do() { this.force.y += this.mass * 0.0003; // low gravity that scales with charge if (this.drawCycle > 0) { @@ -4693,7 +4703,7 @@ const b = { m.fireCDcycle = Infinity //can't fire until mouse is released const previousCharge = this.charge - let smoothRate = 0.98 * (m.crouch ? 0.99 : 1) * (0.98 + 0.02 * b.fireCD) //small b.fireCD = faster shots, b.fireCD=1 = normal shot, big b.fireCD = slower chot + let smoothRate = 0.98 * (m.crouch ? 0.99 : 1) * (0.98 + 0.02 * b.fireCDscale) //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot this.charge = this.charge * smoothRate + 1 * (1 - smoothRate) if (tech.isRailEnergyGain) { if (m.immuneCycle < m.cycle) m.energy += (this.charge - previousCharge) * 2 //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen @@ -4827,12 +4837,12 @@ const b = { this.do = () => {}; if (tech.isPulseLaser) { this.fire = () => { - const drain = 0.01 * tech.isLaserDiode / b.fireCD + const drain = 0.01 * tech.isLaserDiode / b.fireCDscale if (m.energy > drain) { m.energy -= m.fieldRegen if (this.charge < 50 * m.maxEnergy) { m.energy -= drain - this.charge += 1 / b.fireCD + this.charge += 1 / b.fireCDscale } } } @@ -4905,7 +4915,7 @@ const b = { // this.fire = this.firePhoton }, // firePhoton() { - // m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down + // m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down // b.photon({ x: m.pos.x + 23 * Math.cos(m.angle), y: m.pos.y + 23 * Math.sin(m.angle) }, m.angle) // }, fireLaser() { @@ -5041,7 +5051,7 @@ const b = { } }, // firePulse() { - // m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down + // m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down // let energy = 0.3 * Math.min(m.energy, 1.5) // m.energy -= energy * tech.isLaserDiode // if (tech.beamSplitter) { @@ -5082,7 +5092,7 @@ const b = { if (this.rewindCount > 599 || m.energy < DRAIN || history.activeGun !== this.activeGunIndex) { this.rewindCount = 0; m.resetHistory(); - m.fireCDcycle = m.cycle + Math.floor(120 * b.fireCD); // cool down + m.fireCDcycle = m.cycle + Math.floor(120 * b.fireCDscale); // cool down } else { m.energy -= DRAIN if (m.immuneCycle < m.cycle + 30) m.immuneCycle = m.cycle + 30; //player is immune to damage for 5 cycles diff --git a/js/index.js b/js/index.js index 96aa9ab..b9219fe 100644 --- a/js/index.js +++ b/js/index.js @@ -119,6 +119,8 @@ window.addEventListener('load', () => { const canvas = document.getElementById("canvas"); //using "const" causes problems in safari when an ID shares the same name. const ctx = canvas.getContext("2d"); +// const ctx = canvas.getContext('2d', { alpha: false }); //optimization, but doesn't work + document.body.style.backgroundColor = "#fff"; //disable pop up menu on right click @@ -195,7 +197,7 @@ const build = { ${simulation.isCheating? "lore disabled

": ""} damage increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}%
harm reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}% -
fire delay decrease: ${((1-b.fireCD)*100).toFixed(b.fireCD < 0.1 ? 2 : 0)}% +
fire delay decrease: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
duplication chance: ${(Math.min(1,tech.duplicationChance())*100).toFixed(0)}% ${botText}
diff --git a/js/level.js b/js/level.js index 6f0369a..56fe8ff 100644 --- a/js/level.js +++ b/js/level.js @@ -15,9 +15,9 @@ const level = { // simulation.enableConstructMode() //used to build maps in testing mode // level.difficultyIncrease(30) // simulation.isHorizontalFlipped = true - // m.setField("time dilation") - // b.giveGuns("grenades") - // tech.giveTech("neutron bomb") + // m.setField("metamaterial cloaking") + // b.giveGuns("foam") + // tech.giveTech("uncertainty principle") // for (let i = 0; i < 9; i++) tech.giveTech("spherical harmonics") // tech.giveTech("supertemporal") // for (let i = 0; i < 3; i++) tech.giveTech("packet length") @@ -1273,7 +1273,6 @@ const level = { } } ) - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 2000 - 650, y + -875); spawn.randomMob(x + 2000 - 1600, y + -425, Infinity); spawn.randomMob(x + 2000 - 1725, y + -1250, Infinity); spawn.randomMob(x + 2000 - 1250, y + -1200, Infinity); @@ -1281,6 +1280,7 @@ const level = { spawn.randomMob(x + 2000 - 800, y + -125, Infinity); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob + spawn.secondaryBossChance(x + 2000 - 650, y + -875) } else { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall @@ -1305,7 +1305,6 @@ const level = { } } ) - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875); spawn.randomMob(x + 1600, y + -425, Infinity); spawn.randomMob(x + 1725, y + -1250, Infinity); spawn.randomMob(x + 1250, y + -1200, Infinity); @@ -1313,6 +1312,7 @@ const level = { spawn.randomMob(x + 800, y + -125, Infinity); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob + spawn.secondaryBossChance(x + 650, y + -875) } }, (x = offset.x, y = offset.y) => { //spawn block and fire it @@ -1365,7 +1365,6 @@ const level = { } } ) - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875); spawn.randomMob(x + 2000 - 1600, y + -425, Infinity); spawn.randomMob(x + 2000 - 1725, y + -1250, Infinity); spawn.randomMob(x + 2000 - 1250, y + -1200, Infinity); @@ -1373,6 +1372,7 @@ const level = { spawn.randomMob(x + 2000 - 800, y + -125, Infinity); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob + spawn.secondaryBossChance(x + 650, y + -875) } else { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall @@ -1422,7 +1422,6 @@ const level = { } } ) - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875); spawn.randomMob(x + 1600, y + -425, Infinity); spawn.randomMob(x + 1725, y + -1250, Infinity); spawn.randomMob(x + 1250, y + -1200, Infinity); @@ -1430,6 +1429,7 @@ const level = { spawn.randomMob(x + 800, y + -125, Infinity); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob + spawn.secondaryBossChance(x + 650, y - 875) } }, (x = offset.x, y = offset.y) => { //fire an "ammo clip" of blocks @@ -1493,7 +1493,6 @@ const level = { } } ) - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875); spawn.randomMob(x + 2000 - 1600, y + -425, Infinity); spawn.randomMob(x + 2000 - 1725, y + -1250, Infinity); spawn.randomMob(x + 2000 - 1250, y + -1200, Infinity); @@ -1501,6 +1500,7 @@ const level = { spawn.randomMob(x + 2000 - 800, y + -125, Infinity); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob + spawn.secondaryBossChance(x + 650, y - 875) } else { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall @@ -1561,7 +1561,6 @@ const level = { } } ) - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875); spawn.randomMob(x + 1600, y + -425, Infinity); spawn.randomMob(x + 1725, y + -1250, Infinity); spawn.randomMob(x + 1250, y + -1200, Infinity); @@ -1569,6 +1568,7 @@ const level = { spawn.randomMob(x + 800, y + -125, Infinity); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob + spawn.secondaryBossChance(x + 650, y - 875) } } ] @@ -2169,7 +2169,6 @@ const level = { // spawn.randomGroup(1700, -900, 0.4); // if (simulation.difficulty > 3) spawn.randomLevelBoss(2200, -1300); powerUps.addResearchToLevel() //needs to run after mobs are spawned - // if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500); }, final() { level.custom = () => { @@ -2219,7 +2218,7 @@ const level = { spawn.mapRect(5700, -3300, 1800, 5100); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump spawn.mapRect(5425, -650, 375, 450); //blocking exit - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500); + spawn.secondaryBossChance(4800, -500) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -2289,7 +2288,7 @@ const level = { if (simulation.difficulty * Math.random() > 7 * i) spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); } powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350); + spawn.secondaryBossChance(4125, -350) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -2509,7 +2508,6 @@ const level = { } } powerUps.spawnStartingPowerUps(2300, -150); - // if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1900, -675); }, testChamber() { level.setPosToSpawn(0, -50); //lower start @@ -2705,8 +2703,7 @@ const level = { } } powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1925, -1250); - + spawn.secondaryBossChance(1925, -1250) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -2913,8 +2910,7 @@ const level = { spawn.randomMob(2825, 400, 0.9); if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss", "orbitalBoss", "shieldingBoss"]); powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275); - + spawn.secondaryBossChance(7725, 2275) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3101,7 +3097,7 @@ const level = { } } powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3950, -850); + spawn.secondaryBossChance(3950, -850) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3272,7 +3268,7 @@ const level = { spawn.randomGroup(4900, -1200, 0); if (simulation.difficulty > 3) spawn.randomLevelBoss(3200, -1900); powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(2175, -2425); + spawn.secondaryBossChance(2175, -2425) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3489,7 +3485,7 @@ const level = { } } powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(5350, -325); + spawn.secondaryBossChance(5350, -325) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3657,7 +3653,7 @@ const level = { spawn.randomGroup(1700, -900, 0.4); if (simulation.difficulty > 3) spawn.randomLevelBoss(2600, -2300); powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3075, -2050); + spawn.secondaryBossChance(3075, -2050) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3899,7 +3895,7 @@ const level = { if (simulation.difficulty > 3) spawn.randomLevelBoss(-2400, -2650); powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(-1825, -1975); + spawn.secondaryBossChance(-1825, -1975) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -4206,8 +4202,8 @@ const level = { spawn.snakeBoss(-1000 + Math.random() * 2500, -1300); //boss snake with head } } - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(300, -800); powerUps.addResearchToLevel() //needs to run after mobs are spawned + spawn.secondaryBossChance(300, -800) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -4438,7 +4434,7 @@ const level = { } } powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1875, -675); + spawn.secondaryBossChance(1875, -675) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -5920,7 +5916,7 @@ const level = { } } powerUps.addResearchToLevel() //needs to run after mobs are spawned - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275); + spawn.secondaryBossChance(7725, 2275) }, coliseum() { level.custom = () => { @@ -6070,8 +6066,7 @@ const level = { powerUps.spawn(200, 50, "ammo"); powerUps.addResearchToLevel() //needs to run after mobs are spawned - - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(6600, 600, ["historyBoss", "powerUpBoss", "pulsarBoss", "orbitalBoss"]); + spawn.secondaryBossChance(6600, 600) }, crossfire() { //*1.5 @@ -6179,12 +6174,8 @@ const level = { // spawn.randomGroup(7700, -1100, 0.5); spawn.randomGroup(9800, -1100, 0.5); - if (simulation.difficulty > 10) { - spawn.randomLevelBoss(8600, -600, ["powerUpBoss", "bomberBoss", "snakeBoss", "spiderBoss", "historyBoss"]); - } - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) { - spawn.randomLevelBoss(7900, -400, ["powerUpBoss", "spiderBoss", "historyBoss"]); - } + if (simulation.difficulty > 10) spawn.randomLevelBoss(8600, -600, ["powerUpBoss", "bomberBoss", "snakeBoss", "spiderBoss", "historyBoss"]) + spawn.secondaryBossChance(7900, -400) //Boss Spawning if (simulation.difficulty > 10) { @@ -6422,7 +6413,7 @@ const level = { } else { exitDoor.isOpen = false; } - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(800, -800); + spawn.secondaryBossChance(800, -800) powerUps.spawn(4450, 1050, "heal"); if (Math.random() > (0.2 + (simulation.difficulty / 60))) { @@ -6933,15 +6924,7 @@ const level = { spawn.randomLevelBoss(850 + Math.random() * 250, -1100 + Math.random() * 200, bosses); } } - if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) { - if (abc < 0.6 * 5 / 8 || abc >= 1 - 0.15 * 5 / 17) { - spawn.laserBoss(-350 + Math.random() * 300, -600 + Math.random() * 200); - } else if (abc < 0.65) { - spawn.randomLevelBoss(850 + Math.random() * 250, -1100 + Math.random() * 200, bosses); - } else { - spawn.randomLevelBoss(-1500 + Math.random() * 250, -1100 + Math.random() * 200, bosses); - } - } + spawn.secondaryBossChance(850 + Math.random() * 250, -1100 + Math.random() * 200) //draw leg for statue function statueLeg(shift, color) { diff --git a/js/player.js b/js/player.js index 7ee8b3c..c0cd448 100644 --- a/js/player.js +++ b/js/player.js @@ -49,6 +49,7 @@ const m = { eyeFillColor: null, fillColor: null, //set by setFillColors fillColorDark: null, //set by setFillColors + bodyGradient: null, //set by setFillColors color: { hue: 0, sat: 0, @@ -57,6 +58,10 @@ const m = { setFillColors() { this.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)` this.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light-25}%)` + let grd = ctx.createLinearGradient(-30, 0, 30, 0); + grd.addColorStop(0, m.fillColorDark); + grd.addColorStop(1, m.fillColor); + this.bodyGradient = grd }, height: 42, yOffWhen: { @@ -803,10 +808,7 @@ const m = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient; ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -838,10 +840,7 @@ const m = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -873,10 +872,7 @@ const m = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -1091,8 +1087,8 @@ const m = { if (input.field) { if (m.energy > 0.001) { if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle - m.energy -= 0.001 / tech.throwChargeRate; - m.throwCharge += 0.5 * (tech.throwChargeRate + 2 * tech.isAddBlockMass) / m.holdingTarget.mass + m.throwCharge += 0.5 * (tech.throwChargeRate / b.fireCDscale + 2 * tech.isAddBlockMass) / m.holdingTarget.mass + if (m.throwCharge < 6) m.energy -= 0.001 / tech.throwChargeRate / b.fireCDscale; // m.throwCharge caps at 5 //draw charge const x = m.pos.x + 15 * Math.cos(m.angle); const y = m.pos.y + 15 * Math.sin(m.angle); @@ -2996,10 +2992,7 @@ const m = { //body ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; diff --git a/js/powerup.js b/js/powerup.js index a84de0c..8dc572d 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -223,7 +223,7 @@ const powerUps = { b.randomBot() if (tech.renormalization) { for (let i = 0; i < limit; i++) { - if (Math.random() < 0.37) { + if (Math.random() < 0.4) { m.fieldCDcycle = m.cycle + 30; powerUps.spawn(m.pos.x, m.pos.y, "research"); } @@ -234,7 +234,7 @@ const powerUps = { if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) { document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}` } - if (tech.renormalization && Math.random() < 0.37 && amount < 0) { + if (tech.renormalization && Math.random() < 0.4 && amount < 0) { for (let i = 0, len = -amount; i < len; i++) powerUps.spawn(m.pos.x, m.pos.y, "research"); } if (tech.isRerollHaste) { diff --git a/js/spawn.js b/js/spawn.js index de4f64b..773ec26 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -87,6 +87,19 @@ const spawn = { // other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool spawn[options[Math.floor(Math.random() * options.length)]](x, y) }, + secondaryBossChance(x, y) { + if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) { + spawn.randomLevelBoss(x, y); + } else if (tech.isResearchBoss) { + if (powerUps.research.count > 4) { + powerUps.research.changeRerolls(-5) + simulation.makeTextLog(`m.research -= 5
${powerUps.research.count}`) + } else { + tech.addJunkTechToPool(49) + } + spawn.randomLevelBoss(x, y); + } + }, //mob templates ********************************************************************************************* //*********************************************************************************************************** MACHO(x = m.pos.x, y = m.pos.y) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the player diff --git a/js/tech.js b/js/tech.js index c768d8b..70c800e 100644 --- a/js/tech.js +++ b/js/tech.js @@ -66,6 +66,7 @@ if (options.length) { for (let i = 0; i < num; i++) tech.tech[options[Math.floor(Math.random() * options.length)]].frequency++ } + simulation.makeTextLog(`tech.tech.push(${num} JUNK)`) }, removeJunkTechFromPool(num = 1) { for (let j = 0; j < num; j++) { @@ -77,11 +78,6 @@ } } }, - // removeJunkTechFromPool() { - // for (let i = tech.tech.length - 1; i > 0; i--) { - // if (tech.tech[i].isJunk && tech.tech[i].count === 0) tech.tech.splice(i, 1) - // } - // }, giveTech(index = 'random') { if (index === 'random') { let options = []; @@ -93,7 +89,6 @@ let newTech = options[Math.floor(Math.random() * options.length)] tech.giveTech(newTech) simulation.makeTextLog(`tech.giveTech("${tech.tech[newTech].name}") //random tech`); - } } else { if (isNaN(index)) { //find index by name @@ -704,6 +699,24 @@ tech.isRadioactive = false } }, + { + name: "water shielding", + description: "radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime", + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio + }, + requires: "neutron bomb or irradiated drones or iridium-192", + effect() { + tech.isRadioactiveResistance = true + }, + remove() { + tech.isRadioactiveResistance = false + } + }, { name: "iridium-192", description: "explosions release gamma radiation
100% more damage, but over 4 seconds", @@ -951,15 +964,15 @@ }, { name: "decorrelation", - description: "reduce harm by 66%
after not using your gun or field for 2 seconds", + description: "reduce harm by 66% after not activating
your gun or field for 2 seconds", maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return (b.totalBots() > 1 || tech.haveGunCheck("mine") || tech.haveGunCheck("spores") || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing") && !tech.isEnergyHealth + return ((m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" && (tech.blockingIce !== 0 || tech.blockDmg !== 0)) || b.totalBots() > 1 || tech.haveGunCheck("mine") || tech.haveGunCheck("spores") || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing") && !tech.isEnergyHealth }, - requires: "drones, spores, mines, or bots", + requires: "drones, spores, mines, or bots, ", effect() { tech.isNoFireDefense = true }, @@ -2244,7 +2257,7 @@ }, { name: "overcharge", - description: "increase your maximum energy by 60
add 10 JUNK tech to the potential pool", + description: "increase your maximum energy by 60
+10 JUNK to the potential tech pool", maxCount: 9, count: 0, frequency: 1, @@ -2266,7 +2279,7 @@ }, { name: "Maxwell's demon", - description: "energy above your max decays 92% slower
add 18 JUNK tech to the potential pool", + description: "energy above your max decays 92% slower
+18 JUNK to the potential tech pool", maxCount: 1, count: 0, frequency: 2, @@ -2712,7 +2725,7 @@ }, { name: "renormalization", - description: "using a research for any purpose
has a 37% chance to spawn a research", + description: "using a research for any purpose
has a 40% chance to spawn a research", maxCount: 1, count: 0, frequency: 2, @@ -2819,6 +2832,24 @@ }, remove() {} }, + { + name: "abiogenesis", + description: "at the start of a level spawn a 2nd boss for
5 research or +49 JUNK to the tech pool", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return (build.isExperimentSelection || powerUps.research.count > 4) && !tech.isDuplicateBoss + }, + requires: "at least 5 research and not parthenogenesis", + effect() { + tech.isResearchBoss = true; //abiogenesis + }, + remove() { + tech.isResearchBoss = false; + } + }, { name: "bubble fusion", description: "after destroying a mob's natural shield
spawn 1-2 heals, ammo, or research", @@ -2857,7 +2888,7 @@ }, { name: "replication", - description: "10% chance to duplicate spawned power ups
add 18 JUNK tech to the potential pool", + description: "10% chance to duplicate spawned power ups
+18 JUNK to the potential tech pool", maxCount: 9, count: 0, frequency: 1, @@ -2983,9 +3014,9 @@ frequency: 2, frequencyDefault: 2, allowed() { - return tech.duplicationChance() > 0 + return tech.duplicationChance() > 0 && !tech.isResearchBoss }, - requires: "some duplication chance", + requires: "some duplication chance, not abiogenesis", effect() { tech.isDuplicateBoss = true; }, @@ -3259,7 +3290,7 @@ }, { name: "dark patterns", - description: "reduce combat difficulty by 1 level
add 21 JUNK tech to the potential pool", + description: "reduce combat difficulty by 1 level
+21 JUNK to the potential tech pool", maxCount: 1, count: 0, frequency: 1, @@ -4058,25 +4089,6 @@ b.setGrenadeMode() } }, - { - name: "water shielding", - description: "radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime", - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio - }, - requires: "neutron bomb or irradiated drones or iridium-192", - effect() { - tech.isRadioactiveResistance = true - }, - remove() { - tech.isRadioactiveResistance = false - } - }, { name: "vacuum permittivity", description: "increase radioactive range by 20%
objects in range of the bomb are slowed", @@ -4155,7 +4167,7 @@ }, { name: "booby trap", - description: "drop a mine after picking up a power up
add 13 JUNK tech to the potential pool", + description: "drop a mine after picking up a power up
+13 JUNK to the potential tech pool", maxCount: 1, count: 0, frequency: 2, @@ -4410,6 +4422,25 @@ tech.droneRadioDamage = 1 } }, + { + name: "uncertainty principle", + description: "foam bubbles randomly change position
increase foam damage per second by 66%", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return !tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.foamBotCount > 1) + }, + requires: "foam, not electrostatic induction", + effect() { + tech.isFoamTeleport = true + }, + remove() { + tech.isFoamTeleport = false; + } + }, { name: "necrophoresis", description: "foam bubbles grow and split into 3 copies
when the mob they are stuck to dies", @@ -4450,25 +4481,6 @@ tech.foamGravity = 0.00008 } }, - { - name: "electrostatic induction", - description: "foam bullets are electrically charged
causing attraction to nearby mobs", - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.haveGunCheck("foam") || tech.foamBotCount > 1 - }, - requires: "foam", - effect() { - tech.isFoamAttract = true - }, - remove() { - tech.isFoamAttract = false - } - }, { name: "quantum foam", description: "foam gun fires 0.30 seconds into the future
increase foam gun damage by 90%", @@ -4507,6 +4519,25 @@ tech.isAmmoFoamSize = false; } }, + { + name: "electrostatic induction", + description: "foam bullets are electrically charged
causing attraction to nearby mobs", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return !tech.isFoamTeleport && (tech.haveGunCheck("foam") || tech.foamBotCount > 1) + }, + requires: "foam, not uncertainty", + effect() { + tech.isFoamAttract = true + }, + remove() { + tech.isFoamAttract = false + } + }, { name: "half-wave rectifier", description: "charging the rail gun gives you energy
instead of draining it", @@ -6454,7 +6485,7 @@ }, { name: "expert system", - description: "spawn a tech power up
add 64 JUNK tech to the potential pool", + description: "spawn a tech power up
+64 JUNK to the potential tech pool", maxCount: 9, count: 0, frequency: 0, @@ -6604,10 +6635,7 @@ ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -6652,10 +6680,7 @@ ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -6694,10 +6719,7 @@ ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, m.fillColorDark); - grd.addColorStop(1, m.fillColor); - ctx.fillStyle = grd; + ctx.fillStyle = this.bodyGradient ctx.fill(); ctx.strokeStyle = "#333"; ctx.lineWidth = 2; @@ -6909,7 +6931,7 @@ }, { name: "quantum black hole", - description: "use all your energy to spawn
inside the event horizon of a huge black hole", + description: "use your energy and 1 research to spawn
inside the event horizon of a huge black hole", maxCount: 9, count: 0, frequency: 0, @@ -6917,12 +6939,14 @@ isExperimentHide: true, isJunk: true, allowed() { - return true + return powerUps.research.count > 0 }, - requires: "", + requires: "at least 1 research", effect() { m.energy = 0 spawn.suckerBoss(m.pos.x, m.pos.y - 1000) + powerUps.research.changeRerolls(-1) + simulation.makeTextLog(`m.research --
${powerUps.research.count}`) }, remove() {} }, @@ -7267,5 +7291,7 @@ isBlockExplode: null, isOverHeal: null, isDroneRadioactive: null, - droneRadioDamage: null + droneRadioDamage: null, + isFoamTeleport: null, + isResearchBoss: null } \ No newline at end of file diff --git a/todo.txt b/todo.txt index abe42bd..f34fb9f 100644 --- a/todo.txt +++ b/todo.txt @@ -1,170 +1,19 @@ ******************************************************** NEXT PATCH ******************************************************** -irradiated drones - new tech: beta radiation - double damage and half lifespan - now don't clump as often, to make the graphics look better - effective radius now includes edges of mobs, not just centers - so they work better on large radius mobs - do 50% more damage, but have a 10% smaller radius and last 3 second shorter time and 80% less ammo (was 75%) - irradiated drones can't get a slowing effect anymore - it was just too annoying - nano-scale can now unlock irradiated drone tech properly - nano-scale now drains more energy per irradiated drone, to scale with the higher ammo costs +tech: abiogenesis - spawn a second level boss on each level, but costs 5 research or if you don't have the research add 49 JUNK tech to the pool + note to level builders I rewrote the add duplicate boss code in all levels: spawn.secondaryBossChance(x,y) -time dilation field is now just called "time dilation" -constraints under time dilation is less buggy, but still a bit buggy +foam tech: uncertainty principle - foam bullets change position randomly, increase foam damage by 66% -******************************************************** BUGS ******************************************************** - -player can become crouched while not touching the ground if they exit the ground while crouched - -a couple times people have reported the final boss dropping extra bodies on death - -Why does micro-extruder lag so much - -blue triangle boss can move backwards and aim away from you if set up properly - issues with dot product probably, but might not be worth fixing - -mouse event e.which is deprecated - -fix door.isOpen actually meaning isClosed? - -make it so that when you are immune to harm you can either jump on mobs or you pass through them - -is there a way to check if the player is stuck inside the map or block - trigger a short term non-collide if that occurs - -(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause - -******************************************************** LEVELS ******************************************************** - -labs - procedural generation - bugs - mob spawns shouldn't be based on probability? - style - graphics look too bright? - add shadows and lighting and graphic details? - what about performance? - with the mobs staggered spawning it should be fine - feel - disrupt the flat ground - less platforming / easier platforming - the spinners on exit are still too hard... - make combat more interesting - is it laggy? - in loot room, spawn mobs after power up is grabbed - more background graphics, better colors - loot room: - make it more interesting to get the power up - slow player and reduce damage in region - increase the size of the region - don't have space for much - make graphics more unique - push player away, so that normal pick up methods don't work, but add a button to disable region - room ideas - - portal room - endlessly falling blocks down a slide, that the player has to climb up - portal + rotor + falling blocks = perpetual motion - slime room - sound room, with buttons to control sound - color room with r,g,b buttons to control color - mob buff zone: Map element: "Orbital Pickup Zone": Mobs that enter a specific area of the map gain +1 orbital per second, or a shield - could put in the loot room - -buttons can now on/off boosts - -repeat map in vertical when you fall teleport to above the mab, as if the map repeats - camera looks strange when you teleport player with a high velocity - -map element - player rotates a rotor that makes a platform go up or down - -level element: a zone with wind, anti-gravity, extra gravity - control with button - -map: observatory - button controls rotation of telescope - laser beam shoots out of telescope - button opens the dome - -******************************************************** MOBS ******************************************************** - -mob mechanics - use the force at a location effect, like the plasma field - Matter.Body.applyForce(who, path[1], force) - -mob - after taking damage - release seekers - teleports - -hop boss: - AoE damage when landing - pull in player? and blocks? - extra gravity on falling? - immune to damage while falling? - -mob: molecule shapes - 2 separate mobs joined by a bond - use constraints: just spawn 2x or 3x groupings - low friction so they can spin around - spin when attacking player? - increase constraint length when attacking - -mob vision: look at player history - build a new type of attraction for mobs - if mobs can't see player, they check to see if they can see where the player was in the history - if mobs can't see player, they could check to see if they can find player in the past - https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding - write find in spawn undo exploder, but commented out - -Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage. - maybe it could be immune to damage? but it is spawned by an actual mob - -level Boss: fractal Sierpiński triangle - https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle - spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level - they spawn once at the start of the level - if a version dies, one can be replaced every ten seconds by the largest version - -give mobs more animal-like behaviors like rain world - mobs play, look for food, explore - mobs some times aren't aggressive - when low on life or after taking a large hit - mobs can fight each other - this might be hard to code - isolated mobs try to group up - -mob: wall mounted guns / lasers - not part of randomized mob pool, customized to each level - -level boss: fires a line intersection in a random direction every few seconds. - the last two intersections have a destructive laser between them. +throwing blocks now charges faster with reduced fire cooldown +tech renormalization now has a 40% chance to refund a research (was 37%) +performance- now precalculate player gradient fill ******************************************************** TODO ******************************************************** -tech - shorter cloaking delay - -irradiated drones, get annoying when they go after mobs near the player... - should they only follow mouse? or at least show a preference for targets near mouse, not near player - -tech - 1/2 your drone ammo/efficiency double the damage? - -tech foam teleports around, like a quantum wave function collapse - should ammo apply to all guns, or just one of your guns? if one gun only, it would make multi-gun builds weaker -nail bots should benefit from nail gun tech - -tech: picking up heal power ups at max health does harm, but increases max health - scales with heal value - -let standing wave harmonics get tech decorrelation - -tech: cloaking field - decrease/increase cooldown on sneak attack? - decrease/increase damage bonus? - decrease/increase visual radius? - -have throw charge scale with fire delay - in testing mode console log the body you click on throwing a block removes the block and rewinds time 10 seconds (including health and energy) @@ -174,8 +23,6 @@ tech plasma : plasma length increases then decreases as you hold down the field grows to 1.5 longer after 0.3 seconds, then returns to normal length over 1 second, until field is pressed again extra energy is drained when field is longer -tech: at the start of a new level remove 5 research and spawn a second boss - energy conservation 6% damage recovered as energy add a negative effect: junk tech @@ -335,6 +182,129 @@ n-gon outreach ideas hacker news - show hacker news post twitch - lets play +******************************************************** BUGS ******************************************************** + +player can become crouched while not touching the ground if they exit the ground while crouched + +a couple times people have reported the final boss dropping extra bodies on death + +Why does micro-extruder lag so much + +blue triangle boss can move backwards and aim away from you if set up properly + issues with dot product probably, but might not be worth fixing + +mouse event e.which is deprecated + +fix door.isOpen actually meaning isClosed? + +make it so that when you are immune to harm you can either jump on mobs or you pass through them + +is there a way to check if the player is stuck inside the map or block + trigger a short term non-collide if that occurs + +(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause + +******************************************************** LEVELS ******************************************************** + +labs - procedural generation + bugs + mob spawns shouldn't be based on probability? + style + graphics look too bright? + add shadows and lighting and graphic details? + what about performance? + with the mobs staggered spawning it should be fine + feel + disrupt the flat ground + less platforming / easier platforming + the spinners on exit are still too hard... + make combat more interesting + is it laggy? + in loot room, spawn mobs after power up is grabbed + more background graphics, better colors + loot room: + make it more interesting to get the power up + slow player and reduce damage in region + increase the size of the region + don't have space for much + make graphics more unique + push player away, so that normal pick up methods don't work, but add a button to disable region + room ideas - + portal room + endlessly falling blocks down a slide, that the player has to climb up + portal + rotor + falling blocks = perpetual motion + slime room + sound room, with buttons to control sound + color room with r,g,b buttons to control color + mob buff zone: Map element: "Orbital Pickup Zone": Mobs that enter a specific area of the map gain +1 orbital per second, or a shield + could put in the loot room + +buttons can now on/off boosts + +repeat map in vertical when you fall teleport to above the mab, as if the map repeats + camera looks strange when you teleport player with a high velocity + +map element - player rotates a rotor that makes a platform go up or down + +level element: a zone with wind, anti-gravity, extra gravity + control with button + +map: observatory + button controls rotation of telescope + laser beam shoots out of telescope + button opens the dome + +******************************************************** MOBS ******************************************************** + +mob mechanics + use the force at a location effect, like the plasma field + Matter.Body.applyForce(who, path[1], force) + +mob - after taking damage + release seekers + teleports + +hop boss: + AoE damage when landing + pull in player? and blocks? + extra gravity on falling? + immune to damage while falling? + +mob: molecule shapes - 2 separate mobs joined by a bond + use constraints: just spawn 2x or 3x groupings + low friction so they can spin around + spin when attacking player? + increase constraint length when attacking + +mob vision: look at player history + build a new type of attraction for mobs + if mobs can't see player, they check to see if they can see where the player was in the history + if mobs can't see player, they could check to see if they can find player in the past + https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding + write find in spawn undo exploder, but commented out + +Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage. + maybe it could be immune to damage? but it is spawned by an actual mob + +level Boss: fractal Sierpiński triangle + https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle + spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level + they spawn once at the start of the level + if a version dies, one can be replaced every ten seconds by the largest version + +give mobs more animal-like behaviors like rain world + mobs play, look for food, explore + mobs some times aren't aggressive + when low on life or after taking a large hit + mobs can fight each other + this might be hard to code + isolated mobs try to group up + +mob: wall mounted guns / lasers + not part of randomized mob pool, customized to each level + +level boss: fires a line intersection in a random direction every few seconds. + the last two intersections have a destructive laser between them. ******************************************************** LORE ******************************************************** @@ -342,7 +312,6 @@ possible names for tech strange loop holonomy - parallel transport of a vector leads to movement (applies to curved space) hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other. - uncertainty principle swarm intelligence - for a drone tech genetic algorithm metaheuristic - is a higher-level procedure or heuristic designed to find, generate, or select a heuristic (partial search algorithm) that may provide a sufficiently good solution to an optimization problem, especially with incomplete or imperfect information or limited computation capacity