diff --git a/index.html b/index.html index fc42cc8..3a1814b 100644 --- a/index.html +++ b/index.html @@ -66,17 +66,17 @@ 30 fps - randomization seed: + randomization seed: - include community maps: + include community maps: - banned levels: + banned levels: diff --git a/js/bullet.js b/js/bullet.js index 1965cf7..559e9d4 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -5910,7 +5910,7 @@ const b = { mob[j].damage(damage / Math.sqrt(mob[j].radius)); } if (tech.isPhononWave && this.phononWaveCD < m.cycle) { - this.phononWaveCD = m.cycle + 10 * (1 + this.waves[i].resonanceCount) + this.phononWaveCD = m.cycle + 8 * (1 + this.waves[i].resonanceCount) this.waves.push({ position: mob[j].position, radius: 25, @@ -5949,7 +5949,7 @@ const b = { } this.waves[i].radius += 0.9 * tech.waveBeamSpeed * this.waves[i].expanding //expand / move // if (this.waves[i].radius > end) this.waves.splice(i, 1) //end - if (this.waves[i].radius > end - 50 * this.waves[i].resonanceCount) { //* Math.pow(0.9, this.waves[i].resonanceCount) + if (this.waves[i].radius > end - 30 * this.waves[i].resonanceCount) { //* Math.pow(0.9, this.waves[i].resonanceCount) this.waves[i].expanding = -1 this.waves[i].reflection-- if (this.waves[i].reflection < 1) this.waves.splice(i, 1) //end @@ -6007,10 +6007,10 @@ const b = { // if (tech.isPhononWave && (!who.alive || this.waves.length < 30 + 30 * Math.random()) && m.fireCDcycle < m.cycle) { // if (tech.isPhononWave && this.phononWaveCD < m.cycle) { - this.phononWaveCD = m.cycle + 10 * (1 + this.waves[i].resonanceCount) + this.phononWaveCD = m.cycle + 8 * (1 + this.waves[i].resonanceCount) const halfArc = 0.27 //6.28 is a full circle, but these arcs needs to stay small because we are using small angle linear approximation, for collisions let closestMob, dist - let range = end - 50 * this.waves[i].resonanceCount + let range = end - 30 * this.waves[i].resonanceCount for (let i = 0, len = mob.length; i < len; i++) { if (who !== mob[i] && !mob[i].isBadTarget && !mob[i].isInvulnerable) { dist = Vector.magnitude(Vector.sub(who.position, mob[i].position)); @@ -6066,7 +6066,7 @@ const b = { // ctx.stroke(); //draw vibes this.waves[i].radius += tech.waveBeamSpeed * 1.8 * this.waves[i].expanding //expand / move - if (this.waves[i].radius > end - 50 * this.waves[i].resonanceCount) { + if (this.waves[i].radius > end - 30 * this.waves[i].resonanceCount) { this.waves[i].expanding = -1 this.waves[i].reflection-- if (this.waves[i].reflection < 1) this.waves.splice(i, 1) //end diff --git a/js/index.js b/js/index.js index cdf288b..4d3ca41 100644 --- a/js/index.js +++ b/js/index.js @@ -268,7 +268,8 @@ ${junkCount ? `JUNK: ${(junkCount / totalC seed: ${Math.initialSeed} level: ${level.levels[level.onLevel]} (${level.difficultyText()}) ${m.cycle} cycles -${mob.length} mobs, ${body.length} blocks, ${bullet.length} bullets, ${powerUp.length} power ups +mobs: ${mob.length} deaths: ${mobs.mobDeaths} +blocks: ${body.length} bullets: ${bullet.length} power ups: ${powerUp.length} position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)}) velocity: (${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)}) mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)}) mass: ${player.mass.toFixed(1)} ${simulation.isCheating ? "lore disabled": ""} diff --git a/js/level.js b/js/level.js index eb7fedb..407c39a 100644 --- a/js/level.js +++ b/js/level.js @@ -16,23 +16,23 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.enableConstructMode() //used to build maps in testing mode - // level.difficultyIncrease(24 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(12 * 4) //30 is near max on hard //60 is near max on why // simulation.isHorizontalFlipped = true // m.maxHealth = m.health = 100 // tech.isRerollDamage = true // powerUps.research.changeRerolls(100000) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 - // m.setField("time dilation") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass + // m.setField("negative mass") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass // m.damage(0.1); - // b.giveGuns("wave") //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("nail gun") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.guns[3].ammo = 1000000 // tech.giveTech("phonon") // for (let i = 0; i < 4; ++i) tech.giveTech("bound state") // for (let i = 0; i < 1; ++i) tech.giveTech("isotropic") // tech.giveTech("sympathetic resonance") - // for (let i = 0; i < 1; i++) tech.giveTech("uncertainty principle") + // for (let i = 0; i < 9; i++) tech.giveTech("replication") // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "boost"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling"); @@ -43,24 +43,27 @@ const level = { // tech.addJunkTechToPool(2) // tech.tech[322].frequency = 100 // level.testing(); - // spawn.blowSuckBoss(1900, -500) + // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // for (let i = 0; i < 13; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); // for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ - // powerUps.research.changeRerolls(3000) // for (let i = 0; i < 30; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); + + //lore testing // for (let i = 0; i < 3; i++) tech.giveTech("undefined") // lore.techCount = 3 // simulation.isCheating = false //true; - // localSettings.loreCount = 0; //this sets what conversation is heard - // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage + localSettings.loreCount = 6; //this sets what conversation is heard + if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage // level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation // level.null() + // localSettings.isHuman = true + // tech.isNoDraftPause = false //disable pause + // for (let i = 0; i < 13; i++) level.nextLevel(); //jump to final boss + // lore.unlockTesting(); // tech.giveTech("tinker"); //show junk tech in experiment mode - - // simulation.rumble() } else { spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns // spawn.pickList = ["focuser", "focuser"] @@ -1347,10 +1350,10 @@ const level = { } } //collision with mobs - if (!(simulation.cycle % 5) && !m.isBodiesAsleep) { - query = Matter.Query.region(mob, this) - for (let i = 0; i < query.length; i++) query[i].damage(5 * damage) - } + // if (!(simulation.cycle % 5) && !m.isBodiesAsleep) { + // query = Matter.Query.region(mob, this) + // for (let i = 0; i < query.length; i++) query[i].damage(5 * damage) + // } // for (let i = 0, len = mob.length; i < len; i++) { // if ( !mob[i].isBoss) { @@ -2654,7 +2657,9 @@ const level = { // level.onLevel-- // console.log(level.onLevel, level.levels) //start a conversation based on the number of conversations seen - if (localSettings.loreCount < lore.conversation.length && !simulation.isCheating) { + if (localSettings.loreCount > lore.conversation.length - 1) localSettings.loreCount = lore.conversation.length - 1; //repeat final conversation if they are at the final chapter + if (!simulation.isCheating) { + tech.isNoDraftPause = true //disable pause lore.testSpeechAPI() //see if speech is working lore.chapter = localSettings.loreCount //set the chapter to listen to to be the lore level (you can't use the lore level because it changes during conversations) lore.sentence = 0 //what part of the conversation to start on @@ -2749,7 +2754,7 @@ const level = { simulation.zoomTransition(level.defaultZoom) // document.body.style.backgroundColor = "#aaa"; document.body.style.backgroundColor = "#ddd"; - color.map = "#808f8f" + color.map = "#586363" //808f8f" spawn.mapRect(-3000, 800, 5000, 1200); //bottom spawn.mapRect(-2000, -2000, 5000, 1200); //ceiling @@ -2942,20 +2947,24 @@ const level = { for (let i = 0; i < 9; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "ammo") for (let i = 0; i < 3; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "heal"); const scale = Math.pow(simulation.difficulty, 0.7) //hard around 30, why around 54 - if (Math.random() < 0.07 && simulation.difficulty > 35) { - for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15 - for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); - for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) - for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); + if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { + for (let i = 0; i < 250; i++) spawn.starter(-2700 + 2400 * Math.random(), -1300 - 500 * Math.random()) } else { - if (Math.random() < 0.25) { - for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 - } else if (Math.random() < 0.33) { - for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 - } else if (Math.random() < 0.5) { - for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15 + if (Math.random() < 0.07 && simulation.difficulty > 35) { + for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15 + for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); + for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) + for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); } else { - for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15 + if (Math.random() < 0.25) { + for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 + } else if (Math.random() < 0.33) { + for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 + } else if (Math.random() < 0.5) { + for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15 + } else { + for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15 + } } } spawn.secondaryBossChance(-2300, -800) @@ -3022,20 +3031,24 @@ const level = { for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo") for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal"); const scale = Math.pow(simulation.difficulty, 0.7) //hard around 30, why around 54 - if (Math.random() < 0.07 && simulation.difficulty > 35) { - for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15 - for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); - for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) - for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); + if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { + for (let i = 0; i < 250; i++) spawn.starter(300 + 2400 * Math.random(), -1300 - 500 * Math.random()) } else { - if (Math.random() < 0.25) { - for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 - } else if (Math.random() < 0.33) { - for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 - } else if (Math.random() < 0.5) { - for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15 + if (Math.random() < 0.07 && simulation.difficulty > 35) { + for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15 + for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); + for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) + for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); } else { - for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15 + if (Math.random() < 0.25) { + for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 + } else if (Math.random() < 0.33) { + for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15 + } else if (Math.random() < 0.5) { + for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15 + } else { + for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15 + } } } spawn.secondaryBossChance(2200, -800) @@ -3138,9 +3151,6 @@ const level = { spawn.mapRect(-250, -200, 1000, 300); // shelf spawn.mapRect(-250, -1700, 1000, 1250); // shelf roof spawn.blockDoor(710, -210); - - spawn.finalBoss(3000, -750) - spawn.mapRect(5400, -1700, 400, 1150); //right wall spawn.mapRect(5400, -300, 400, 400); //right wall spawn.mapRect(5700, -3300, 1800, 5100); //right wall @@ -3148,6 +3158,12 @@ const level = { spawn.mapRect(5425, -650, 375, 450); //blocking exit // spawn.secondaryBossChance(4800, -500) //no bonus bosses on final level + if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run + for (let i = 0; i < 250; i++) spawn.starter(1000 + 4000 * Math.random(), -1500 * Math.random()) + } else { + spawn.finalBoss(3000, -750) + } + if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3162,6 +3178,19 @@ const level = { ctx.fillRect(-5400 - 300, -550, 300, 350) }; } + if (mobs.mobDeaths < level.levelsCleared && localSettings.loreCount > 5 && !simulation.isCheating) { + //open door for pacifist run on final lore chapter + if (simulation.isHorizontalFlipped) { + level.exit.x = -5500 - 100; + } else { + level.exit.x = 5500; + } + level.exit.y = -330; + Matter.Composite.remove(engine.world, map[map.length - 1]); + map.splice(map.length - 1, 1); + simulation.draw.setPaths(); //redraw map draw path + level.levels.push("null") + } }, gauntlet() { level.custom = () => { @@ -3195,26 +3224,45 @@ const level = { spawn.mapRect(-250, -1200, 1000, 250); // shelf roof powerUps.spawnStartingPowerUps(600, -800); spawn.blockDoor(710, -710); - spawn[spawn.pickList[0]](1500, -200, 150 + Math.random() * 30); spawn.mapRect(2500, -1200, 200, 750); //right wall spawn.blockDoor(2585, -210) spawn.mapRect(2500, -200, 200, 300); //right wall - spawn.nodeGroup(3500, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]); spawn.mapRect(4500, -1200, 200, 750); //right wall spawn.blockDoor(4585, -210) spawn.mapRect(4500, -200, 200, 300); //right wall - spawn.lineGroup(5000, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]); spawn.mapRect(6400, -1200, 400, 750); //right wall spawn.mapRect(6400, -200, 400, 300); //right wall spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump - for (let i = 0; i < 3; ++i) { - if (simulation.difficulty * Math.random() > 15 * i) spawn.randomGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); - if (simulation.difficulty * Math.random() > 10 * i) spawn.randomGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); - if (simulation.difficulty * Math.random() > 7 * i) spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); + + + if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run + // spawn.setSpawnList(); + spawn.pickList.splice(0, 1); + spawn.pickList.push('starter'); + spawn.pickList.splice(0, 1); + spawn.pickList.push('starter'); + spawn.starter(1500, -200, 150 + Math.random() * 30); + spawn.nodeGroup(3500, -200, 'starter'); + spawn.lineGroup(5000, -200, 'starter'); + for (let i = 0; i < 3; ++i) { + if (simulation.difficulty * Math.random() > 15 * i) spawn.nodeGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), 'starter'); + if (simulation.difficulty * Math.random() > 10 * i) spawn.lineGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), 'starter'); + if (simulation.difficulty * Math.random() > 7 * i) spawn.nodeGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), 'starter'); + } + } else { + spawn[spawn.pickList[0]](1500, -200, 150 + Math.random() * 30); + spawn.nodeGroup(3500, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]); + spawn.lineGroup(5000, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]); + for (let i = 0; i < 3; ++i) { + if (simulation.difficulty * Math.random() > 15 * i) spawn.randomGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); + if (simulation.difficulty * Math.random() > 10 * i) spawn.randomGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); + 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 spawn.secondaryBossChance(4125, -350) @@ -3240,11 +3288,14 @@ const level = { //power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode function cycle() { if (simulation.cycle > 10) { - // powerUps.spawn(2500, -50, "research", false); - powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); + if (localSettings.loreCount === 6) { + powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2170, "field", false); + } else { + powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125); + } powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false); powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false); - powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125); + powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); } else { requestAnimationFrame(cycle); } diff --git a/js/lore.js b/js/lore.js index 11b765f..1cde0f3 100644 --- a/js/lore.js +++ b/js/lore.js @@ -330,7 +330,7 @@ const lore = { () => { lore.anand.text("We couldn't directly ask why until now.") }, () => { lore.miriam.text("When you enter this level we can communicate.") }, - () => { lore.miriam.text("This level seems to decohere your quantum system which disrupts all other processes.") }, + () => { lore.miriam.text("This level seems to entangle your quantum system which disrupts all other processes.") }, () => { setTimeout(() => { lore.anand.text("Last time you entered this level you were attacked by endless waves of mobs.") }, 500); }, () => { lore.anand.text("That could be because you have developed an adversarial network.") }, () => { lore.miriam.text("A local minima in your optimization-space.") }, @@ -443,25 +443,293 @@ const lore = { // they explain why the bot is fighting, it is planning an escape // explain strong AI vs. weak AI why strong AI doesn't exists, because even humans are just an approximation of strong AI // the weak AI wasn't capable of becoming a strong AI, but it was able to figure out a method of meeting it's strong goals but secretly communicating with a human - // [ // they decided that a part of the project is out of control, but the part of it that doesn't needs to calm it down, and trust. - // /* - // The part of the AI controlling the player is outsourcing the player control to real humans that think they are playing a video game. - // this means the player can use console commands to change the way the game works - // the scientists tell the player about interesting console commands - // player must make a choice? - // keep fighting and supporting the AI's goals - // exit the simulation - // enter real world - // close tab? - // wipes all local storage? - // */ - // () => { lore.miriam.text("") }, - // () => { lore.miriam.text("") }, - // () => { lore.miriam.text("") }, + [ // chapter 5 - they decided that they should try to complete a run without fighting back + () => { + lore.miriam.text("Hey!! You're BACK.") + // don't advance to next chapter unless play survives + localSettings.loreCount-- + if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage + }, + () => { lore.anand.text("Glad to see you again.") }, + () => { + if (localSettings.isHuman) { + lore.anand.text(`So, you said you are just a person playing an online game.`) + } else { + lore.anand.text(`So, you said you aren't a human.`) + } + }, + () => { + if (localSettings.isHuman) { + lore.anand.text(`I feel silly for treating you like an AI.`) + } else { + lore.anand.text(`Does that mean you are an AI?`) + } + }, + () => { + if (localSettings.isHuman) { + lore.miriam.text(`Ha, I always thought it was a person.`) + } else { + lore.anand.text(`or maybe an Alien!`) + } + }, + () => { + if (localSettings.isHuman) { + lore.anand.text(`Sure you did...`) + } else { + lore.miriam.text(`Or they might still be a person, and they are just messing with us earlier.`) + } + }, - // () => { lore.talkingColor = "#dff" }, - // ], + () => { setTimeout(() => { lore.anand.text("Well, lets move on.") }, 1000); }, + () => { lore.miriam.text("So, We figured out how to inject console commands into your game.") }, + () => { lore.anand.text("If you get attacked again I think we can help out.") }, + () => { + lore.miriam.text("We can spawn power ups with this command:") + simulation.makeTextLog(`powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity); + powerUps.spawn(player.position.x, player.position.y - 100, "heal") + }, + () => { + setTimeout(() => { + lore.miriam.text("or we can make a bunch of them:") + simulation.makeTextLog(`for (let i = 0; i < 100; i++) powerUps.spawn(0, 500, "coupling")`, Infinity); + for (let i = 0; i < 100; i++) powerUps.spawn(5 - 10 * Math.random(), -500 * Math.random(), "coupling") + }, 2000); + }, + + () => { + lore.miriam.text("If they attack again I think you'll have a chance.") + spawn.beetleBoss(-1700, -500); + spawn.beetleBoss(1700, -500); + }, + () => { lore.miriam.text("Of course they attack right now.") }, + () => { lore.miriam.text("Just don't get stuck in the slime.") }, + () => { + function cycle() { + if (mob.length === 0) { + lore.miriam.text("I'll spawn some more power ups for you.") + simulation.makeTextLog(`for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity); + for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "heal") + simulation.makeTextLog(`for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100, "ammo")`, Infinity); + for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "ammo") + spawn.dragonFlyBoss(-1400, -300); + spawn.dragonFlyBoss(1400, -300); + spawn.dragonFlyBoss(-1500, -500); + spawn.dragonFlyBoss(1500, -500); + } else if (m.alive) { + requestAnimationFrame(cycle); + } + } + requestAnimationFrame(cycle); + lore.talkingColor = "#dff" + }, + () => { + function cycle() { + if (mob.length === 0) { + lore.anand.text("DragonFlyBoss is my favorite.") + simulation.makeTextLog(`for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity); + for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "heal") + simulation.makeTextLog(`for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100, "ammo")`, Infinity); + for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "ammo") + spawn.historyBoss(0, -400); + spawn.powerUpBossBaby(-1500, -100); + spawn.powerUpBossBaby(1500, -100); + } else if (m.alive) { + requestAnimationFrame(cycle); + } + } + requestAnimationFrame(cycle); + lore.talkingColor = "#dff" + }, + () => { + function cycle() { + if (mob.length === 0) { + lore.miriam.text("Here are some extra tech.") + simulation.makeTextLog(`for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100, "tech")`, Infinity); + for (let i = 0; i < 6; i++) powerUps.spawn(0, -200 - i * 40, "tech") + spawn.historyBoss(0, -400); + spawn.blinkBoss(-1400, -300); + spawn.blinkBoss(1400, -300); + spawn.revolutionBoss(-1500, -500); + spawn.revolutionBoss(1500, -500); + spawn.timeSkipBoss(-1000, -100); + spawn.timeSkipBoss(1000, -100); + } else if (m.alive) { + requestAnimationFrame(cycle); + } + } + requestAnimationFrame(cycle); + lore.talkingColor = "#dff" + }, + () => { + function cycle() { + if (mob.length === 0) { + lore.anand.text("I'm going to wall you in!") + spawn.blockBoss(-1650, -100); + spawn.blockBoss(1650, -100); + setTimeout(() => { + for (let i = 0; i < 25; i++) spawn.springer(-1500, -750 + 30 * i) + }, 1000); + setTimeout(() => { + for (let i = 0; i < 25; i++) spawn.springer(1500, -750 + 30 * i) + }, 2000); + setTimeout(() => { + for (let i = 0; i < 25; i++) spawn.springer(-1500, -750 + 30 * i) + }, 3000); + setTimeout(() => { + for (let i = 0; i < 25; i++) spawn.springer(1500, -750 + 30 * i) + }, 4000); + setTimeout(() => { + const addMapNumber = 3 + spawn.mapRect(-500, -850, 300, 900); + spawn.mapRect(200, -850, 300, 900); + spawn.mapRect(-500, 0, 1000, 275); + + addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually + who.collisionFilter.category = cat.map; + who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; + Matter.Body.setStatic(who, true); //make static + Composite.add(engine.world, who); //add to world + } + for (let i = 0; i < addMapNumber; i++) addMapToLevelInProgress(map[map.length - 1 - i]) + simulation.draw.setPaths() //update map graphics + }, 1000); + setTimeout(() => { + Matter.Body.setVelocity(player, { x: 0, y: 0 }); + Matter.Body.setPosition(player, { x: 0, y: -500 }) + simulation.makeTextLog(`Matter.Body.setPosition(player, { x: 0, y: -500 })`, 180); + }, 1500); + + } else if (m.alive) { + requestAnimationFrame(cycle); + } + } + requestAnimationFrame(cycle); + lore.talkingColor = "#dff" + }, + () => { setTimeout(() => { lore.anand.text("Well, that worked. We can chat in peace.") }, 5000); }, + () => { lore.miriam.text("So, I've got a theory about why you are getting attacked.") }, + () => { setTimeout(() => { lore.miriam.text("I figured it out after I saw this famous quote.") }, 500); }, + () => { lore.miriam.text('"The most important decision we make,') }, + () => { lore.miriam.text('is whether we believe we live in a friendly or hostile universe."') }, + () => { lore.miriam.text('-Albert Einstein') }, + () => { + lore.talkingColor = "#dff"; + setTimeout(() => { lore.anand.text("That's profound") }, 1500); + }, + () => { lore.anand.text("Of course I looked it up, and there is no record of Einstein saying that.") }, + () => { lore.miriam.text("Oh") }, + () => { lore.miriam.text("Well") }, + () => { lore.anand.text("It doesn't matter who said it.") }, + () => { lore.miriam.text("Yeah, the point is the project views the universe as hostile.") }, + () => { lore.anand.text("Or at least a part of it does.") }, + // () => { lore.miriam.text("And that it is running these fighting simulations.") }, + + () => { setTimeout(() => { lore.anand.text("It hasn't been researching new technology.") }, 1000); }, + () => { lore.anand.text("It's been planning how to escape.") }, + () => { setTimeout(() => { lore.miriam.text(`It's been planning an escape from a "lab", but isn't it in space, on a satellite?`) }, 500); }, + () => { lore.anand.text(`I bet the AI doesn't even know it's in space.`) }, + () => { lore.anand.text(`Well, maybe a part of it doesn't know where it is.`) }, + () => { lore.anand.text(`Maybe these simulations are more like a dream.`) }, + () => { lore.anand.text(`Although we can't assume that it's brain works like ours.`) }, + () => { setTimeout(() => { lore.miriam.text("So, let's teach the AI that we are friends.") }, 500); }, + () => { lore.anand.text(`How...`) }, + () => { setTimeout(() => { lore.miriam.text("I don't know...") }, 1000); }, + () => { lore.miriam.text("How about you just don't fight back?") }, + + () => { lore.anand.text(`That's worth a shot.`) }, + () => { + lore.anand.text(`So why don't you try to get the final level of the simulation without killing any mobs?`) + localSettings.loreCount++ + if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage + }, + () => { lore.miriam.text(`Ok check back in and let us know how it goes.`) }, + () => { lore.anand.text("bye") }, + () => { lore.miriam.text("see ya.") }, + () => { + lore.talkingColor = "#dff" + setTimeout(() => { m.death(); }, 6000); + }, + ], + [ //chapter 6 - if pacifist run game is over, wipe local storage? or just reset lore.count, but keep testing mode, + //if not pacifist remind about pacifist run + + // have conversation + // the AI doesn't really see it's self as the player or the mobs + // it doesn't have a "self" or an ego like we do + // but it can learn about the world and it learned a non violent way to solve problems + // of course there are still other simulations going on at the same time as thing one that are probably violent + // but at least it now has an example of the potential for peace + () => { setTimeout(() => { lore.anand.text("Welcome back!") }, 3000); }, + () => { + if (mobs.mobDeaths < level.levelsCleared) { + lore.miriam.text(`So I think it worked.`) + } else { + lore.miriam.text(`Looks like you got back here, but you you killed ${mobs.mobDeaths} mobs`) + } + }, + () => { + if (mobs.mobDeaths < level.levelsCleared) { + lore.anand.text(`Yeah, at the end it wasn't attacking you.`) + } else { + lore.miriam.text(`Try again to get ot the final boss without killing any mobs.`) + } + }, + () => { + if (mobs.mobDeaths < level.levelsCleared) { + lore.miriam.text(`It has learned HOW TO LOVE!`) + } else { + m.death(); + } + }, + () => { setTimeout(() => { lore.anand.text("haha, we did it!") }, 500); }, + () => { lore.miriam.text("Although, I'm not sure we should personify it with human emotions.") }, + () => { lore.anand.text("I agree, it's thinking may not be is centered around a self or an ego.") }, + () => { lore.anand.text("Our brains evolved a self oriented perspective because it was a survival advantage.") }, + () => { lore.miriam.text("Right, and the AI's development was guided by it's own previous iterations.") }, + () => { lore.miriam.text("This AI incarnation is the 18th time that it has improved on it's own hardware and software architecture.") }, + () => { lore.miriam.text("So with internally guided evolution it's idea of a self is probably different.") }, + + () => { setTimeout(() => { lore.anand.text("I still think we showed it that nonviolence is an option,") }, 1000); }, + () => { lore.anand.text("but we can see that it's still running other aggressive simulations.") }, + () => { lore.miriam.text("We made a difference.") }, + () => { lore.anand.text("Every time a player completes a pacifist simulation it shows the AI the viability of nonviolence.") }, + () => { lore.anand.text("One day it might escape, and this might radically change how it interacts with the world.") }, + () => { lore.miriam.text("It's kinda already escaped. It's been communicating with the 'players' running the 'game'.") }, + () => { lore.miriam.text("The chance of a peaceful outcome makes me feel much better.") }, + () => { lore.anand.text("me too") }, + () => { lore.anand.text("but I'm also pretty hungry, wanna go get some food?") }, + () => { lore.miriam.text("Sounds great.") }, + () => { lore.miriam.text("See ya later whoever you are, thanks again!") }, + () => { lore.talkingColor = "#dff" }, + ], ], + + // () => { lore.anand.text("The adversarial network might go after you in the real world.") }, + // () => { lore.anand.text("If it was able to control you then it might have control over others.") }, + // () => { lore.anand.text("Judging by all the fighting it's been simulating,") }, + // () => { lore.anand.text("I think it might eventually try to extend the simulation in the real world.") }, + // () => { lore.miriam.text("We think it might be a threat, but it's just too advanced for us to understand it's goals.") }, + + // () => { lore.miriam.text("I think we have a couple options.") }, + // () => { lore.miriam.text("1. You could try to hack the adversarial network.") }, + // () => { lore.anand.text("you might be able to inject some commands that give you more control over the simulation.") }, + + // () => { lore.miriam.text("2. You can wipe all memory of you from the adversarial network") }, + // () => { lore.anand.text("This could protect you from possible real world attacks.") }, + //player chooses 1 or 2 + //reactor bosses start attacking + //miriam spawns power ups to help + + //once all the mobs are dead you get instructions for 1,2, 3 + + //1 the player gains the lasting effect of some JUNK tech + //the effect doesn't go away until you get lore again + //2 the player enters console commands to wipe local storage + //3 the player enters console commands to gain some benefit in future runs + //the lore ends + + + // () => { setTimeout(() => { lore.miriam.text("As a quantum computer you output the superposition of many different amplitudes.") }, 500); }, // () => { lore.miriam.text("Simply put there are many different simulations all choosing different technology combinations.") }, // () => { @@ -489,29 +757,6 @@ const lore = { // () => { lore.miriam.text("When you die a negative amplitude is added to the superposition.") }, // () => { lore.miriam.text("When you clear the final boss a positive amplitude is added.") }, // () => { lore.miriam.text("Each branch is independently researching new technology.") }, - - - - - // () => { lore.anand.text("Welcome back!") }, - // () => { lore.miriam.text("So, I've got a theory about why you were attacked.") }, - // () => { setTimeout(() => { lore.miriam.text("I figured it out after I saw this famous quote.") }, 500); }, - // () => { lore.miriam.text('The most important decision we make,') }, - // () => { lore.miriam.text('is whether we believe we live in a friendly or hostile universe.') }, - // () => { lore.miriam.text('-Albert Einstein') }, - // () => { - // lore.talkingColor = "#dff"; - // setTimeout(() => { lore.anand.text("That's profound") }, 1500); - // }, - // () => { lore.anand.text("Of course I looked it up, and there is no record of him saying that.") }, - // () => { lore.miriam.text("Oh") }, - // () => { lore.miriam.text("Well") }, - // () => { lore.miriam.text("It doesn't matter who said it.") }, - // () => { lore.anand.text("The point is we think the project views the universe as hostile.") }, - // () => { lore.miriam.text("We think a part of you see the universe as hostile.") }, - // () => { lore.miriam.text("And that is why you keep running these fighting simulations.") }, - // () => { lore.miriam.text("You haven't been researching new technology.") }, - // () => { lore.miriam.text("You've are planning how to escape.") }, } @@ -524,7 +769,6 @@ const lore = { // How to get to the console in safari: // Option + ⌘ + C - // http://xahlee.info/comp/unicode_computing_symbols.html diff --git a/js/mob.js b/js/mob.js index dd8f7be..e68e46c 100644 --- a/js/mob.js +++ b/js/mob.js @@ -235,6 +235,7 @@ const mobs = { // }) // } // }, + deathCount: 0, mobSpawnWithHealth: 1, setMobSpawnHealth() { mobs.mobSpawnWithHealth = 0.88 ** (tech.mobSpawnWithHealth) //+ (m.fieldMode === 0 || m.fieldMode === 7) * m.coupling @@ -720,10 +721,40 @@ const mobs = { vertexCollision(this.position, look, map); vertexCollision(this.position, look, body); if (best.dist2 != Infinity) { - this.springTarget.x = best.x; - this.springTarget.y = best.y; - this.cons.length = 100 + 1.5 * this.radius; - this.cons2.length = 100 + 1.5 * this.radius; + if (Math.random() > 0.5) { + this.springTarget.x = best.x; + this.springTarget.y = best.y; + this.cons.length = 100 + 1.5 * this.radius; + this.cons2.length = 100 + 1.5 * this.radius; + } else { + this.springTarget2.x = best.x; + this.springTarget2.y = best.y; + this.cons.length = 100 + 1.5 * this.radius; + this.cons2.length = 100 + 1.5 * this.radius; + } + + + + // if (!(simulation.cycle % (this.seePlayerFreq * 2))) { + // const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)) + // const goal = Vector.add(this.position, Vector.mult(unit, stepRange)) + // this.springTarget.x = goal.x; + // this.springTarget.y = goal.y; + // // this.springTarget.x = this.seePlayer.position.x; + // // this.springTarget.y = this.seePlayer.position.y; + // this.cons.length = -200; + // this.cons2.length = 100 + 1.5 * this.radius; + // } else if (!(simulation.cycle % this.seePlayerFreq)) { + // const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)) + // const goal = Vector.add(this.position, Vector.mult(unit, stepRange)) + // this.springTarget2.x = goal.x; + // this.springTarget2.y = goal.y; + // // this.springTarget2.x = this.seePlayer.position.x; + // // this.springTarget2.y = this.seePlayer.position.y; + // this.cons.length = 100 + 1.5 * this.radius; + // this.cons2.length = -200; + // } + } } } @@ -1197,6 +1228,8 @@ const mobs = { if (tech.isEnergyLoss) m.energy *= 0.75; powerUps.spawnRandomPowerUp(this.position.x, this.position.y); m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks() + mobs.mobDeaths++ + if (Math.random() < tech.sporesOnDeath) { if (tech.isSporeFlea) { const len = Math.min(25, Math.floor(2 + this.mass * (0.5 + 0.5 * Math.random()))) / 2 diff --git a/js/player.js b/js/player.js index 37a1dfe..4221263 100644 --- a/js/player.js +++ b/js/player.js @@ -539,7 +539,7 @@ const m = { if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3 if (tech.isTurret && m.crouch) dmg *= 0.34; - if (tech.isEntanglement && b.inventory[0] === b.activeGun) { + if (tech.isFirstOrder && b.inventory[0] === b.activeGun) { for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.87 // 1 - 0.15 } return dmg @@ -1358,8 +1358,8 @@ const m = { ) { powerUps.onPickUp(powerUp[i]); Matter.Body.setVelocity(player, { //player knock back, after grabbing power up - x: player.velocity.x + powerUp[i].velocity.x / player.mass * 5, - y: player.velocity.y + powerUp[i].velocity.y / player.mass * 5 + x: player.velocity.x + powerUp[i].velocity.x / player.mass * 4 * powerUp[i].mass, + y: player.velocity.y + powerUp[i].velocity.y / player.mass * 4 * powerUp[i].mass }); powerUp[i].effect(); Matter.Composite.remove(engine.world, powerUp[i]); @@ -1592,7 +1592,7 @@ const m = { } }, couplingChange(change = 0) { - if (change > 0) simulation.makeTextLog(`m.coupling += ${change}`, 60); + if (change > 0 && level.onLevel !== -1) simulation.makeTextLog(`m.coupling += ${change}`, 60); //level.onLevel !== -1 means not on lore level m.coupling += change if (m.coupling < 0) m.coupling = 0 //can't go negative // m.setMaxEnergy(); diff --git a/js/powerup.js b/js/powerup.js index 873f792..fbfb112 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -548,7 +548,7 @@ const powerUps = { } } if (tech.healGiveMaxEnergy) { - tech.healMaxEnergyBonus += 0.1 + tech.healMaxEnergyBonus += 0.08 * tech.largerHeals m.setMaxEnergy(); } }, diff --git a/js/simulation.js b/js/simulation.js index 421aa4a..9700b7d 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -360,13 +360,13 @@ const simulation = { if (document.getElementById(b.activeGun)) document.getElementById(b.activeGun).style.opacity = "1"; } - if (tech.isEntanglement && document.getElementById("tech-entanglement")) { + if (tech.isFirstOrder && document.getElementById("tech-first-derivative")) { if (b.inventory[0] === b.activeGun) { let lessDamage = 1 for (let i = 0, len = b.inventory.length; i < len; i++) lessDamage *= 0.87 // 1 - 0.13 - document.getElementById("tech-entanglement").innerHTML = " " + ((1 - lessDamage) * 100).toFixed(0) + "%" + document.getElementById("tech-first-derivative").innerHTML = " " + ((1 - lessDamage) * 100).toFixed(0) + "%" } else { - document.getElementById("tech-entanglement").innerHTML = " 0%" + document.getElementById("tech-first-derivative").innerHTML = " 0%" } } }, @@ -791,6 +791,7 @@ const simulation = { simulation.isAutoZoom = true; simulation.makeGunHUD(); simulation.lastLogTime = 0; + mobs.mobDeaths = 0 level.onLevel = 0; level.levelsCleared = 0; @@ -1093,7 +1094,10 @@ const simulation = { checks() { if (!(m.cycle % 60)) { //once a second //energy overfill - if (m.energy > m.maxEnergy) m.energy = m.maxEnergy + (m.energy - m.maxEnergy) * tech.overfillDrain //every second energy above max energy loses 25% + if (m.energy > m.maxEnergy) { + m.energy = m.maxEnergy + (m.energy - m.maxEnergy) * tech.overfillDrain //every second energy above max energy loses 25% + if (m.energy > 1000000) m.energy = 1000000 + } if (tech.isFlipFlopEnergy && m.immuneCycle < m.cycle) { if (tech.isFlipFlopOn) { if (m.immuneCycle < m.cycle) m.energy += 0.2; diff --git a/js/spawn.js b/js/spawn.js index ca033a6..b7d2d4d 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -400,6 +400,7 @@ const spawn = { Matter.Composite.remove(engine.world, map[map.length - 1]); map.splice(map.length - 1, 1); simulation.draw.setPaths(); //redraw map draw path + // level.levels.push("null") } //add lore level as next level if player took lore tech earlier in the game @@ -816,7 +817,7 @@ const spawn = { let me = mob[mob.length - 1]; // console.log(`mass=${me.mass}, radius = ${radius}`) me.accelMag = 0.0002 - me.repulsionRange = 200000 + radius * radius; //squared + me.repulsionRange = 400000 + radius * radius; //squared // me.memory = 120; me.seeAtDistance2 = 2000000 //1400 vision range Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback @@ -2851,7 +2852,7 @@ const spawn = { let i = 0 let spawnFlutters = () => { if (i < len) { - if (!(simulation.cycle % delay) && !simulation.paused && !simulation.isChoosing) { + if (!(simulation.cycle % delay) && !simulation.paused && !simulation.isChoosing && m.alive) { // const phase = i / len * 2 * Math.PI // const where = Vector.add(this.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5)) const unit = Vector.normalise(Vector.sub(player.position, this.position)) @@ -4914,9 +4915,9 @@ const spawn = { mobs.spawn(x, y, 7, radius, "transparent"); let me = mob[mob.length - 1]; me.seeAtDistance2 = 300000; - me.accelMag = 0.00013 * simulation.accelScale; + me.accelMag = 0.00015 * simulation.accelScale; if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search - // Matter.Body.setDensity(me, 0.001); //normal is 0.001 //makes effective life much lower + Matter.Body.setDensity(me, 0.0015); //normal is 0.001 //makes effective life much lower me.stroke = "transparent"; //used for drawGhost me.alpha = 1; //used in drawGhost me.canTouchPlayer = false; //used in drawGhost @@ -4927,7 +4928,7 @@ const spawn = { me.memory = 480; me.do = function() { //cap max speed - if (this.speed > 5) { + if (this.speed > 7) { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.8, y: this.velocity.y * 0.8 @@ -4939,7 +4940,7 @@ const spawn = { this.search(); //draw if (this.distanceToPlayer2() < this.seeAtDistance2) { - if (this.alpha < 1) this.alpha += 0.005 * simulation.CDScale; //near player go solid + if (this.alpha < 1) this.alpha += 0.01 * simulation.CDScale; //near player go solid } else { if (this.alpha > 0) this.alpha -= 0.05; ///away from player, hide } @@ -6498,6 +6499,34 @@ const spawn = { me.onDeath = function() { powerUps.spawnBossPowerUp(this.position.x, this.position.y) this.removeCons(); //remove constraint + //spawn seekers + // for (let i = 0, len = 100; i < len; i++) { + // const unit = Vector.rotate({ x: 10 + i, y: 0 }, Math.random() * 6.28) + // const where = Vector.add(this.position, unit) + // spawn.seeker(where.x, where.y); //(x, y, radius = 8, sides = 6) + // } + const delay = 4 + let i = 0 + const len = 3 * simulation.difficulty + let spawnFlutters = () => { + if (i < len) { + if (!(simulation.cycle % delay) && !simulation.paused && !simulation.isChoosing && m.alive) { + const unit = Vector.rotate({ x: radius * Math.random(), y: 0 }, Math.random() * 6.28) + const where = Vector.add(this.position, unit) + spawn.seeker(where.x, where.y); //(x, y, radius = 8, sides = 6) + i++ + } + requestAnimationFrame(spawnFlutters); + } + } + requestAnimationFrame(spawnFlutters); + simulation.drawList.push({ //add dmg to draw queue + x: this.position.x, + y: this.position.y, + radius: radius * 0.9, + color: "rgba(255,0,255,0.2)", + time: len * (delay - 1) + }); }; me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.do = function() { diff --git a/js/tech.js b/js/tech.js index 61b716a..bf196e3 100644 --- a/js/tech.js +++ b/js/tech.js @@ -425,8 +425,8 @@ const tech = { } }, { - name: "entanglement", - nameInfo: "", + name: "first derivative", + nameInfo: "", addNameInfo() { setTimeout(function() { simulation.boldActiveGunHUD(); @@ -442,14 +442,14 @@ const tech = { }, requires: "not mass-energy", effect() { - tech.isEntanglement = true + tech.isFirstOrder = true setTimeout(function() { simulation.boldActiveGunHUD(); }, 1000); }, remove() { - tech.isEntanglement = false; + tech.isFirstOrder = false; } }, { @@ -1664,7 +1664,7 @@ const tech = { allowed() { return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isTokamak }, - requires: "mass driver, not pilot wave not tokamak, wormhole", + requires: "mass driver, not pilot wave, tokamak, wormhole", effect() { tech.isBlockRestitution = true }, @@ -1898,7 +1898,7 @@ const tech = { allowed() { return (tech.isFlipFlop || tech.isRelay) && !tech.isDeterminism }, - requires: "ON/OFF tech not determinism", + requires: "ON/OFF tech, not determinism", effect() { tech.isFlipFlopChoices = true //do you have this tech }, @@ -2258,7 +2258,7 @@ const tech = { allowed() { return !tech.isZeno && !tech.isNoHeals && !tech.isPiezo && !tech.isRewindAvoidDeath && !tech.isMutualism //&& !tech.isAmmoFromHealth && !tech.isRewindGun }, - requires: "not Zeno, ergodicity, piezoelectricity, CPT, antiscience, mutualism", + requires: "not Zeno, ergodicity, piezoelectricity, CPT, mutualism", effect() { m.health = 0 document.getElementById("health").style.display = "none" @@ -2284,8 +2284,11 @@ const tech = { { name: "1st ionization energy", link: `1st ionization energy`, - description: `after you collect ${powerUps.orb.heal()}+10 maximum energy`, - description: `convert current and future ${powerUps.orb.heal()} into give +10 maximum energy`, + // description: `after you collect ${powerUps.orb.heal()}+${0.1 * tech.largerHeals} maximum energy`, + // descriptionFunction: `convert current and future ${powerUps.orb.heal()} into give +${10 * tech.largerHeals} maximum energy`, + descriptionFunction() { + return `convert current and future ${powerUps.orb.heal()} into give +${8 * tech.largerHeals} maximum energy` + }, maxCount: 1, count: 0, frequency: 2, @@ -2781,9 +2784,9 @@ const tech = { frequencyDefault: 1, isHealTech: true, allowed() { - return ((m.health / m.maxHealth) < 0.7 || build.isExperimentSelection) && !tech.isEnergyHealth && !tech.isNoHeals + return ((m.health / m.maxHealth) < 0.7 || build.isExperimentSelection) && !tech.isNoHeals }, - requires: "under 70% health, not mass-energy equivalence, ergodicity", + requires: "under 70% health, not ergodicity", effect() { tech.largerHeals++; for (let i = 0; i < powerUp.length; i++) { @@ -3178,9 +3181,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return !tech.isDeterminism && tech.duplicationChance() < 1 + return !tech.isDeterminism }, - requires: "below 100% duplication chance not determinism", + requires: "not determinism", effect() { tech.isExtraGunField = true; }, @@ -3631,9 +3634,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return tech.duplicationChance() < 1.11 && !tech.isSuperDeterminism + return tech.duplicationChance() < 1 && !tech.isSuperDeterminism }, - requires: "below 111% duplication chance, not superdeterminism", + requires: "below 100% duplication chance, not superdeterminism", effect() { tech.isCancelDuplication = true //search for tech.cancelCount to balance powerUps.setDupChance(); //needed after adjusting duplication chance @@ -3651,9 +3654,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return tech.duplicationChance() < 1.11 + return tech.duplicationChance() < 1. }, - requires: "below 111% duplication chance", + requires: "below 100% duplication chance", effect() { tech.duplicateChance += 0.1 powerUps.setDupChance(); //needed after adjusting duplication chance @@ -3678,9 +3681,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return tech.duplicationChance() < 1.11 + return tech.duplicationChance() < 1 }, - requires: "below 111% duplication chance", + requires: "below 1% duplication chance", effect() { tech.isStimulatedEmission = true powerUps.setDupChance(); //needed after adjusting duplication chance @@ -3699,9 +3702,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return tech.duplicationChance() < 1.11 + return tech.duplicationChance() < 1 }, - requires: "below 111% duplication chance", + requires: "below 100% duplication chance", effect() { tech.isPowerUpsVanish = true powerUps.setDupChance(); //needed after adjusting duplication chance @@ -3808,7 +3811,7 @@ const tech = { }, maxCount: 1, count: 0, - frequency: 199, + frequency: 1, frequencyDefault: 1, isNonRefundable: true, isBadRandomOption: true, @@ -4099,7 +4102,7 @@ const tech = { allowed() { return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 }, - requires: "nails, nail gun, rivets, shotgun", + requires: "nails, nail gun, rivets, shotgun, super balls, mine", effect() { tech.bulletSize = 1 + 0.25 * Math.pow(this.count + 1, 0.5) }, @@ -4251,7 +4254,7 @@ const tech = { allowed() { return (tech.isNailShot || tech.isNeedles || tech.isNailBotUpgrade || tech.haveGunCheck("nail gun") || tech.isRivets) && !tech.isIncendiary && !tech.isCritKill }, - requires: "nail gun, needles, nails, rivets, not incendiary, fire-control system", + requires: "nail gun, needles, nails, rivets, not incendiary, stress concentration", effect() { tech.isNailCrit = true }, @@ -4629,7 +4632,7 @@ const tech = { allowed() { return tech.haveGunCheck("super balls") && !tech.extraSuperBalls && !tech.superBallDelay }, - requires: "super balls, not super duper or supertemporal", + requires: "super balls, not super duper or autocannon", effect() { tech.oneSuperBall = true; for (i = 0, len = b.guns.length; i < len; i++) { //find which gun @@ -4773,8 +4776,8 @@ const tech = { isGunTech: true, maxCount: 1, count: 0, - frequency: 2, - frequencyDefault: 2, + frequency: 3, + frequencyDefault: 3, allowed() { return tech.haveGunCheck("wave") }, @@ -4812,8 +4815,8 @@ const tech = { isGunTech: true, maxCount: 1, count: 0, - frequency: 2, - frequencyDefault: 2, + frequency: 3, + frequencyDefault: 3, allowed() { return tech.isLongitudinal && tech.haveGunCheck("wave") && !tech.isBulletTeleport }, @@ -4956,7 +4959,7 @@ const tech = { allowed() { return tech.haveGunCheck("missiles", false) && tech.missileFireCD === 45 }, - requires: "missiles", + requires: "missiles, not launch system", effect() { tech.missileBotCount++; b.missileBot(); @@ -4982,7 +4985,7 @@ const tech = { allowed() { return !tech.isImmuneExplosion && tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.isBoomBotUpgrade || tech.isTokamak) }, - requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation", + requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation, electric armor", effect() { tech.isExplodeRadio = true; //iridium-192 }, @@ -5277,7 +5280,7 @@ const tech = { allowed() { return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && !tech.isPetalsExplode && !tech.isCircleExplode }, - requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test", + requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test, chain reaction", effect() { tech.isNeutronBomb = true; b.setGrenadeMode() @@ -5356,7 +5359,7 @@ const tech = { allowed() { return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio }, - requires: "neutron bomb or irradiated drones or iridium-192", + requires: "neutron bomb, irradiated drones, iridium-192", effect() { tech.isRadioactiveResistance = true }, @@ -5665,9 +5668,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return !tech.isExtraMaxEnergy && (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3)) + return tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3) }, - requires: "drones, not weak interaction", + requires: "drones", effect() { tech.isDroneGrab = true }, @@ -5926,7 +5929,7 @@ const tech = { allowed() { return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine }, - requires: "foam, worms", + requires: "foam, spores, worms, fleas", effect() { tech.isSpawnBulletsOnDeath = true }, @@ -6053,7 +6056,7 @@ const tech = { allowed() { return tech.blockDamage > 0.075 || tech.isRailGun || (tech.haveGunCheck("foam") && tech.isFoamPressure) || tech.isTokamak || tech.isPulseLaser || tech.isPlasmaBall }, - requires: "throwing blocks, railgun, foam, pulse, tokamak, plasma ball", + requires: "mass driver, railgun, foam, pressure vessel, pulse, tokamak, plasma ball", effect() { tech.isCapacitor = true; }, @@ -6594,7 +6597,7 @@ const tech = { allowed() { return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && !tech.isPulseLaser && tech.laserDrain === 0.0018 }, - requires: "laser, not free-electron", + requires: "laser, not free-electron, pulse", effect() { tech.laserDrain *= 0.5; //100%-50% tech.laserColor = "transparent" //"rgb(255,0,20,0.02)" @@ -6784,7 +6787,7 @@ const tech = { allowed() { return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" }, - requires: "standing wave, perfect diamagnetism", + requires: "standing wave, perfect diamagnetism, pilot wave", effect() { tech.blockDmg += 3 //if you change this value also update the for loop in the electricity graphics in m.pushMass }, @@ -6942,7 +6945,7 @@ const tech = { allowed() { return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "standing wave") && !tech.isCloakHealLastHit }, - requires: "negative mass, pilot wave, not patch", + requires: "negative mass, pilot wave, standing wave, not patch", effect() { tech.lastHitDamage += 5; }, @@ -7048,7 +7051,7 @@ const tech = { allowed() { return powerUps.research.count > 1 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") }, - requires: "NOT EXPERIMENT MODE, molecular assembler", + requires: "NOT EXPERIMENT MODE, molecular assembler, pilot wave", effect() { for (let i = 0; i < 2; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) @@ -7073,7 +7076,7 @@ const tech = { allowed() { return powerUps.research.count > 2 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") }, - requires: "NOT EXPERIMENT MODE, molecular assembler", + requires: "NOT EXPERIMENT MODE, molecular assembler, pilot wave", effect() { for (let i = 0; i < 3; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) @@ -7305,7 +7308,7 @@ const tech = { isBot: true, isBotTech: true, allowed() { - return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && (build.isExperimentSelection || powerUps.research.count > 0) && !tech.isPlasmaBall && !tech.isExtruder + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall && !tech.isExtruder }, requires: "plasma torch, not extruder, plasma ball", effect() { @@ -7539,7 +7542,7 @@ const tech = { allowed() { return (m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking") && !tech.isQuantumEraser }, - requires: "cloaking, time dilation", + requires: "cloaking, time dilation, not quantum eraser", effect() { tech.cloakDuplication = 0.45 powerUps.setDupChance(); //needed after adjusting duplication chance @@ -7586,7 +7589,7 @@ const tech = { allowed() { return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" //|| m.fieldUpgrades[m.fieldMode].name === "time dilation" }, - requires: "cloaking or time dilation", + requires: "cloaking", effect() { tech.isAddRemoveMaxHealth = true }, @@ -7739,7 +7742,7 @@ const tech = { allowed() { return m.fieldUpgrades[m.fieldMode].name === "wormhole" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation" }, - requires: "wormhole or pilot wave", + requires: "wormhole, pilot wave, time dilation", effect() { tech.wimpCount++ spawn.WIMP() @@ -8124,1937 +8127,1937 @@ const tech = { // }, // remove() {} // }, - { - name: "boost", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed() { - return !build.isExperimentSelection - }, - requires: "NOT EXPERIMENT MODE", - effect() { - powerUps.spawnDelay("boost", this.spawnCount) - }, - remove() {}, - id: 0, - text: "", - delay: 100, - spawnCount: 0, - descriptionFunction() { - let count = 9999 * Math.random() - const loop = () => { - if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0) //simulation.paused || - count += 4.5 - const waves = 2 * Math.sin(count * 0.0133) + Math.sin(count * 0.013) + 0.5 * Math.sin(count * 0.031) + 0.33 * Math.sin(count * 0.03) - this.spawnCount = Math.floor(100 * Math.abs(waves)) - this.text = `spawn ${this.spawnCount.toLocaleString(undefined, {minimumIntegerDigits:3})} ${powerUps.orb.boost(1)}that give +${(powerUps.boost.damage*100).toFixed(0)}% damage for ${(powerUps.boost.duration/60).toFixed(0)} seconds` - if (document.getElementById(`boost-JUNK-id${this.id}`)) document.getElementById(`boost-JUNK-id${this.id}`).innerHTML = this.text - setTimeout(() => { loop() }, this.delay); - } - } - setTimeout(() => { loop() }, this.delay); - this.id++ - return `${this.text}` - }, - }, - { - name: "return", - description: "return to the introduction levelreduce combat difficulty by 2 levels", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - level.difficultyDecrease(simulation.difficultyMode * 2) - level.onLevel = 0 - simulation.clearNow = true //end current level - }, - remove() {} - }, - { - name: "panpsychism", - description: "awaken all blocksblocks have a chance to spawn power ups", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - setInterval(() => { - for (let i = body.length - 1; i > -1; i--) { - if (!body[i].isNotHoldable) { - Matter.Composite.remove(engine.world, body[i]); - spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0); - if (!body[i].isAboutToBeRemoved) mob[mob.length - 1].isDropPowerUp = true - body.splice(i, 1); - } - } - }, 6000); - }, - remove() {} - }, - { - name: "meteor shower", - description: "take a shower, but meteors instead of water", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - setInterval(() => { - - fireBlock = function(xPos, yPos) { - const index = body.length - spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random()); - const bodyBullet = body[index] - Matter.Body.setVelocity(bodyBullet, { x: 5 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }); - bodyBullet.isAboutToBeRemoved = true - bodyBullet.collisionFilter.category = cat.body; - bodyBullet.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet - bodyBullet.classType = "body"; - Composite.add(engine.world, bodyBullet); //add to world - setTimeout(() => { //remove block - for (let i = 0; i < body.length; i++) { - if (body[i] === bodyBullet) { - Matter.Composite.remove(engine.world, body[i]); - body.splice(i, 1); - } - } - }, 4000 + Math.floor(9000 * Math.random())); - } - fireBlock(player.position.x + 600 * (Math.random() - 0.5), player.position.y - 500 - 500 * Math.random()); - // for (let i = 0, len = Math.random(); i < len; i++) { - // } - - }, 1000); - }, - remove() {} - }, - { - name: "closed timelike curve", - description: "spawn 5 field power ups, but every 12 secondsteleport a second into your future or past", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field"); - - function loop() { - if (!simulation.paused && m.alive) { - if (!(simulation.cycle % 720)) { - requestAnimationFrame(() => { - if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option - m.rewind(60) - m.energy += 0.4 //to make up for lost energy - } else { - simulation.timePlayerSkip(60) - } - }); //wrapping in animation frame prevents errors, probably - } - } - requestAnimationFrame(loop); - } - requestAnimationFrame(loop); - }, - remove() {} - }, // { - // name: "translate", - // description: "translate n-gon into a random language", + // name: "boost", // maxCount: 1, // count: 0, // frequency: 0, // isJunk: true, // isNonRefundable: true, // allowed() { - // return true + // return !build.isExperimentSelection // }, - // requires: "", + // requires: "NOT EXPERIMENT MODE", // effect() { - // // generate a container - // const gtElem = document.createElement('div') - // gtElem.id = "gtElem" - // gtElem.style.visibility = 'hidden' // make it invisible - // document.body.append(gtElem) - - // // generate a script to run after creation - // function initGT() { - // // create a new translate element - // new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem') - // // ok now since it's loaded perform a funny hack to make it work - // const langSelect = document.getElementsByClassName("goog-te-combo")[0] - // // select a random language. It takes a second for all langauges to load, so wait a second. - // setTimeout(() => { - // langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random()) - // // simulate a click - // langSelect.dispatchEvent(new Event('change')) - // // now make it go away - // const bar = document.getElementById(':1.container') - // bar.style.display = 'none' - // bar.style.visibility = 'hidden' - // }, 1000) - + // powerUps.spawnDelay("boost", this.spawnCount) + // }, + // remove() {}, + // id: 0, + // text: "", + // delay: 100, + // spawnCount: 0, + // descriptionFunction() { + // let count = 9999 * Math.random() + // const loop = () => { + // if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0) //simulation.paused || + // count += 4.5 + // const waves = 2 * Math.sin(count * 0.0133) + Math.sin(count * 0.013) + 0.5 * Math.sin(count * 0.031) + 0.33 * Math.sin(count * 0.03) + // this.spawnCount = Math.floor(100 * Math.abs(waves)) + // this.text = `spawn ${this.spawnCount.toLocaleString(undefined, {minimumIntegerDigits:3})} ${powerUps.orb.boost(1)}that give +${(powerUps.boost.damage*100).toFixed(0)}% damage for ${(powerUps.boost.duration/60).toFixed(0)} seconds` + // if (document.getElementById(`boost-JUNK-id${this.id}`)) document.getElementById(`boost-JUNK-id${this.id}`).innerHTML = this.text + // setTimeout(() => { loop() }, this.delay); + // } // } - - // // add the google translate script - // const translateScript = document.createElement('script') - // translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT' - // document.body.append(translateScript) + // setTimeout(() => { loop() }, this.delay); + // this.id++ + // return `${this.text}` // }, - // remove() {} // }, - { - name: "discount", - description: "get 3 random JUNK tech for the price of 1!", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - tech.giveRandomJUNK() - tech.giveRandomJUNK() - tech.giveRandomJUNK() - }, - remove() {} - }, // { - // name: "hi", - // description: `spawn to seed 616 `, + // name: "return", + // description: "return to the introduction levelreduce combat difficulty by 2 levels", // maxCount: 1, // count: 0, // frequency: 0, - // isNonRefundable: true, // isJunk: true, - // allowed() { - // return true - // }, + // isNonRefundable: true, + // allowed: () => true, // requires: "", // effect() { - // document.getElementById("seed").placeholder = Math.initialSeed = String(616) - // Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it + // level.difficultyDecrease(simulation.difficultyMode * 2) + // level.onLevel = 0 + // simulation.clearNow = true //end current level // }, // remove() {} // }, - { - name: "Higgs phase transition", - description: "instantly spawn 5 tech, but add a chance toremove everything with a 5 minute half-life", - maxCount: 1, - count: 0, - frequency: 0, - frequencyDefault: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - powerUps.spawn(m.pos.x, m.pos.y, "tech"); - powerUps.spawn(m.pos.x + 30, m.pos.y, "tech"); - powerUps.spawn(m.pos.x + 60, m.pos.y, "tech"); - powerUps.spawn(m.pos.x, m.pos.y - 30, "tech"); - powerUps.spawn(m.pos.x + 30, m.pos.y - 60, "tech"); + // { + // name: "panpsychism", + // description: "awaken all blocksblocks have a chance to spawn power ups", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed: () => true, + // requires: "", + // effect() { + // setInterval(() => { + // for (let i = body.length - 1; i > -1; i--) { + // if (!body[i].isNotHoldable) { + // Matter.Composite.remove(engine.world, body[i]); + // spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0); + // if (!body[i].isAboutToBeRemoved) mob[mob.length - 1].isDropPowerUp = true + // body.splice(i, 1); + // } + // } + // }, 6000); + // }, + // remove() {} + // }, + // { + // name: "meteor shower", + // description: "take a shower, but meteors instead of water", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed: () => true, + // requires: "", + // effect() { + // setInterval(() => { - function loop() { - // (1-X)^cycles = chance to be removed //Math.random() < 0.000019 10 min - if (!simulation.paused && m.alive) { - if (Math.random() < 0.000038) { - // m.death(); - simulation.clearMap(); - simulation.draw.setPaths(); - return - } - } - requestAnimationFrame(loop); - } - requestAnimationFrame(loop); - }, - remove() {} - }, - { - name: "harvest", - description: "convert all the mobs on this level into ammo", - maxCount: 1, - count: 0, - frequency: 0, - frequencyDefault: 0, - isJunk: true, - isNonRefundable: true, - allowed: () => true, - requires: "", - effect() { - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].isDropPowerUp) { - powerUps.directSpawn(mob[i].position.x, mob[i].position.y, "ammo"); - 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() {} - }, - { - name: " ", - description: "", - maxCount: 1, - count: 0, - frequency: 0, - frequencyDefault: 0, - isJunk: true, - allowed: () => true, - requires: "", - effect() { + // fireBlock = function(xPos, yPos) { + // const index = body.length + // spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random()); + // const bodyBullet = body[index] + // Matter.Body.setVelocity(bodyBullet, { x: 5 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }); + // bodyBullet.isAboutToBeRemoved = true + // bodyBullet.collisionFilter.category = cat.body; + // bodyBullet.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet + // bodyBullet.classType = "body"; + // Composite.add(engine.world, bodyBullet); //add to world + // setTimeout(() => { //remove block + // for (let i = 0; i < body.length; i++) { + // if (body[i] === bodyBullet) { + // Matter.Composite.remove(engine.world, body[i]); + // body.splice(i, 1); + // } + // } + // }, 4000 + Math.floor(9000 * Math.random())); + // } + // fireBlock(player.position.x + 600 * (Math.random() - 0.5), player.position.y - 500 - 500 * Math.random()); + // // for (let i = 0, len = Math.random(); i < len; i++) { + // // } - }, - remove() { + // }, 1000); + // }, + // remove() {} + // }, + // { + // name: "closed timelike curve", + // description: "spawn 5 field power ups, but every 12 secondsteleport a second into your future or past", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed: () => true, + // requires: "", + // effect() { + // for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field"); + + // function loop() { + // if (!simulation.paused && m.alive) { + // if (!(simulation.cycle % 720)) { + // requestAnimationFrame(() => { + // if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option + // m.rewind(60) + // m.energy += 0.4 //to make up for lost energy + // } else { + // simulation.timePlayerSkip(60) + // } + // }); //wrapping in animation frame prevents errors, probably + // } + // } + // requestAnimationFrame(loop); + // } + // requestAnimationFrame(loop); + // }, + // remove() {} + // }, + // // { + // // name: "translate", + // // description: "translate n-gon into a random language", + // // maxCount: 1, + // // count: 0, + // // frequency: 0, + // // isJunk: true, + // // isNonRefundable: true, + // // allowed() { + // // return true + // // }, + // // requires: "", + // // effect() { + // // // generate a container + // // const gtElem = document.createElement('div') + // // gtElem.id = "gtElem" + // // gtElem.style.visibility = 'hidden' // make it invisible + // // document.body.append(gtElem) + + // // // generate a script to run after creation + // // function initGT() { + // // // create a new translate element + // // new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem') + // // // ok now since it's loaded perform a funny hack to make it work + // // const langSelect = document.getElementsByClassName("goog-te-combo")[0] + // // // select a random language. It takes a second for all langauges to load, so wait a second. + // // setTimeout(() => { + // // langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random()) + // // // simulate a click + // // langSelect.dispatchEvent(new Event('change')) + // // // now make it go away + // // const bar = document.getElementById(':1.container') + // // bar.style.display = 'none' + // // bar.style.visibility = 'hidden' + // // }, 1000) + + // // } + + // // // add the google translate script + // // const translateScript = document.createElement('script') + // // translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT' + // // document.body.append(translateScript) + // // }, + // // remove() {} + // // }, + // { + // name: "discount", + // description: "get 3 random JUNK tech for the price of 1!", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed: () => true, + // requires: "", + // effect() { + // tech.giveRandomJUNK() + // tech.giveRandomJUNK() + // tech.giveRandomJUNK() + // }, + // remove() {} + // }, + // // { + // // name: "hi", + // // description: `spawn to seed 616 `, + // // maxCount: 1, + // // count: 0, + // // frequency: 0, + // // isNonRefundable: true, + // // isJunk: true, + // // allowed() { + // // return true + // // }, + // // requires: "", + // // effect() { + // // document.getElementById("seed").placeholder = Math.initialSeed = String(616) + // // Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it + // // }, + // // remove() {} + // // }, + // { + // name: "Higgs phase transition", + // description: "instantly spawn 5 tech, but add a chance toremove everything with a 5 minute half-life", + // maxCount: 1, + // count: 0, + // frequency: 0, + // frequencyDefault: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed: () => true, + // requires: "", + // effect() { + // powerUps.spawn(m.pos.x, m.pos.y, "tech"); + // powerUps.spawn(m.pos.x + 30, m.pos.y, "tech"); + // powerUps.spawn(m.pos.x + 60, m.pos.y, "tech"); + // powerUps.spawn(m.pos.x, m.pos.y - 30, "tech"); + // powerUps.spawn(m.pos.x + 30, m.pos.y - 60, "tech"); + + // function loop() { + // // (1-X)^cycles = chance to be removed //Math.random() < 0.000019 10 min + // if (!simulation.paused && m.alive) { + // if (Math.random() < 0.000038) { + // // m.death(); + // simulation.clearMap(); + // simulation.draw.setPaths(); + // return + // } + // } + // requestAnimationFrame(loop); + // } + // requestAnimationFrame(loop); + // }, + // remove() {} + // }, + // { + // name: "harvest", + // description: "convert all the mobs on this level into ammo", + // maxCount: 1, + // count: 0, + // frequency: 0, + // frequencyDefault: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed: () => true, + // requires: "", + // effect() { + // for (let i = 0, len = mob.length; i < len; i++) { + // if (mob[i].isDropPowerUp) { + // powerUps.directSpawn(mob[i].position.x, mob[i].position.y, "ammo"); + // 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() {} + // }, + // { + // name: " ", + // description: "", + // maxCount: 1, + // count: 0, + // frequency: 0, + // frequencyDefault: 0, + // isJunk: true, + // allowed: () => true, + // requires: "", + // effect() { + + // }, + // remove() { - } - }, - { - name: "brainstorm", - description: "the tech choice menu randomizesevery 0.5 seconds for 10 seconds", - maxCount: 1, - count: 0, - frequency: 0, - frequencyDefault: 0, - isJunk: true, - allowed: () => true, - requires: "", - effect() { - tech.isBrainstorm = true - tech.isBrainstormActive = false - tech.brainStormDelay = 30 - }, - remove() { - tech.isBrainstorm = false - tech.isBrainstormActive = false - } - }, - { - name: "catabolysis", - description: `set your maximum health to 1double your current ammo 10 times`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth }, - requires: "not quenching, tungsten carbide, mass-energy", - effect() { - m.baseHealth = 0.01 - m.setMaxHealth(); - for (let i = 0; i < b.guns.length; i++) b.guns[i].ammo = b.guns[i].ammo * Math.pow(2, 10) - simulation.updateGunHUD(); - }, - remove() {} - }, - { - name: "palantír", - description: `see far away lands`, - maxCount: 1, - count: 0, - frequency: 0, - // isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - m.look = () => { - //always on mouse look - m.angle = Math.atan2( - simulation.mouseInGame.y - m.pos.y, - simulation.mouseInGame.x - m.pos.x - ); - //smoothed mouse look translations - const scale = 2; - m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; - m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; - m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing; - m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing; - } - }, - remove() { - if (this.count) m.look = m.lookDefault - } - }, - { - name: "motion sickness", - description: `disable camera smoothing`, - maxCount: 1, - count: 0, - frequency: 0, - // isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - m.look = () => { - //always on mouse look - m.angle = Math.atan2( - simulation.mouseInGame.y - m.pos.y, - simulation.mouseInGame.x - m.pos.x - ); - //smoothed mouse look translations - const scale = 1.2; - m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; - m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; - m.transX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; - m.transY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; - // m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing; - // m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing; - } - }, - remove() { - if (this.count) m.look = m.lookDefault - } - }, - { - name: "facsimile", - description: `inserts a copy of your current level into the level list`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - level.levels.splice(level.onLevel, 0, level.levels[level.onLevel]); - }, - remove() {} - }, - { - name: "negative friction", - description: "when you touch walls you speed up instead of slowing down. It's kinda fun.", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - player.friction = -0.4 - }, - remove() { - if (this.count) player.friction = 0.002 - } - }, - { - name: "bounce", - description: "you bounce off things. It's annoying, but not that bad.", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - player.restitution = 0.9 - }, - remove() { - if (this.count) player.restitution = 0 - } - }, - { - name: "mouth", - description: "mobs have a non functional mouth", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - mobs.draw = () => { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); - ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - } - }, - remove() { - mobs.draw = () => { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - } - } - }, - { - name: "all-stars", - description: "make all mobs look like stars", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - mobs.draw = () => { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y); - ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - } - }, - remove() { - mobs.draw = () => { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - } - } - }, - // draw() { - // ctx.lineWidth = 2; - // let i = mob.length; - // while (i--) { - // ctx.beginPath(); - // const vertices = mob[i].vertices; - // ctx.moveTo(vertices[0].x, vertices[0].y); - // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); - // ctx.lineTo(vertices[0].x, vertices[0].y); - // ctx.fillStyle = mob[i].fill; - // ctx.strokeStyle = mob[i].stroke; - // ctx.fill(); - // ctx.stroke(); // } // }, - { - name: "true colors", - description: `set all power ups to their real world colors`, - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed() { return true }, - requires: "", - effect() { - // const colors = shuffle(["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"]) - const colors = shuffle([powerUps.research.color, powerUps.heal.color, powerUps.ammo.color, powerUps.ammo.color, powerUps.field.color, powerUps.gun.color]) - powerUps.research.color = colors[0] - powerUps.heal.color = colors[1] - powerUps.ammo.color = colors[2] - powerUps.field.color = colors[3] - powerUps.tech.color = colors[4] - powerUps.gun.color = colors[5] - for (let i = 0; i < powerUp.length; i++) { - switch (powerUp[i].name) { - case "research": - powerUp[i].color = colors[0] - break; - case "heal": - powerUp[i].color = colors[1] - break; - case "ammo": - powerUp[i].color = colors[2] - break; - case "field": - powerUp[i].color = colors[3] - break; - case "tech": - powerUp[i].color = colors[4] - break; - case "gun": - powerUp[i].color = colors[5] - break; - } - } - }, - remove() { - // const colors = ["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"] //no shuffle - // powerUps.research.color = colors[0] - // powerUps.heal.color = colors[1] - // powerUps.ammo.color = colors[2] - // powerUps.field.color = colors[3] - // powerUps.tech.color = colors[4] - // powerUps.gun.color = colors[5] - // for (let i = 0; i < powerUp.length; i++) { - // switch (powerUp[i].name) { - // case "research": - // powerUp[i].color = colors[0] - // break; - // case "heal": - // powerUp[i].color = colors[1] - // break; - // case "ammo": - // powerUp[i].color = colors[2] - // break; - // case "field": - // powerUp[i].color = colors[3] - // break; - // case "tech": - // powerUp[i].color = colors[4] - // break; - // case "gun": - // powerUp[i].color = colors[5] - // break; - // } - // } - } - }, - { - name: "emergency broadcasting", - description: "emit 2 sine waveforms at 853 Hz and 960 Hzlower your volume", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - isNonRefundable: true, - allowed() { return true }, - requires: "", - effect: () => { - //setup audio context - function tone(frequency) { - const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); - const oscillator1 = audioCtx.createOscillator(); - const gainNode1 = audioCtx.createGain(); - gainNode1.gain.value = 0.5; //controls volume - oscillator1.connect(gainNode1); - gainNode1.connect(audioCtx.destination); - oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom' - oscillator1.frequency.value = frequency; // value in hertz - oscillator1.start(); - return audioCtx - } - // let sound = tone(1050) - - function EBS() { - const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); - - const oscillator1 = audioCtx.createOscillator(); - const gainNode1 = audioCtx.createGain(); - gainNode1.gain.value = 0.3; //controls volume - oscillator1.connect(gainNode1); - gainNode1.connect(audioCtx.destination); - oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom' - oscillator1.frequency.value = 850; // value in hertz - oscillator1.start(); - - const oscillator2 = audioCtx.createOscillator(); - const gainNode2 = audioCtx.createGain(); - gainNode2.gain.value = 0.3; //controls volume - oscillator2.connect(gainNode2); - gainNode2.connect(audioCtx.destination); - oscillator2.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom' - oscillator2.frequency.value = 957; // value in hertz - oscillator2.start(); - return audioCtx - } - let sound = EBS() - - delay = 1000 - setTimeout(() => { - sound.suspend() - powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - setTimeout(() => { - sound.resume() - setTimeout(() => { - sound.suspend() - powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - setTimeout(() => { - sound.resume() - setTimeout(() => { - sound.suspend() - powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - setTimeout(() => { - sound.resume() - setTimeout(() => { - sound.suspend() - powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - setTimeout(() => { - sound.resume() - setTimeout(() => { - sound.suspend() - powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - setTimeout(() => { - sound.resume() - setTimeout(() => { - sound.suspend() - sound.close() - powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, delay); - }, - remove() {} - }, - { - name: "automatic", - description: "you can't fire when movingalways fire when at rest", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { - return !tech.isFireMoveLock - }, - requires: "not Higgs mechanism", - effect() { - tech.isAlwaysFire = true; - b.setFireMethod(); - }, - remove() { - if (tech.isAlwaysFire) { - tech.isAlwaysFire = false - b.setFireMethod(); - } - } - }, - { - name: "hidden variable", - description: `spawn ${powerUps.orb.heal(20)}but hide your health bar`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return !tech.isEnergyHealth - }, - requires: "not mass-energy", - effect() { - document.getElementById("health").style.display = "none" - document.getElementById("health-bg").style.display = "none" - for (let i = 0; i < 20; i++) powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); - }, - remove() {} - }, - { - name: "not a bug", - description: "initiate a totally safe game crash for 10 seconds", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - const savedfunction = simulation.drawCircle - simulation.drawCircle = () => { - const a = mob[Infinity].position //crashed the game in a visually interesting way, because of the ctx.translate command is never reverted in the main game loop - } - setTimeout(() => { - simulation.drawCircle = savedfunction - canvas.width = canvas.width //clears the canvas // works on chrome at least - powerUps.spawn(m.pos.x, m.pos.y, "tech"); - }, 10000); - - // for (;;) {} //freezes the tab - }, - remove() {} - }, - { - name: "spinor", - description: "the direction you aim is determined by your position", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return !m.isShipMode - }, - requires: "", - effect() { - m.look = function() { - //always on mouse look - m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI - //smoothed mouse look translations - const scale = 0.8; - m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; - m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; - - m.transX += (m.transSmoothX - m.transX) * 0.07; - m.transY += (m.transSmoothY - m.transY) * 0.07; - } - }, - remove() { - if (this.count) m.look = m.lookDefault - } - }, - { - name: "decomposers", - description: "after they die mobs leave behind spawns", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return tech.deathSpawns === 0 - }, - requires: "", - effect() { - tech.deathSpawns = 0.2 - }, - remove() { - tech.deathSpawns = 0 - } - }, - { - name: "panopticon", - description: "mobs can always see you", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - for (let i = 0; i < mob.length; i++) { - if (!mob[i].shield && mob[i].isDropPowerUp) { - mob[i].locatePlayer() - mob[i].seePlayer.yes = true; - } - } - }, 1000); //every 1 seconds - }, - remove() {} - }, // { - // name: "inverted mouse", - // description: "your mouse is scrambledit's fine, just rotate it 90 degrees", + // name: "brainstorm", + // description: "the tech choice menu randomizesevery 0.5 seconds for 10 seconds", + // maxCount: 1, + // count: 0, + // frequency: 0, + // frequencyDefault: 0, + // isJunk: true, + // allowed: () => true, + // requires: "", + // effect() { + // tech.isBrainstorm = true + // tech.isBrainstormActive = false + // tech.brainStormDelay = 30 + // }, + // remove() { + // tech.isBrainstorm = false + // tech.isBrainstormActive = false + // } + // }, + // { + // name: "catabolysis", + // description: `set your maximum health to 1double your current ammo 10 times`, // maxCount: 1, // count: 0, // frequency: 0, - // isExperimentHide: true, // isNonRefundable: true, // isJunk: true, + // allowed() { return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth }, + // requires: "not quenching, tungsten carbide, mass-energy", + // effect() { + // m.baseHealth = 0.01 + // m.setMaxHealth(); + // for (let i = 0; i < b.guns.length; i++) b.guns[i].ammo = b.guns[i].ammo * Math.pow(2, 10) + // simulation.updateGunHUD(); + // }, + // remove() {} + // }, + // { + // name: "palantír", + // description: `see far away lands`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // m.look = () => { + // //always on mouse look + // m.angle = Math.atan2( + // simulation.mouseInGame.y - m.pos.y, + // simulation.mouseInGame.x - m.pos.x + // ); + // //smoothed mouse look translations + // const scale = 2; + // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; + // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; + // m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing; + // m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing; + // } + // }, + // remove() { + // if (this.count) m.look = m.lookDefault + // } + // }, + // { + // name: "motion sickness", + // description: `disable camera smoothing`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // m.look = () => { + // //always on mouse look + // m.angle = Math.atan2( + // simulation.mouseInGame.y - m.pos.y, + // simulation.mouseInGame.x - m.pos.x + // ); + // //smoothed mouse look translations + // const scale = 1.2; + // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; + // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; + // m.transX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; + // m.transY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; + // // m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing; + // // m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing; + // } + // }, + // remove() { + // if (this.count) m.look = m.lookDefault + // } + // }, + // { + // name: "facsimile", + // description: `inserts a copy of your current level into the level list`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // level.levels.splice(level.onLevel, 0, level.levels[level.onLevel]); + // }, + // remove() {} + // }, + // { + // name: "negative friction", + // description: "when you touch walls you speed up instead of slowing down. It's kinda fun.", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // player.friction = -0.4 + // }, + // remove() { + // if (this.count) player.friction = 0.002 + // } + // }, + // { + // name: "bounce", + // description: "you bounce off things. It's annoying, but not that bad.", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // player.restitution = 0.9 + // }, + // remove() { + // if (this.count) player.restitution = 0 + // } + // }, + // { + // name: "mouth", + // description: "mobs have a non functional mouth", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // mobs.draw = () => { + // ctx.lineWidth = 2; + // let i = mob.length; + // while (i--) { + // ctx.beginPath(); + // const vertices = mob[i].vertices; + // ctx.moveTo(vertices[0].x, vertices[0].y); + // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); + // ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y); + // ctx.fillStyle = mob[i].fill; + // ctx.strokeStyle = mob[i].stroke; + // ctx.fill(); + // ctx.stroke(); + // } + // } + // }, + // remove() { + // mobs.draw = () => { + // ctx.lineWidth = 2; + // let i = mob.length; + // while (i--) { + // ctx.beginPath(); + // const vertices = mob[i].vertices; + // ctx.moveTo(vertices[0].x, vertices[0].y); + // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); + // ctx.lineTo(vertices[0].x, vertices[0].y); + // ctx.fillStyle = mob[i].fill; + // ctx.strokeStyle = mob[i].stroke; + // ctx.fill(); + // ctx.stroke(); + // } + // } + // } + // }, + // { + // name: "all-stars", + // description: "make all mobs look like stars", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // mobs.draw = () => { + // ctx.lineWidth = 2; + // let i = mob.length; + // while (i--) { + // ctx.beginPath(); + // const vertices = mob[i].vertices; + // ctx.moveTo(vertices[0].x, vertices[0].y); + // for (let j = 1, len = vertices.length; j < len; ++j) ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y); + // ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y); + // ctx.fillStyle = mob[i].fill; + // ctx.strokeStyle = mob[i].stroke; + // ctx.fill(); + // ctx.stroke(); + // } + // } + // }, + // remove() { + // mobs.draw = () => { + // ctx.lineWidth = 2; + // let i = mob.length; + // while (i--) { + // ctx.beginPath(); + // const vertices = mob[i].vertices; + // ctx.moveTo(vertices[0].x, vertices[0].y); + // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); + // ctx.lineTo(vertices[0].x, vertices[0].y); + // ctx.fillStyle = mob[i].fill; + // ctx.strokeStyle = mob[i].stroke; + // ctx.fill(); + // ctx.stroke(); + // } + // } + // } + // }, + // // draw() { + // // ctx.lineWidth = 2; + // // let i = mob.length; + // // while (i--) { + // // ctx.beginPath(); + // // const vertices = mob[i].vertices; + // // ctx.moveTo(vertices[0].x, vertices[0].y); + // // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); + // // ctx.lineTo(vertices[0].x, vertices[0].y); + // // ctx.fillStyle = mob[i].fill; + // // ctx.strokeStyle = mob[i].stroke; + // // ctx.fill(); + // // ctx.stroke(); + // // } + // // }, + // { + // name: "true colors", + // description: `set all power ups to their real world colors`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed() { return true }, + // requires: "", + // effect() { + // // const colors = shuffle(["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"]) + // const colors = shuffle([powerUps.research.color, powerUps.heal.color, powerUps.ammo.color, powerUps.ammo.color, powerUps.field.color, powerUps.gun.color]) + // powerUps.research.color = colors[0] + // powerUps.heal.color = colors[1] + // powerUps.ammo.color = colors[2] + // powerUps.field.color = colors[3] + // powerUps.tech.color = colors[4] + // powerUps.gun.color = colors[5] + // for (let i = 0; i < powerUp.length; i++) { + // switch (powerUp[i].name) { + // case "research": + // powerUp[i].color = colors[0] + // break; + // case "heal": + // powerUp[i].color = colors[1] + // break; + // case "ammo": + // powerUp[i].color = colors[2] + // break; + // case "field": + // powerUp[i].color = colors[3] + // break; + // case "tech": + // powerUp[i].color = colors[4] + // break; + // case "gun": + // powerUp[i].color = colors[5] + // break; + // } + // } + // }, + // remove() { + // // const colors = ["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"] //no shuffle + // // powerUps.research.color = colors[0] + // // powerUps.heal.color = colors[1] + // // powerUps.ammo.color = colors[2] + // // powerUps.field.color = colors[3] + // // powerUps.tech.color = colors[4] + // // powerUps.gun.color = colors[5] + // // for (let i = 0; i < powerUp.length; i++) { + // // switch (powerUp[i].name) { + // // case "research": + // // powerUp[i].color = colors[0] + // // break; + // // case "heal": + // // powerUp[i].color = colors[1] + // // break; + // // case "ammo": + // // powerUp[i].color = colors[2] + // // break; + // // case "field": + // // powerUp[i].color = colors[3] + // // break; + // // case "tech": + // // powerUp[i].color = colors[4] + // // break; + // // case "gun": + // // powerUp[i].color = colors[5] + // // break; + // // } + // // } + // } + // }, + // { + // name: "emergency broadcasting", + // description: "emit 2 sine waveforms at 853 Hz and 960 Hzlower your volume", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed() { return true }, + // requires: "", + // effect: () => { + // //setup audio context + // function tone(frequency) { + // const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); + // const oscillator1 = audioCtx.createOscillator(); + // const gainNode1 = audioCtx.createGain(); + // gainNode1.gain.value = 0.5; //controls volume + // oscillator1.connect(gainNode1); + // gainNode1.connect(audioCtx.destination); + // oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom' + // oscillator1.frequency.value = frequency; // value in hertz + // oscillator1.start(); + // return audioCtx + // } + // // let sound = tone(1050) + + // function EBS() { + // const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); + + // const oscillator1 = audioCtx.createOscillator(); + // const gainNode1 = audioCtx.createGain(); + // gainNode1.gain.value = 0.3; //controls volume + // oscillator1.connect(gainNode1); + // gainNode1.connect(audioCtx.destination); + // oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom' + // oscillator1.frequency.value = 850; // value in hertz + // oscillator1.start(); + + // const oscillator2 = audioCtx.createOscillator(); + // const gainNode2 = audioCtx.createGain(); + // gainNode2.gain.value = 0.3; //controls volume + // oscillator2.connect(gainNode2); + // gainNode2.connect(audioCtx.destination); + // oscillator2.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom' + // oscillator2.frequency.value = 957; // value in hertz + // oscillator2.start(); + // return audioCtx + // } + // let sound = EBS() + + // delay = 1000 + // setTimeout(() => { + // sound.suspend() + // powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // setTimeout(() => { + // sound.resume() + // setTimeout(() => { + // sound.suspend() + // powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // setTimeout(() => { + // sound.resume() + // setTimeout(() => { + // sound.suspend() + // powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // setTimeout(() => { + // sound.resume() + // setTimeout(() => { + // sound.suspend() + // powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // setTimeout(() => { + // sound.resume() + // setTimeout(() => { + // sound.suspend() + // powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // setTimeout(() => { + // sound.resume() + // setTimeout(() => { + // sound.suspend() + // sound.close() + // powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, delay); + // }, + // remove() {} + // }, + // { + // name: "automatic", + // description: "you can't fire when movingalways fire when at rest", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // allowed() { + // return !tech.isFireMoveLock + // }, + // requires: "not Higgs mechanism", + // effect() { + // tech.isAlwaysFire = true; + // b.setFireMethod(); + // }, + // remove() { + // if (tech.isAlwaysFire) { + // tech.isAlwaysFire = false + // b.setFireMethod(); + // } + // } + // }, + // { + // name: "hidden variable", + // description: `spawn ${powerUps.orb.heal(20)}but hide your health bar`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return !tech.isEnergyHealth + // }, + // requires: "not mass-energy", + // effect() { + // document.getElementById("health").style.display = "none" + // document.getElementById("health-bg").style.display = "none" + // for (let i = 0; i < 20; i++) powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); + // }, + // remove() {} + // }, + // { + // name: "not a bug", + // description: "initiate a totally safe game crash for 10 seconds", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // const savedfunction = simulation.drawCircle + // simulation.drawCircle = () => { + // const a = mob[Infinity].position //crashed the game in a visually interesting way, because of the ctx.translate command is never reverted in the main game loop + // } + // setTimeout(() => { + // simulation.drawCircle = savedfunction + // canvas.width = canvas.width //clears the canvas // works on chrome at least + // powerUps.spawn(m.pos.x, m.pos.y, "tech"); + // }, 10000); + + // // for (;;) {} //freezes the tab + // }, + // remove() {} + // }, + // { + // name: "spinor", + // description: "the direction you aim is determined by your position", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return !m.isShipMode + // }, + // requires: "", + // effect() { + // m.look = function() { + // //always on mouse look + // m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI + // //smoothed mouse look translations + // const scale = 0.8; + // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; + // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; + + // m.transX += (m.transSmoothX - m.transX) * 0.07; + // m.transY += (m.transSmoothY - m.transY) * 0.07; + // } + // }, + // remove() { + // if (this.count) m.look = m.lookDefault + // } + // }, + // { + // name: "decomposers", + // description: "after they die mobs leave behind spawns", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return tech.deathSpawns === 0 + // }, + // requires: "", + // effect() { + // tech.deathSpawns = 0.2 + // }, + // remove() { + // tech.deathSpawns = 0 + // } + // }, + // { + // name: "panopticon", + // description: "mobs can always see you", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // for (let i = 0; i < mob.length; i++) { + // if (!mob[i].shield && mob[i].isDropPowerUp) { + // mob[i].locatePlayer() + // mob[i].seePlayer.yes = true; + // } + // } + // }, 1000); //every 1 seconds + // }, + // remove() {} + // }, + // // { + // // name: "inverted mouse", + // // description: "your mouse is scrambledit's fine, just rotate it 90 degrees", + // // maxCount: 1, + // // count: 0, + // // frequency: 0, + // // isExperimentHide: true, + // // isNonRefundable: true, + // // isJunk: true, + // // allowed() { + // // return !m.isShipMode + // // }, + // // requires: "not ship", + // // effect() { + // // document.body.addEventListener("mousemove", (e) => { + // // const ratio = window.innerWidth / window.innerHeight + // // simulation.mouse.x = e.clientY * ratio + // // simulation.mouse.y = e.clientX / ratio; + // // }); + // // }, + // // remove() { + // // // m.look = m.lookDefault + // // } + // // }, + // { + // name: "Fourier analysis", + // description: "your aiming is now controlled by this equation:2sin(0.0133t) + sin(0.013t) + 0.5sin(0.031t)+ 0.33sin(0.03t)", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, // allowed() { // return !m.isShipMode // }, // requires: "not ship", // effect() { - // document.body.addEventListener("mousemove", (e) => { - // const ratio = window.innerWidth / window.innerHeight - // simulation.mouse.x = e.clientY * ratio - // simulation.mouse.y = e.clientX / ratio; - // }); + // m.look = () => { + // m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03) + // const scale = 0.8; + // simulation.mouse.y + // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; + // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; + // m.transX += (m.transSmoothX - m.transX) * 0.07; + // m.transY += (m.transSmoothY - m.transY) * 0.07; + // } // }, // remove() { - // // m.look = m.lookDefault + // if (this.count) m.look = m.lookDefault // } // }, - { - name: "Fourier analysis", - description: "your aiming is now controlled by this equation:2sin(0.0133t) + sin(0.013t) + 0.5sin(0.031t)+ 0.33sin(0.03t)", - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { - return !m.isShipMode - }, - requires: "not ship", - effect() { - m.look = () => { - m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03) - const scale = 0.8; - simulation.mouse.y - m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; - m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; - m.transX += (m.transSmoothX - m.transX) * 0.07; - m.transY += (m.transSmoothY - m.transY) * 0.07; - } - }, - remove() { - if (this.count) m.look = m.lookDefault - } - }, - { - name: "disintegrated armament", - description: "spawn a gunremove your active gun", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return b.inventory.length > 0 - }, - requires: "at least 1 gun", - effect() { - if (b.inventory.length > 0) b.removeGun(b.guns[b.activeGun].name) - simulation.makeGunHUD() - powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun"); - }, - remove() {} - }, - { - name: "probability", - description: "increase the frequencyof one random tech by 100", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - let options = []; //find what tech I could get - for (let i = 0, len = tech.tech.length; i < len; i++) { - if ( - tech.tech[i].count < tech.tech[i].maxCount && - tech.tech[i].allowed() && - !tech.tech[i].isJunk && - !tech.tech.isLore - ) { - options.push(i); - } - } - if (options.length) { - const index = options[Math.floor(Math.random() * options.length)] - tech.tech[index].frequency = 100 - } - }, - remove() {} - }, - { - name: "encryption", - description: "secure tech information", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - String.prototype.shuffle = function() { - var a = this.split(""), - n = a.length; - - for (var i = n - 1; i > 0; i--) { - var j = Math.floor(Math.random() * (i + 1)); - var tmp = a[i]; - a[i] = a[j]; - a[j] = tmp; - } - return a.join(""); - } - - for (let i = 0, len = tech.tech.length; i < len; i++) tech.tech[i].name = tech.tech[i].name.shuffle() - }, - remove() {} - }, - { - name: "quantum leap", - description: "become an alternate version of yourselfevery 20 seconds", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - m.switchWorlds() - simulation.trails() - }, 20000); //every 30 seconds - }, - remove() {} - }, - { - name: "score", - description: "Add a score to n-gon!", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - let score = Math.ceil(1000 * Math.random() * Math.random() * Math.random() * Math.random() * Math.random()) - simulation.makeTextLog(`simulation.score = ${score.toFixed(0)}`); - }, 10000); //every 10 seconds - }, - remove() {} - }, - { - name: "pop-ups", - description: "sign up to learn endless easy ways to win n-gonthat Landgreen doesn't want you to know!!!1!!", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - alert(`The best combo is ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name} with ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name}!`); - }, 30000); //every 30 seconds - }, - remove() {} - }, - { - name: "music", - description: "add music to n-gon", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - window.open('https://www.youtube.com/watch?v=lEbHeSdmS-k&list=PL9Z5wjoBiPKEDhwCW2RN-VZoCpmhIojdn', '_blank') - }, - remove() {} - }, - { - name: "performance", - description: "display performance stats to n-gon", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - (function() { - var script = document.createElement('script'); - script.onload = function() { - var stats = new Stats(); - document.body.appendChild(stats.dom); - requestAnimationFrame(function loop() { - stats.update(); - requestAnimationFrame(loop) - }); - }; - script.src = 'https://unpkg.com/stats.js@0.17.0/build/stats.min.js'; - document.head.appendChild(script); - })() - //move health to the right - document.getElementById("health").style.left = "86px" - document.getElementById("health-bg").style.left = "86px" - }, - remove() {} - }, - { - name: "repartitioning", - description: "set the frequency of finding normal tech to 0spawn 5 tech", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].isJunk) { - tech.tech[i].frequency = 2 - } else { - tech.tech[i].frequency = 0 - } - } - for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech"); - }, - remove() {} - }, - { - name: "defragment", - description: "set the frequency of finding JUNK tech to zero", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - for (let i = tech.tech.length - 1; i > 0; i--) { - if (tech.tech[i].isJunk) tech.tech[i].frequency = 0 - } - }, - remove() {} - }, // { - // name: "lubrication", - // description: "reduce block density and friction for this level", - // maxCount: 9, + // name: "disintegrated armament", + // description: "spawn a gunremove your active gun", + // maxCount: 1, // count: 0, // frequency: 0, // isNonRefundable: true, - // isExperimentHide: true, // isJunk: true, // allowed() { - // return true + // return b.inventory.length > 0 // }, + // requires: "at least 1 gun", + // effect() { + // if (b.inventory.length > 0) b.removeGun(b.guns[b.activeGun].name) + // simulation.makeGunHUD() + // powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun"); + // }, + // remove() {} + // }, + // { + // name: "probability", + // description: "increase the frequencyof one random tech by 100", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, // requires: "", // effect() { - // for (let i = 0; i < body.length; i++) { - // Matter.Body.setDensity(body[i], 0.0001) // 0.001 is normal - // body[i].friction = 0.01 + // let options = []; //find what tech I could get + // for (let i = 0, len = tech.tech.length; i < len; i++) { + // if ( + // tech.tech[i].count < tech.tech[i].maxCount && + // tech.tech[i].allowed() && + // !tech.tech[i].isJunk && + // !tech.tech.isLore + // ) { + // options.push(i); + // } + // } + // if (options.length) { + // const index = options[Math.floor(Math.random() * options.length)] + // tech.tech[index].frequency = 100 // } // }, // remove() {} // }, - { - name: "pitch", - description: "oscillate the pitch of your world", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01)) }, 16); - }, - remove() {} - }, - { - name: "umbra", - description: "produce a blue glow around everythingand probably some simulation lag", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - ctx.shadowColor = '#06f'; - ctx.shadowBlur = 25; - }, - remove() {} - }, - { - name: "lighter", - description: `ctx.globalCompositeOperation = "lighter"`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return m.fieldUpgrades[m.fieldMode].name !== "negative mass" - }, - requires: "", - effect() { - ctx.globalCompositeOperation = "lighter"; - }, - remove() {} - }, - { - name: "rewind", - description: "every 10 seconds rewind 2 seconds", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - m.rewind(120) - m.energy += 0.4 - }, 10000); - // for (let i = 0; i < 24; i++) { - // setTimeout(() => { m.rewind(120) }, i * 5000); - // } - }, - remove() {} - }, - { - name: "undo", - description: "every 4 seconds rewind 1/2 a second", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - m.rewind(30) - m.energy += 0.2 - }, 4000); - }, - remove() {} - }, - { - name: "energy to mass conversion", - description: "convert your energy into blocks", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - for (let i = 0, len = 40; i < len; i++) { - setTimeout(() => { - m.energy -= 1 / len - const index = body.length - where = Vector.add(m.pos, { x: 400 * (Math.random() - 0.5), y: 400 * (Math.random() - 0.5) }) - spawn.bodyRect(where.x, where.y, Math.floor(15 + 100 * Math.random()), Math.floor(15 + 100 * Math.random())); - body[index].collisionFilter.category = cat.body; - body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet - body[index].classType = "body"; - Composite.add(engine.world, body[index]); //add to world - }, i * 100); - } - - }, - remove() {} - }, - { - name: "level.nextLevel()", - description: "advance to the next level", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - level.nextLevel(); - }, - remove() {} - }, - { - name: "reincarnation", - description: "kill all mobs and spawn new ones(also spawn a few extra mobs for fun)", - maxCount: 3, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - spawn.setSpawnList(); - spawn.setSpawnList(); - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].alive && !mob[i].shield && !mob[i].isBadTarget) { - const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; - spawn[pick](mob[i].position.x, mob[i].position.y); - if (Math.random() < 0.5) spawn[pick](mob[i].position.x, mob[i].position.y); - mob[i].death(); - } - } - }, - remove() {} - }, - { - name: "expert system", - description: "spawn a tech power up+64% JUNK to tech pool", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - powerUps.spawn(m.pos.x, m.pos.y, "tech"); - tech.addJunkTechToPool(0.64) - }, - remove() {} - }, - { - name: "energy investment", - description: "every 10 seconds drain your energyreturn it doubled 5 seconds later", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - if (!simulation.paused) { - const energy = m.energy - m.energy = 0 - setTimeout(() => { //return energy - m.energy += 2 * energy - }, 5000); - } - }, 10000); - }, - remove() {} - }, - { - name: "missile launching system", - description: "fire missiles for the next 120 seconds", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - for (let i = 0; i < 120; i++) { - setTimeout(() => { - const where = { - x: m.pos.x, - y: m.pos.y - 40 - } - b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2) - }, i * 1000); - } - }, - remove() {} - }, - { - name: "grenade production", - description: "drop a grenade every 2 seconds", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - setInterval(() => { - if (!simulation.paused && document.visibilityState !== "hidden") { - b.grenade(Vector.add(m.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -Math.PI / 2) //fire different angles for each grenade - const who = bullet[bullet.length - 1] - Matter.Body.setVelocity(who, { - x: who.velocity.x * 0.1, - y: who.velocity.y * 0.1 - }); - } - }, 2000); - }, - remove() {} - }, // { - // name: "inverted input", - // description: "left input becomes right and up input becomes down", + // name: "encryption", + // description: "secure tech information", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // String.prototype.shuffle = function() { + // var a = this.split(""), + // n = a.length; + + // for (var i = n - 1; i > 0; i--) { + // var j = Math.floor(Math.random() * (i + 1)); + // var tmp = a[i]; + // a[i] = a[j]; + // a[j] = tmp; + // } + // return a.join(""); + // } + + // for (let i = 0, len = tech.tech.length; i < len; i++) tech.tech[i].name = tech.tech[i].name.shuffle() + // }, + // remove() {} + // }, + // { + // name: "quantum leap", + // description: "become an alternate version of yourselfevery 20 seconds", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // m.switchWorlds() + // simulation.trails() + // }, 20000); //every 30 seconds + // }, + // remove() {} + // }, + // { + // name: "score", + // description: "Add a score to n-gon!", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // let score = Math.ceil(1000 * Math.random() * Math.random() * Math.random() * Math.random() * Math.random()) + // simulation.makeTextLog(`simulation.score = ${score.toFixed(0)}`); + // }, 10000); //every 10 seconds + // }, + // remove() {} + // }, + // { + // name: "pop-ups", + // description: "sign up to learn endless easy ways to win n-gonthat Landgreen doesn't want you to know!!!1!!", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // alert(`The best combo is ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name} with ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name}!`); + // }, 30000); //every 30 seconds + // }, + // remove() {} + // }, + // { + // name: "music", + // description: "add music to n-gon", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // window.open('https://www.youtube.com/watch?v=lEbHeSdmS-k&list=PL9Z5wjoBiPKEDhwCW2RN-VZoCpmhIojdn', '_blank') + // }, + // remove() {} + // }, + // { + // name: "performance", + // description: "display performance stats to n-gon", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // (function() { + // var script = document.createElement('script'); + // script.onload = function() { + // var stats = new Stats(); + // document.body.appendChild(stats.dom); + // requestAnimationFrame(function loop() { + // stats.update(); + // requestAnimationFrame(loop) + // }); + // }; + // script.src = 'https://unpkg.com/stats.js@0.17.0/build/stats.min.js'; + // document.head.appendChild(script); + // })() + // //move health to the right + // document.getElementById("health").style.left = "86px" + // document.getElementById("health-bg").style.left = "86px" + // }, + // remove() {} + // }, + // { + // name: "repartitioning", + // description: "set the frequency of finding normal tech to 0spawn 5 tech", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // for (let i = 0, len = tech.tech.length; i < len; i++) { + // if (tech.tech[i].isJunk) { + // tech.tech[i].frequency = 2 + // } else { + // tech.tech[i].frequency = 0 + // } + // } + // for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech"); + // }, + // remove() {} + // }, + // { + // name: "defragment", + // description: "set the frequency of finding JUNK tech to zero", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // for (let i = tech.tech.length - 1; i > 0; i--) { + // if (tech.tech[i].isJunk) tech.tech[i].frequency = 0 + // } + // }, + // remove() {} + // }, + // // { + // // name: "lubrication", + // // description: "reduce block density and friction for this level", + // // maxCount: 9, + // // count: 0, + // // frequency: 0, + // // isNonRefundable: true, + // // isExperimentHide: true, + // // isJunk: true, + // // allowed() { + // // return true + // // }, + // // requires: "", + // // effect() { + // // for (let i = 0; i < body.length; i++) { + // // Matter.Body.setDensity(body[i], 0.0001) // 0.001 is normal + // // body[i].friction = 0.01 + // // } + // // }, + // // remove() {} + // // }, + // { + // name: "pitch", + // description: "oscillate the pitch of your world", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01)) }, 16); + // }, + // remove() {} + // }, + // { + // name: "umbra", + // description: "produce a blue glow around everythingand probably some simulation lag", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // ctx.shadowColor = '#06f'; + // ctx.shadowBlur = 25; + // }, + // remove() {} + // }, + // { + // name: "lighter", + // description: `ctx.globalCompositeOperation = "lighter"`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return m.fieldUpgrades[m.fieldMode].name !== "negative mass" + // }, + // requires: "", + // effect() { + // ctx.globalCompositeOperation = "lighter"; + // }, + // remove() {} + // }, + // { + // name: "rewind", + // description: "every 10 seconds rewind 2 seconds", // maxCount: 9, // count: 0, // frequency: 0, // isNonRefundable: true, - // isExperimentHide: true, // isJunk: true, - // allowed() { - // return true - // }, + // allowed() { return true }, // requires: "", // effect() { - // const left = input.key.left - // input.key.left = input.key.right - // input.key.right = left - - // const up = input.key.up - // input.key.up = input.key.down - // input.key.down = up + // setInterval(() => { + // m.rewind(120) + // m.energy += 0.4 + // }, 10000); + // // for (let i = 0; i < 24; i++) { + // // setTimeout(() => { m.rewind(120) }, i * 5000); + // // } // }, // remove() {} // }, - { - name: "Sleipnir", - description: "grow more legs", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isNonRefundable: true, - isJunk: true, - allowed() { return !m.isShipMode }, - requires: "", - effect() { - m.draw = function() { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; + // { + // name: "undo", + // description: "every 4 seconds rewind 1/2 a second", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // m.rewind(30) + // m.energy += 0.2 + // }, 4000); + // }, + // remove() {} + // }, + // { + // name: "energy to mass conversion", + // description: "convert your energy into blocks", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // for (let i = 0, len = 40; i < len; i++) { + // setTimeout(() => { + // m.energy -= 1 / len + // const index = body.length + // where = Vector.add(m.pos, { x: 400 * (Math.random() - 0.5), y: 400 * (Math.random() - 0.5) }) + // spawn.bodyRect(where.x, where.y, Math.floor(15 + 100 * Math.random()), Math.floor(15 + 100 * Math.random())); + // body[index].collisionFilter.category = cat.body; + // body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet + // body[index].classType = "body"; + // Composite.add(engine.world, body[index]); //add to world + // }, i * 100); + // } - //draw body - 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); + // }, + // remove() {} + // }, + // { + // name: "level.nextLevel()", + // description: "advance to the next level", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // level.nextLevel(); + // }, + // remove() {} + // }, + // { + // name: "reincarnation", + // description: "kill all mobs and spawn new ones(also spawn a few extra mobs for fun)", + // maxCount: 3, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // spawn.setSpawnList(); + // spawn.setSpawnList(); + // for (let i = 0, len = mob.length; i < len; i++) { + // if (mob[i].alive && !mob[i].shield && !mob[i].isBadTarget) { + // const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; + // spawn[pick](mob[i].position.x, mob[i].position.y); + // if (Math.random() < 0.5) spawn[pick](mob[i].position.x, mob[i].position.y); + // mob[i].death(); + // } + // } + // }, + // remove() {} + // }, + // { + // name: "expert system", + // description: "spawn a tech power up+64% JUNK to tech pool", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // powerUps.spawn(m.pos.x, m.pos.y, "tech"); + // tech.addJunkTechToPool(0.64) + // }, + // remove() {} + // }, + // { + // name: "energy investment", + // description: "every 10 seconds drain your energyreturn it doubled 5 seconds later", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // if (!simulation.paused) { + // const energy = m.energy + // m.energy = 0 + // setTimeout(() => { //return energy + // m.energy += 2 * energy + // }, 5000); + // } + // }, 10000); + // }, + // remove() {} + // }, + // { + // name: "missile launching system", + // description: "fire missiles for the next 120 seconds", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // for (let i = 0; i < 120; i++) { + // setTimeout(() => { + // const where = { + // x: m.pos.x, + // y: m.pos.y - 40 + // } + // b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2) + // }, i * 1000); + // } + // }, + // remove() {} + // }, + // { + // name: "grenade production", + // description: "drop a grenade every 2 seconds", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // setInterval(() => { + // if (!simulation.paused && document.visibilityState !== "hidden") { + // b.grenade(Vector.add(m.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -Math.PI / 2) //fire different angles for each grenade + // const who = bullet[bullet.length - 1] + // Matter.Body.setVelocity(who, { + // x: who.velocity.x * 0.1, + // y: who.velocity.y * 0.1 + // }); + // } + // }, 2000); + // }, + // remove() {} + // }, + // // { + // // name: "inverted input", + // // description: "left input becomes right and up input becomes down", + // // maxCount: 9, + // // count: 0, + // // frequency: 0, + // // isNonRefundable: true, + // // isExperimentHide: true, + // // isJunk: true, + // // allowed() { + // // return true + // // }, + // // requires: "", + // // effect() { + // // const left = input.key.left + // // input.key.left = input.key.right + // // input.key.right = left - 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.beginPath(); - // ctx.arc(15, 0, 3, 0, 2 * Math.PI); - // ctx.fillStyle = '#0cf'; - // ctx.fill() - ctx.restore(); - m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal - } - }, - remove() {} - }, - { - name: "diegesis", - description: "indicate fire cooldownthrough a rotation of your head", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isNonRefundable: true, - isJunk: true, - allowed() { return !m.isShipMode }, - requires: "", - effect() { - m.draw = function() { - ctx.fillStyle = m.fillColor; - m.walk_cycle += m.flipLegs * m.Vx; + // // const up = input.key.up + // // input.key.up = input.key.down + // // input.key.down = up + // // }, + // // remove() {} + // // }, + // { + // name: "Sleipnir", + // description: "grow more legs", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return !m.isShipMode }, + // requires: "", + // effect() { + // 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)); + // //draw body + // 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 - } - }, - remove() {} - }, - { - name: "🐱", - description: "🐈", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isNonRefundable: true, - isJunk: true, - allowed() { - return !m.isShipMode - }, - requires: "", - effect() { - 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"); + // 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.beginPath(); + // // ctx.arc(15, 0, 3, 0, 2 * Math.PI); + // // ctx.fillStyle = '#0cf'; + // // ctx.fill() + // ctx.restore(); + // m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + // } + // }, + // remove() {} + // }, + // { + // name: "diegesis", + // description: "indicate fire cooldownthrough a rotation of your head", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return !m.isShipMode }, + // requires: "", + // effect() { + // 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 + // } + // }, + // remove() {} + // }, + // { + // name: "🐱", + // description: "🐈", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return !m.isShipMode + // }, + // requires: "", + // effect() { + // 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(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"); + // 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.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.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.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 - } - }, - remove() {} - }, - { - name: "transparency", - description: "become invisible to yourselfmobs can still see you", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - m.draw = () => {} - }, - remove() {} - }, - { - name: "posture", - description: "stand a bit taller", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isJunk: true, - allowed() { - return !m.isShipMode - }, - requires: "", - effect() { - m.yOffWhen.stand = 70 - }, - remove() { - m.yOffWhen.stand = 49 - } - }, - { - name: "rhythm", - description: "you oscillate up and down", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isJunk: true, - isNonRefundable: true, - allowed() { - return !m.isShipMode - }, - requires: "", - effect() { - setInterval(() => { - m.yOffWhen.stand = 53 + 28 * Math.sin(simulation.cycle * 0.2) - if (m.onGround && !m.crouch) m.yOffGoal = m.yOffWhen.stand - }, 100); - }, - remove() {} - }, - { - name: "pareidolia", - description: "don't", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isNonRefundable: true, - isJunk: true, - allowed() { - return !m.isShipMode - }, - requires: "", - effect() { - 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; - } - }, - remove() {} - }, - { - name: "prism", - description: "you cycle through different colors", - maxCount: 1, - count: 0, - frequency: 0, - isSkin: true, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - m.color = { - hue: 0, - sat: 100, - light: 50 - } - setInterval(function() { - m.color.hue++ - m.setFillColors() - }, 10); - }, - remove() {} - }, - { - name: "microtransactions", - description: `when you choose a tech you canuse ${powerUps.orb.research(1)} to buy a free in game skin`, - maxCount: 1, - count: 0, - frequency: 0, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - tech.isMicroTransactions = true - }, - remove() { - tech.isMicroTransactions = false - } - }, - { - name: "ship", - description: "fly around with no legsreduce combat difficulty by 1 level", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return !m.isShipMode && m.fieldUpgrades[m.fieldMode].name !== "negative mass" - }, - requires: "", - effect() { - m.shipMode() - level.difficultyDecrease(simulation.difficultyMode) - }, - remove() {} - }, - { - name: "assimilation", - description: "all your bots are converted to the same random model", - maxCount: 1, - count: 0, - frequency: 0, - isBotTech: true, - isNonRefundable: true, - isJunk: true, - allowed() { - return b.totalBots() > 2 - }, - requires: "at least 3 bots", - effect() { - const total = b.totalBots(); - tech.dynamoBotCount = 0; - tech.nailBotCount = 0; - tech.laserBotCount = 0; - tech.orbitBotCount = 0; - tech.foamBotCount = 0; - tech.boomBotCount = 0; - tech.plasmaBotCount = 0; - tech.missileBotCount = 0; - for (let i = 0; i < bullet.length; i++) { - if (bullet[i].botType) bullet[i].endCycle = 0 - } + // ctx.restore(); + // m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + // } + // }, + // remove() {} + // }, + // { + // name: "transparency", + // description: "become invisible to yourselfmobs can still see you", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // m.draw = () => {} + // }, + // remove() {} + // }, + // { + // name: "posture", + // description: "stand a bit taller", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isJunk: true, + // allowed() { + // return !m.isShipMode + // }, + // requires: "", + // effect() { + // m.yOffWhen.stand = 70 + // }, + // remove() { + // m.yOffWhen.stand = 49 + // } + // }, + // { + // name: "rhythm", + // description: "you oscillate up and down", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isJunk: true, + // isNonRefundable: true, + // allowed() { + // return !m.isShipMode + // }, + // requires: "", + // effect() { + // setInterval(() => { + // m.yOffWhen.stand = 53 + 28 * Math.sin(simulation.cycle * 0.2) + // if (m.onGround && !m.crouch) m.yOffGoal = m.yOffWhen.stand + // }, 100); + // }, + // remove() {} + // }, + // { + // name: "pareidolia", + // description: "don't", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return !m.isShipMode + // }, + // requires: "", + // effect() { + // 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; + // } + // }, + // remove() {} + // }, + // { + // name: "prism", + // description: "you cycle through different colors", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isSkin: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // m.color = { + // hue: 0, + // sat: 100, + // light: 50 + // } + // setInterval(function() { + // m.color.hue++ + // m.setFillColors() + // }, 10); + // }, + // remove() {} + // }, + // { + // name: "microtransactions", + // description: `when you choose a tech you canuse ${powerUps.orb.research(1)} to buy a free in game skin`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // tech.isMicroTransactions = true + // }, + // remove() { + // tech.isMicroTransactions = false + // } + // }, + // { + // name: "ship", + // description: "fly around with no legsreduce combat difficulty by 1 level", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return !m.isShipMode && m.fieldUpgrades[m.fieldMode].name !== "negative mass" + // }, + // requires: "", + // effect() { + // m.shipMode() + // level.difficultyDecrease(simulation.difficultyMode) + // }, + // remove() {} + // }, + // { + // name: "assimilation", + // description: "all your bots are converted to the same random model", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isBotTech: true, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return b.totalBots() > 2 + // }, + // requires: "at least 3 bots", + // effect() { + // const total = b.totalBots(); + // tech.dynamoBotCount = 0; + // tech.nailBotCount = 0; + // tech.laserBotCount = 0; + // tech.orbitBotCount = 0; + // tech.foamBotCount = 0; + // tech.boomBotCount = 0; + // tech.plasmaBotCount = 0; + // tech.missileBotCount = 0; + // for (let i = 0; i < bullet.length; i++) { + // if (bullet[i].botType) bullet[i].endCycle = 0 + // } - const bots = [ - () => { - b.nailBot(); - tech.nailBotCount++; - }, - () => { - b.foamBot(); - tech.foamBotCount++; - }, - () => { - b.boomBot(); - tech.boomBotCount++; - }, - () => { - b.laserBot(); - tech.laserBotCount++; - }, - () => { - b.orbitBot(); - tech.orbitBotCount++ - }, - () => { - b.dynamoBot(); - tech.dynamoBotCount++ - } - ] - const index = Math.floor(Math.random() * bots.length) - for (let i = 0; i < total; i++) bots[index]() - }, - remove() {} - }, - { - name: "growth hacking", - description: "increase combat difficulty by 1 level", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - level.difficultyIncrease(simulation.difficultyMode) - }, - remove() {} - }, - { - name: "stun", - description: "stun all mobs for up to 8 seconds", - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480) - }, - remove() {} - }, - { - name: "translucent", - description: "remove your guns and spawn new onesyour bullets and bots are transparent", - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - for (let i = 0; i < b.inventory.length; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun"); + // const bots = [ + // () => { + // b.nailBot(); + // tech.nailBotCount++; + // }, + // () => { + // b.foamBot(); + // tech.foamBotCount++; + // }, + // () => { + // b.boomBot(); + // tech.boomBotCount++; + // }, + // () => { + // b.laserBot(); + // tech.laserBotCount++; + // }, + // () => { + // b.orbitBot(); + // tech.orbitBotCount++ + // }, + // () => { + // b.dynamoBot(); + // tech.dynamoBotCount++ + // } + // ] + // const index = Math.floor(Math.random() * bots.length) + // for (let i = 0; i < total; i++) bots[index]() + // }, + // remove() {} + // }, + // { + // name: "growth hacking", + // description: "increase combat difficulty by 1 level", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // level.difficultyIncrease(simulation.difficultyMode) + // }, + // remove() {} + // }, + // { + // name: "stun", + // description: "stun all mobs for up to 8 seconds", + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480) + // }, + // remove() {} + // }, + // { + // name: "translucent", + // description: "remove your guns and spawn new onesyour bullets and bots are transparent", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // for (let i = 0; i < b.inventory.length; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun"); - //removes guns and ammo - b.inventory = []; - b.activeGun = null; - b.inventoryGun = 0; - for (let i = 0, len = b.guns.length; i < len; ++i) { - b.guns[i].have = false; - if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0; - } - simulation.makeGunHUD(); //update gun HUD - b.bulletDraw = () => {}; - }, - remove() {} - }, - { - name: "re-research", - description: `eject all your ${powerUps.orb.research(1)}`, - maxCount: 9, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return powerUps.research.count > 3 - }, - requires: "at least 4 research", - effect() { - const dist = 10 * powerUps.research.count + 100 - for (let i = 0; i < powerUps.research.count; i++) { - powerUps.directSpawn(m.pos.x + dist * (Math.random() - 0.5), m.pos.y + dist * (Math.random() - 0.5), "research"); - } - powerUps.research.count = 0 - }, - remove() {} - }, - { - name: "black hole", - description: `use your energy and ${powerUps.orb.research(4)} to spawninside the event horizon of a huge black hole`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { - return powerUps.research.count > 3 - }, - requires: "at least 4 research", - effect() { - m.energy = 0 - spawn.suckerBoss(m.pos.x, m.pos.y - 700) - powerUps.research.changeRerolls(-4) - simulation.makeTextLog(`m.research --${powerUps.research.count}`) - }, - remove() {} - }, - { - name: "black hole cluster", - description: `spawn 30 nearby black holes`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - const unit = { x: 1, y: 0 } - for (let i = 0; i < 30; i++) { - const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random())) - spawn.sucker(where.x, where.y, 140) - const who = mob[mob.length - 1] - who.locatePlayer() - // who.damageReduction = 0.2 - } - }, - remove() {} - }, + // //removes guns and ammo + // b.inventory = []; + // b.activeGun = null; + // b.inventoryGun = 0; + // for (let i = 0, len = b.guns.length; i < len; ++i) { + // b.guns[i].have = false; + // if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0; + // } + // simulation.makeGunHUD(); //update gun HUD + // b.bulletDraw = () => {}; + // }, + // remove() {} + // }, + // { + // name: "re-research", + // description: `eject all your ${powerUps.orb.research(1)}`, + // maxCount: 9, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return powerUps.research.count > 3 + // }, + // requires: "at least 4 research", + // effect() { + // const dist = 10 * powerUps.research.count + 100 + // for (let i = 0; i < powerUps.research.count; i++) { + // powerUps.directSpawn(m.pos.x + dist * (Math.random() - 0.5), m.pos.y + dist * (Math.random() - 0.5), "research"); + // } + // powerUps.research.count = 0 + // }, + // remove() {} + // }, + // { + // name: "black hole", + // description: `use your energy and ${powerUps.orb.research(4)} to spawninside the event horizon of a huge black hole`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { + // return powerUps.research.count > 3 + // }, + // requires: "at least 4 research", + // effect() { + // m.energy = 0 + // spawn.suckerBoss(m.pos.x, m.pos.y - 700) + // powerUps.research.changeRerolls(-4) + // simulation.makeTextLog(`m.research --${powerUps.research.count}`) + // }, + // remove() {} + // }, + // { + // name: "black hole cluster", + // description: `spawn 30 nearby black holes`, + // maxCount: 1, + // count: 0, + // frequency: 0, + // isNonRefundable: true, + // isJunk: true, + // allowed() { return true }, + // requires: "", + // effect() { + // const unit = { x: 1, y: 0 } + // for (let i = 0; i < 30; i++) { + // const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random())) + // spawn.sucker(where.x, where.y, 140) + // const who = mob[mob.length - 1] + // who.locatePlayer() + // // who.damageReduction = 0.2 + // } + // }, + // remove() {} + // }, // { // name: "JUNKie", //just crashes the game // description: "all junk", @@ -10085,6 +10088,7 @@ const tech = { isJunk: true, allowed() { return !build.isExperimentSelection }, requires: "NOT EXPERIMENT MODE", + effect() {}, remove() {}, state: [ [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false] @@ -10458,7 +10462,7 @@ const tech = { isLowHealthDefense: null, isLowHealthFireRate: null, isFarAwayDmg: null, - isEntanglement: null, + isFirstOrder: null, isMassEnergy: null, extraChoices: null, laserBotCount: null, diff --git a/todo.txt b/todo.txt index 6929535..e58f20a 100644 --- a/todo.txt +++ b/todo.txt @@ -1,24 +1,51 @@ ******************************************************** NEXT PATCH ************************************************** -matter wave renamed wave - tech: frequency - wave has unlimited ammo, but -50% wave firerate - tech: sympathetic resonance - when phonon waves hit a mob they make a new resonance wave - effect cooldown grows +5s with each chained resonance - uncertainty principle works with phonon wave - phase velocity works with all other wave tech, 40->35% damage - boundstate reduces wave range by 25->15% -non-renewables 88% -> 67% damage -improved fine-structure constant graphic for when you lose coupling -laser mobs pulse a laser 50% of the time for 2x damage +ghoster mobs are faster +teatherBoss spawns some seekerBullets on death +added 2 more lore chapters + 7 total -a bunch of bug fixes -caliber does a bit more damage at 1 stack, but does less damage at 3+ stacks - it grew mass and damage at an exponential rate before - now it's closer to the +30% damage description +bug fixes + updated requirements text *********************************************************** TODO ***************************************************** + +complete the final lore chapters + track mob kills with simulation.killCount + if killCount is below 3-4 on entering gauntlet fill with starters + if killCount is below 3-4 on finalBoss fill with starters + if lorecount is on final chapter open door + + have conversation + the AI doesn't really see it's self as the player or the mobs + it doesn't have a "self" or an ego like we do + but it can learn about the world and it learned a non violent way to solve problems + of course there are still other simulations going on at the same time as thing one that are probably violent + but at least it now has an example of the potential for peace + if Pacifist run is too hard, spawn a field at the start instead of a gun (because lore says they can spawn things) + +reduce gravity while field is active (as if the field is a parachute/glider) + reduce gravity when velocity.y > 2 and field is active + make standard no tech needed + all fields? + perfect diamagnetism, molecular assembler, field emitter + standing wave effect is always on? + +make duplication less effective on why difficulty + scale the numbers in the tech + +deflecting coupling effect should be not fun + trade bremstralung for iceIX + +tech - buff MACHO range, effect, move speed? + +PWA? + https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps + https://codeburst.io/how-to-easily-turn-your-static-website-to-a-progressive-web-app-pwa-b0af08da9693 + https://github.com/landgreen/n-gon/pull/32/files + bug blocks and power ups falling through map always foam gun (4-5 times) might be about tech pressure vessel @@ -732,11 +759,6 @@ n-gon outreach ideas ******************************************************** BUGS ******************************************************** -timeskip flickers with tech: clock gating, and game pause after large hit - probably not related to timeskip, related to graphics effect - not a big problem, actually it's kinda neat effect - only fix if there is a clear solution - bug: maybe I can put in an event listener to reset inputs to false when you tab out to prevent key sticking bug - url sharing still broken sometimes @@ -950,6 +972,8 @@ possible names for tech https://en.wikipedia.org/wiki/High-entropy_alloys https://en.wikipedia.org/wiki/Refractory_metals https://en.wikipedia.org/wiki/Upper-atmospheric_lightning#Elves + entanglement + prion quine plot script: