diff --git a/.DS_Store b/.DS_Store index 6a7a2b0..e8e965f 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/index.html b/index.html index 48f0060..19afb94 100644 --- a/index.html +++ b/index.html @@ -114,14 +114,14 @@

diff --git a/js/bullet.js b/js/bullet.js index 7c6497f..ed1ac9b 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -315,11 +315,11 @@ const b = { } if (tech.isExplodeRadio) { //radiation explosion - const alertRange = 100 + radius * 2; //alert range + radius *= 1.25; //alert range simulation.drawList.push({ //add dmg to draw queue x: where.x, y: where.y, - radius: alertRange, + radius: radius, color: "rgba(25,139,170,0.25)", time: simulation.drawTime * 2 }); @@ -328,9 +328,13 @@ const b = { sub = Vector.sub(where, player.position); dist = Vector.magnitude(sub); - if (dist < alertRange) { - m.energy -= 0.23 * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1) - if (m.energy < 0) m.energy = 0 + if (dist < radius) { + const drain = (tech.isExplosionHarm ? 0.5 : 0.25) * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1) + m.energy -= drain + if (m.energy < 0) { + m.energy = 0 + m.damage(0.03); + } } //mob damage and knock back with alert @@ -339,10 +343,10 @@ const b = { if (mob[i].alive && !mob[i].isShielded) { sub = Vector.sub(where, mob[i].position); dist = Vector.magnitude(sub) - mob[i].radius; - if (dist < alertRange) { + if (dist < radius) { if (mob[i].shield) dmg *= 2.5 //balancing explosion dmg to shields if (Matter.Query.ray(map, mob[i].position, where).length > 0) dmg *= 0.5 //reduce damage if a wall is in the way - mobs.statusDoT(mob[i], dmg * damageScale * 0.2, 240) //apply radiation damage status effect on direct hits + mobs.statusDoT(mob[i], dmg * damageScale * 0.25, 240) //apply radiation damage status effect on direct hits mob[i].locatePlayer(); damageScale *= 0.87 //reduced damage for each additional explosion target } @@ -1077,7 +1081,7 @@ const b = { didExtruderDrain: false, canExtruderFire: true, extruder() { - const DRAIN = 0.0007 + m.fieldRegen + const DRAIN = 0.0006 + m.fieldRegen if (m.energy > DRAIN && b.canExtruderFire) { m.energy -= DRAIN if (m.energy < 0) { @@ -1096,7 +1100,7 @@ const b = { frictionAir: 0, isInHole: true, //this keeps the bullet from entering wormholes minDmgSpeed: 0, - dmg: b.dmgScale * 1.25, //damage also changes when you divide by mob.mass on in .do() + dmg: b.dmgScale * 1.35, //damage also changes when you divide by mob.mass on in .do() classType: "bullet", isBranch: false, restitution: 0, @@ -2545,7 +2549,7 @@ const b = { dmg: 0, // 0.14 //damage done in addition to the damage from momentum minDmgSpeed: 2, lookFrequency: 40 + Math.floor(7 * Math.random()), - drainThreshold: tech.isEnergyHealth ? 0.5 : 0.33, + drainThreshold: tech.isEnergyHealth ? 0.6 : 0.4, acceleration: 0.0015 * (1 + 0.3 * Math.random()), range: 700 * (1 + 0.1 * Math.random()) + 300 * tech.isLaserBotUpgrade, playerRange: 150 + Math.floor(30 * Math.random()), @@ -2711,7 +2715,7 @@ const b = { cd: 0, acceleration: 0.009, endCycle: Infinity, - drainThreshold: tech.isEnergyHealth ? 0.4 : 0.2, + drainThreshold: tech.isEnergyHealth ? 0.5 : 0.33, classType: "bullet", collisionFilter: { category: cat.bullet, diff --git a/js/index.js b/js/index.js index a580807..605689f 100644 --- a/js/index.js +++ b/js/index.js @@ -196,6 +196,7 @@ const build = {

level: ${level.levels[level.onLevel]} (${level.difficultyText()})   ${m.cycle} cycles
${mob.length} mobs,   ${body.length} blocks,   ${bullet.length} bullets,   ${powerUp.length} power ups +
damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }%
harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}%
heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}% diff --git a/js/level.js b/js/level.js index d9e475c..32fcdec 100644 --- a/js/level.js +++ b/js/level.js @@ -7,7 +7,6 @@ const level = { defaultZoom: 1400, onLevel: -1, levelsCleared: 0, - bossKilled: false, playableLevels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber"], levels: [], start() { @@ -111,26 +110,26 @@ const level = { difficultyIncrease(num = 1) { for (let i = 0; i < num; i++) { simulation.difficulty++ - b.dmgScale *= 0.93; //damage done by player decreases each level + b.dmgScale *= 0.94; //damage done by player decreases each level if (simulation.accelScale < 5) simulation.accelScale *= 1.02 //mob acceleration increases each level if (simulation.lookFreqScale > 0.2) simulation.lookFreqScale *= 0.98 //mob cycles between looks decreases each level if (simulation.CDScale > 0.2) simulation.CDScale *= 0.97 //mob CD time decreases each level } - simulation.dmgScale = 0.378 * simulation.difficulty //damage done by mobs increases each level - simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; + simulation.dmgScale = 0.36 * simulation.difficulty //damage done by mobs increases each level + simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; }, difficultyDecrease(num = 1) { //used in easy mode for simulation.reset() for (let i = 0; i < num; i++) { simulation.difficulty-- - b.dmgScale /= 0.93; //damage done by player decreases each level + b.dmgScale /= 0.94; //damage done by player decreases each level if (simulation.accelScale > 0.2) simulation.accelScale /= 1.02 //mob acceleration increases each level if (simulation.lookFreqScale < 5) simulation.lookFreqScale /= 0.98 //mob cycles between looks decreases each level if (simulation.CDScale < 5) simulation.CDScale /= 0.97 //mob CD time decreases each level } if (simulation.difficulty < 1) simulation.difficulty = 0; - simulation.dmgScale = 0.378 * simulation.difficulty //damage done by mobs increases each level + simulation.dmgScale = 0.36 * simulation.difficulty //damage done by mobs increases each level if (simulation.dmgScale < 0.1) simulation.dmgScale = 0.1; - simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) + simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) }, difficultyText() { if (simulation.difficultyMode === 1) { @@ -1052,7 +1051,8 @@ const level = { spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump // spawn.boost(1500, 0, 900); - spawn.starter(1900, -500, 200) //big boy + // spawn.starter(1900, -500, 200) //big boy + spawn.historyBoss(1900, -500) // spawn.sneaker(2900, -500) // spawn.launcherBoss(1200, -500) // spawn.laserTargetingBoss(1600, -400) @@ -1066,7 +1066,7 @@ const level = { // spawn.beamer(1200, -500) // spawn.shield(mob[mob.length - 1], 1800, -120, 1); - // spawn.nodeBoss(1200, -500, "launcher") + // spawn.nodeGroup(1200, -500, "launcher") // spawn.snakeBoss(1200, -500) // spawn.powerUpBoss(2900, -500) // spawn.randomMob(1600, -500) @@ -1105,13 +1105,12 @@ const level = { // spawn.boost(4150, 0, 1300); // spawn.randomSmallMob(1300, -70); // spawn.randomMob(2650, -975, 0.8); - // spawn.randomBoss(1700, -900, 0.4); + // spawn.randomGroup(1700, -900, 0.4); // if (simulation.difficulty > 3) spawn.randomLevelBoss(2200, -1300); powerUps.addRerollToLevel() //needs to run after mobs are spawned // if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500); }, final() { - level.bossKilled = false; // if a boss needs to be killed level.custom = () => { level.playerExitCheck(); }; @@ -1162,7 +1161,6 @@ const level = { if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500); }, gauntlet() { - level.bossKilled = true; //if there is no boss this needs to be true to increase levels level.custom = () => { level.playerExitCheck(); }; @@ -1199,12 +1197,12 @@ const level = { spawn.blockDoor(2585, -210) spawn.mapRect(2500, -200, 200, 300); //right wall - spawn.nodeBoss(3500, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); + 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.lineBoss(5000, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); + 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 @@ -1212,20 +1210,19 @@ const level = { for (let i = 0; i < 3; ++i) { if (simulation.difficulty * Math.random() > 15 * i) { - spawn.randomBoss(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); + spawn.randomGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); } if (simulation.difficulty * Math.random() > 10 * i) { - spawn.randomBoss(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); + spawn.randomGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); } if (simulation.difficulty * Math.random() > 7 * i) { - spawn.randomBoss(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); + spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); } } powerUps.addRerollToLevel() //needs to run after mobs are spawned if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350); }, intro() { - level.bossKilled = true; //if there is no boss this needs to be true to increase levels level.custom = () => { level.playerExitCheck(); }; @@ -1709,7 +1706,7 @@ const level = { spawn.randomMob(1550, -2750, -0.5); spawn.randomMob(1350, -1150, -0.5); spawn.randomMob(-75, -1475, 0); - spawn.randomBoss(600, -2600, 0); + spawn.randomGroup(600, -2600, 0); } if (simulation.difficulty < 25) { spawn.randomMob(700, -1650, 0); @@ -1727,7 +1724,6 @@ const level = { if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1925, -1250); }, sewers() { - level.bossKilled = false; // if a boss needs to be killed const rotor = level.rotor(5100, 2475, -0.001) const button = level.button(6600, 2675) const hazard = level.hazard(4550, 2750, 4550, 150) @@ -1844,7 +1840,7 @@ const level = { spawn.mapRect(9300, 2590, 650, 25); spawn.mapRect(9700, 2580, 100, 50); - spawn.randomBoss(1300, 2100, 0.1); + spawn.randomGroup(1300, 2100, 0.1); spawn.randomMob(8300, 2100, 0.1); spawn.randomSmallMob(2575, -75, 0.1); //entrance spawn.randomMob(8125, 2450, 0.1); @@ -1855,7 +1851,7 @@ const level = { spawn.randomSmallMob(1100, -300, 0.2); //entrance spawn.randomMob(4450, 2500, 0.2); spawn.randomMob(6350, 2525, 0.2); - spawn.randomBoss(9200, 2400, 0.3); + spawn.randomGroup(9200, 2400, 0.3); spawn.randomSmallMob(1900, -250, 0.3); //entrance spawn.randomMob(1500, 2100, 0.4); spawn.randomSmallMob(1700, -150, 0.4); //entrance @@ -1868,12 +1864,11 @@ const level = { spawn.randomMob(3600, 1725, 0.9); spawn.randomMob(4100, 1225, 0.9); spawn.randomMob(2825, 400, 0.9); - if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]); + if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss"]); powerUps.addRerollToLevel() //needs to run after mobs are spawned if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275); }, satellite() { - level.bossKilled = false; // if a boss needs to be killed const elevator = level.platform(4210, -1325, 380, 30, -10) level.custom = () => { level.playerExitCheck(); @@ -2058,13 +2053,13 @@ const level = { spawn.randomMob(2000, -2800, 0.4); spawn.randomMob(2200, -500, 0.4); spawn.randomMob(4475, -3550, 0.3); - spawn.randomBoss(5000, -2150, 1); - spawn.randomBoss(3700, -4100, 0.3); - spawn.randomBoss(2700, -1600, 0.1); - spawn.randomBoss(1600, -100, 0); - spawn.randomBoss(5000, -3900, -0.3); + spawn.randomGroup(5000, -2150, 1); + spawn.randomGroup(3700, -4100, 0.3); + spawn.randomGroup(2700, -1600, 0.1); + spawn.randomGroup(1600, -100, 0); + spawn.randomGroup(5000, -3900, -0.3); if (simulation.difficulty > 3) { - if (Math.random() < 0.1) { + if (Math.random() < 0.2) { spawn.randomLevelBoss(2800, -1400); } else if (Math.random() < 0.25) { spawn.laserBoss(2900 + 300 * Math.random(), -2950 + 150 * Math.random()); @@ -2080,7 +2075,6 @@ const level = { if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3950, -850); }, rooftops() { - level.bossKilled = false; // if a boss needs to be killed const elevator = level.platform(1450, -1000, 235, 30, -2) level.custom = () => { ctx.fillStyle = "#ccc" @@ -2296,15 +2290,14 @@ const level = { spawn.randomMob(5200, -100, 0.3); spawn.randomMob(5275, -900, 0.2); spawn.randomMob(900, -2125, 0.3); - spawn.randomBoss(600, -1575, 0); - spawn.randomBoss(2225, -1325, 0.4); - spawn.randomBoss(4900, -1200, 0); + spawn.randomGroup(600, -1575, 0); + spawn.randomGroup(2225, -1325, 0.4); + spawn.randomGroup(4900, -1200, 0); if (simulation.difficulty > 3) spawn.randomLevelBoss(3200, -2050); powerUps.addRerollToLevel() //needs to run after mobs are spawned if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(2175, -2425); }, aerie() { - level.bossKilled = false; // if a boss needs to be killed // const elevator = level.platform(4112, -2300, 280, 50) // simulation.g = 0.0012 //0.0024 level.custom = () => { @@ -2446,7 +2439,7 @@ const level = { spawn.mapRect(4250, -3700, 50, 300); spawn.mapRect(3700, -3250, 1100, 100); - spawn.randomBoss(350, -500, 1) + spawn.randomGroup(350, -500, 1) spawn.randomSmallMob(-225, 25); spawn.randomSmallMob(1000, -1100); spawn.randomSmallMob(4000, -250); @@ -2465,8 +2458,8 @@ const level = { spawn.randomMob(1700, -50, 0.3) spawn.randomMob(2350, -900, 0.3) spawn.randomMob(4700, -150, 0.2); - spawn.randomBoss(4000, -350, 0.6); - spawn.randomBoss(2750, -550, 0.1); + spawn.randomGroup(4000, -350, 0.6); + spawn.randomGroup(2750, -550, 0.1); spawn.randomMob(2175, -925, 0.5); spawn.randomMob(2750, 100, 0.5); spawn.randomMob(4250, -1725, 0.5); @@ -2486,8 +2479,8 @@ const level = { }); World.add(engine.world, cons[cons.length - 1]); - if (simulation.difficulty > 4) spawn.nodeBoss(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss - } else if (Math.random() < 0.15) { + if (simulation.difficulty > 4) spawn.nodeGroup(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss + } else if (Math.random() < 0.2) { spawn.randomLevelBoss(4250, -250); spawn.debris(-250, 50, 1650, 2); //16 debris per level spawn.debris(2475, 0, 750, 2); //16 debris per level @@ -2514,7 +2507,6 @@ const level = { if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(5350, -325); }, skyscrapers() { - level.bossKilled = false; // if a boss needs to be killed level.custom = () => { level.playerExitCheck(); }; @@ -2669,14 +2661,13 @@ const level = { spawn.randomMob(2200, -600, 0.2); spawn.randomMob(850, -1300, 0.25); spawn.randomMob(-100, -900, -0.2); - spawn.randomBoss(3700, -1500, 0.4); - spawn.randomBoss(1700, -900, 0.4); + spawn.randomGroup(3700, -1500, 0.4); + spawn.randomGroup(1700, -900, 0.4); if (simulation.difficulty > 3) spawn.randomLevelBoss(2600, -2300); powerUps.addRerollToLevel() //needs to run after mobs are spawned if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3075, -2050); }, highrise() { - level.bossKilled = false; // if a boss needs to be killed level.custom = () => { level.playerExitCheck(); }; @@ -2868,15 +2859,14 @@ const level = { spawn.randomMob(-125, -1500, -0.1); spawn.randomMob(-325, -1900, -0.1); spawn.randomMob(-550, -100, -0.1); - spawn.randomBoss(-3250, -2700, 0.2); - spawn.randomBoss(-2450, -1100, 0); + spawn.randomGroup(-3250, -2700, 0.2); + spawn.randomGroup(-2450, -1100, 0); if (simulation.difficulty > 3) spawn.randomLevelBoss(-2400, -3000); powerUps.addRerollToLevel() //needs to run after mobs are spawned if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(-1825, -1975); }, warehouse() { - level.bossKilled = false; // if a boss needs to be killed level.custom = () => { level.playerExitCheck(); }; @@ -3037,9 +3027,9 @@ const level = { spawn.randomMob(475, 300, 0); spawn.randomMob(-75, -700, 0); spawn.randomMob(900, -200, -0.1); - spawn.randomBoss(-125, 275, -0.2); - spawn.randomBoss(-825, 1000, 0.2); - spawn.randomBoss(-1300, -1100, -0.3); + spawn.randomGroup(-125, 275, -0.2); + spawn.randomGroup(-825, 1000, 0.2); + spawn.randomGroup(-1300, -1100, -0.3); if (simulation.difficulty > 3) { if (Math.random() < 0.25) { @@ -3069,7 +3059,7 @@ const level = { color: "#dff" }); } else { //reverse direction, start in bottom right - button = level.button(4300, 0) + button = level.button(3800, 0) door = level.door(3012, -200, 25, 200, 195) level.setPosToSpawn(3250, -550); //normal spawn level.exit.x = 1375; @@ -3220,11 +3210,11 @@ const level = { spawn.randomMob(450, -225, 0.15); spawn.randomMob(100, -1200, 1); spawn.randomMob(950, -1150, -0.1); - spawn.randomBoss(1800, -800, -0.2); - spawn.randomBoss(4150, -1000, 0.6); + spawn.randomGroup(1800, -800, -0.2); + spawn.randomGroup(4150, -1000, 0.6); if (simulation.difficulty > 3) { - if (Math.random() < 0.65) { + if (Math.random() < 0.5) { // tether ball level.fillBG.push({ x: 2495, @@ -3244,7 +3234,7 @@ const level = { }); World.add(engine.world, cons[cons.length - 1]); //chance to spawn a ring of exploding mobs around this boss - if (simulation.difficulty > 6) spawn.nodeBoss(2850, -80, "spawns", 8, 20, 105); + if (simulation.difficulty > 6) spawn.nodeGroup(2850, -80, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(2200, -450) } @@ -3483,9 +3473,9 @@ const level = { spawn.randomMob(3050, -1650, 0.8); spawn.randomMob(3350, -600, 0.8); spawn.randomMob(4400, -50, 1); - spawn.randomBoss(1500, -1900, 0.5); - spawn.randomBoss(2350, -850, 1); - spawn.randomBoss(100, -450, 0.9); + spawn.randomGroup(1500, -1900, 0.5); + spawn.randomGroup(2350, -850, 1); + spawn.randomGroup(100, -450, 0.9); if (simulation.difficulty > 3) spawn.randomLevelBoss(1850, -1400); powerUps.addRerollToLevel() //needs to run after mobs are spawned @@ -3719,7 +3709,7 @@ const level = { stiffness: 0.00006 }); World.add(engine.world, cons[cons.length - 1]); - if (simulation.difficulty > 4) spawn.nodeBoss(7000, -3300, "spawns", 8, 20, 105); + if (simulation.difficulty > 4) spawn.nodeGroup(7000, -3300, "spawns", 8, 20, 105); } else if (simulation.difficulty > 3) { spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss"]); } @@ -3738,7 +3728,7 @@ const level = { stiffness: 0.00036 }); World.add(engine.world, cons[cons.length - 1]); - if (simulation.difficulty > 4) spawn.nodeBoss(2350, -1300, "spawns", 8, 20, 105); + if (simulation.difficulty > 4) spawn.nodeGroup(2350, -1300, "spawns", 8, 20, 105); } else if (simulation.difficulty > 3) { spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "snakeBoss"]); } @@ -3765,10 +3755,10 @@ const level = { spawn.randomMob(800, 1200, 0.3); spawn.randomMob(7200, -4000, 0.3); spawn.randomMob(250, -1550, 0.3); - spawn.randomBoss(900, -1450, 0.3); - spawn.randomBoss(2980, -400, 0.3); - spawn.randomBoss(5750, -3860, 0.4); - spawn.randomBoss(1130, 1300, 0.1); + spawn.randomGroup(900, -1450, 0.3); + spawn.randomGroup(2980, -400, 0.3); + spawn.randomGroup(5750, -3860, 0.4); + spawn.randomGroup(1130, 1300, 0.1); powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.spawn(1900, -940, "heal"); powerUps.spawn(3000, -230, "heal"); @@ -3815,7 +3805,7 @@ const level = { }); World.add(engine.world, cons[cons.length - 1]); //chance to spawn a ring of exploding mobs around this boss - if (simulation.difficulty > 4) spawn.nodeBoss(2330, 1850, "spawns", 8, 20, 105); + if (simulation.difficulty > 4) spawn.nodeGroup(2330, 1850, "spawns", 8, 20, 105); powerUps.chooseRandomPowerUp(3100, 1630); }, detours() { @@ -3958,7 +3948,7 @@ const level = { spawn.randomSmallMob(2800, -1620, 0.7); spawn.randomMob(2400, -1370, 0.5); spawn.randomMob(3725, -1320, 0.3); - spawn.randomBoss(2115, -2020, 0.1) + spawn.randomGroup(2115, -2020, 0.1) powerUps.spawn(5000, -1275, "heal"); @@ -4078,7 +4068,7 @@ const level = { spawn.randomMob(1500, -270, 0.2); spawn.randomMob(1250, 55, 0.2); spawn.randomMob(8800, -45, 0.2); - spawn.randomBoss(8025, -845, 0.2); + spawn.randomGroup(8025, -845, 0.2); if (simulation.difficulty > 2) { if (Math.random() < 0.2) { @@ -4099,7 +4089,7 @@ const level = { stiffness: 0.00015 }); World.add(engine.world, cons[cons.length - 1]); - if (simulation.difficulty > 4) spawn.nodeBoss(8000, 630, "spawns", 8, 20, 105); + if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss"]); let me = mob[mob.length - 1]; @@ -4664,16 +4654,16 @@ const level = { spawn.randomMob(3965, -1650, 0.6) spawn.randomMob(4650, -1750, 0.6); spawn.randomMob(830, -1170, 0.5); - spawn.randomBoss(3730, -1100, 0.5); + spawn.randomGroup(3730, -1100, 0.5); spawn.randomMob(2650, -2250, 0.3); spawn.randomMob(1615, -2270, 0.3); spawn.randomMob(1380, -1280, 0.25); spawn.randomMob(2280, -650, 0.2); - spawn.randomBoss(2450, -2650, 0.2); + spawn.randomGroup(2450, -2650, 0.2); spawn.randomMob(3800, -580, 0.2); spawn.randomMob(4630, -425, 0.1); - spawn.randomBoss(630, -1300, -0.1); - spawn.randomBoss(3450, -2880, -0.2) + spawn.randomGroup(630, -1300, -0.1); + spawn.randomGroup(3450, -2880, -0.2) if (simulation.difficulty > 3) { if (Math.random() < 0.16) { @@ -4687,7 +4677,7 @@ const level = { stiffness: 0.00018 + 0.000007 * level.levelsCleared }); World.add(engine.world, cons[cons.length - 1]); - if (simulation.difficulty > 4) spawn.nodeBoss(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss + if (simulation.difficulty > 4) spawn.nodeGroup(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss } else { spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "snakeBoss", "laserBoss"]); diff --git a/js/lore.js b/js/lore.js index ea4a360..7b3c52b 100644 --- a/js/lore.js +++ b/js/lore.js @@ -128,14 +128,12 @@ const lore = { requestAnimationFrame(cycle); }, delay); }, - // () => { - // let delay = 2000 - // setTimeout(() => { lore.miriam.text("testing speech generation for lore level", true) }, delay); - // delay += 2200 - // setTimeout(() => { lore.anand.text("well, I'm also testing speech synthesis. Do you think it sounds good?", true) }, delay); - // delay += 4600 - // setTimeout(() => { lore.miriam.text("I guess it's fine.", true) }, delay); - // }, + () => { + let delay = 6000 + setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.", true) }, delay); + delay += 2700 + + }, ], dialogue: [ ``, diff --git a/js/mob.js b/js/mob.js index 4f33077..9f33f1b 100644 --- a/js/mob.js +++ b/js/mob.js @@ -410,7 +410,7 @@ const mobs = { // } // }, laserBeam() { - if (simulation.cycle % 7 && this.seePlayer.yes) { + if (this.seePlayer.yes) { ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); // ctx.lineDashOffset = 6*(simulation.cycle % 215); if (this.distanceToPlayer() < this.laserRange) { diff --git a/js/player.js b/js/player.js index 54ec8d5..a168577 100644 --- a/js/player.js +++ b/js/player.js @@ -638,9 +638,7 @@ const m = { tech.isDeathAvoidedThisLevel = true powerUps.research.changeRerolls(-1) simulation.makeTextLog(`m.research--
${powerUps.research.count}`) - for (let i = 0; i < 6; i++) { - powerUps.spawn(m.pos.x, m.pos.y, "heal", false); - } + for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x, m.pos.y, "heal", false); m.energy = m.maxEnergy m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds simulation.wipe = function() { //set wipe to have trails @@ -1170,14 +1168,12 @@ const m = { }, pushMass(who) { const speed = Vector.magnitude(Vector.sub(who.velocity, player.velocity)) - const fieldBlockCost = (0.03 + Math.sqrt(who.mass) * speed * 0.003) * m.fieldShieldingScale; + const fieldBlockCost = (0.025 + Math.sqrt(who.mass) * speed * 0.002) * m.fieldShieldingScale; const unit = Vector.normalise(Vector.sub(player.position, who.position)) if (m.energy > fieldBlockCost * 0.2) { //shield needs at least some of the cost to block m.energy -= fieldBlockCost - if (m.energy < 0) { - m.energy = 0; - } + if (m.energy < 0) m.energy = 0; // if (m.energy > m.maxEnergy) m.energy = m.maxEnergy; if (tech.blockDmg) { @@ -1396,11 +1392,11 @@ const m = { }, { name: "standing wave harmonics", - description: "3 oscillating shields are permanently active
blocking drains energy with no cool down
reduce harm by 15%", + description: "3 oscillating shields are permanently active
blocking drains energy with no cool down
reduce harm by 20%", effect: () => { // m.fieldHarmReduction = 0.80; m.fieldBlockCD = 0; - m.fieldHarmReduction = 0.85; + m.fieldHarmReduction = 0.8; m.hold = function() { if (m.isHolding) { m.drawHold(m.holdingTarget); @@ -1554,13 +1550,13 @@ const m = { }, { name: "negative mass field", - description: "use energy to nullify  gravity
reduce harm by 45%
blocks held by the field have a lower mass", + description: "use energy to nullify  gravity
reduce harm by 50%
blocks held by the field have a lower mass", fieldDrawRadius: 0, effect: () => { m.fieldFire = true; m.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping m.fieldMeterColor = "#000" - m.fieldHarmReduction = 0.55; + m.fieldHarmReduction = 0.5; m.fieldDrawRadius = 0; m.hold = function() { diff --git a/js/powerup.js b/js/powerup.js index e9037b1..ac81a12 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -38,13 +38,15 @@ const powerUps = { if (isCanceled) { if (tech.isCancelDuplication) tech.cancelCount++ if (tech.isCancelRerolls) { - let spawnType = (m.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo" - if (Math.random() < 0.33) { - spawnType = "heal" - } else if (Math.random() < 0.5 && !tech.isSuperDeterminism) { - spawnType = "research" + for (let i = 0; i < 6; i++) { + let spawnType = (m.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo" + if (Math.random() < 0.33) { + spawnType = "heal" + } else if (Math.random() < 0.5 && !tech.isSuperDeterminism) { + spawnType = "research" + } + powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false); } - for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false); } if (tech.isBanish && type === 'tech') { // banish researched tech by adding them to the list of banished tech const banishLength = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 @@ -469,7 +471,7 @@ const powerUps = { if (tech.isTechDamage && who.name === "tech") m.damage(0.11) if (tech.isMassEnergy) m.energy += 2.5; if (tech.isMineDrop) { - if (tech.isLaserMine) { //laser mine + if (tech.isLaserMine) { b.laserMine(who.position) } else { b.mine(who.position, { x: 0, y: 0 }, 0, tech.isMineAmmoBack) @@ -498,7 +500,7 @@ const powerUps = { powerUps.spawn(x, y, "gun"); return; } - if (Math.random() < 0.0027 * (25 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 15 + if (Math.random() < 0.0027 * (25 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 25 powerUps.spawn(x, y, "tech"); return; } @@ -559,10 +561,8 @@ const powerUps = { if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech") //bonus power ups for clearing runs in the last game - if (level.levelsCleared === 0 && !simulation.isCheating) { - for (let i = 0; i < localSettings.levelsClearedLastGame / 4 - 1; i++) { - powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game - } + if (level.levelsCleared === 0 && !simulation.isCheating && localSettings.levelsClearedLastGame > 1) { + for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } diff --git a/js/spawn.js b/js/spawn.js index 9ea18ce..faff7a6 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -21,7 +21,7 @@ const spawn = { "ghoster", "sneaker", ], - allowedBossList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper"], + allowedGroupList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper"], setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level //each level has 2 mobs: one new mob and one from the last level spawn.pickList.splice(0, 1); @@ -47,41 +47,41 @@ const spawn = { } } }, - randomBoss(x, y, chance = 1) { + randomGroup(x, y, chance = 1) { if (spawn.spawnChance(chance) && simulation.difficulty > 2 || chance == Infinity) { //choose from the possible picklist let pick = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - //is the pick able to be a boss? - let canBeBoss = false; - for (let i = 0, len = this.allowedBossList.length; i < len; ++i) { - if (this.allowedBossList[i] === pick) { - canBeBoss = true; + //is the pick able to be a group? + let canBeGroup = false; + for (let i = 0, len = this.allowedGroupList.length; i < len; ++i) { + if (this.allowedGroupList[i] === pick) { + canBeGroup = true; break; } } - if (canBeBoss) { + if (canBeGroup) { if (Math.random() < 0.55) { - this.nodeBoss(x, y, pick); + this.nodeGroup(x, y, pick); } else { - this.lineBoss(x, y, pick); + this.lineGroup(x, y, pick); } } else { if (Math.random() < 0.07) { this[pick](x, y, 90 + Math.random() * 40); //one extra large mob } else if (Math.random() < 0.35) { - this.groupBoss(x, y) //hidden grouping blocks + this.blockGroup(x, y) //hidden grouping blocks } else { pick = (Math.random() < 0.5) ? "randomList" : "random"; if (Math.random() < 0.55) { - this.nodeBoss(x, y, pick); + this.nodeGroup(x, y, pick); } else { - this.lineBoss(x, y, pick); + this.lineGroup(x, y, pick); } } } } }, - randomLevelBoss(x, y, options = ["shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"]) { + randomLevelBoss(x, y, options = ["historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"]) { // other bosses: suckerBoss, laserBoss, tetherBoss, //all need a particular level to work so they are not included spawn[options[Math.floor(Math.random() * options.length)]](x, y) }, @@ -297,7 +297,7 @@ const spawn = { //when player is inside event horizon if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { if (m.energy > 0) m.energy -= 0.01 - if (m.energy < 0.15) { + if (m.energy < 0.15 && m.immuneCycle < m.cycle) { m.damage(0.0004 * simulation.dmgScale); } const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); @@ -443,7 +443,7 @@ const spawn = { } } }, - groupBoss(x, y, num = 3 + Math.random() * 8) { + blockGroup(x, y, num = 3 + Math.random() * 8) { for (let i = 0; i < num; i++) { const radius = 25 + Math.floor(Math.random() * 20) spawn.grouper(x + Math.random() * radius, y + Math.random() * radius, radius); @@ -875,7 +875,7 @@ const spawn = { //when player is inside event horizon if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { if (m.energy > 0) m.energy -= 0.004 - if (m.energy < 0.1) { + if (m.energy < 0.1 && m.immuneCycle < m.cycle) { m.damage(0.00015 * simulation.dmgScale); } const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); @@ -981,7 +981,7 @@ const spawn = { //when player is inside event horizon if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { if (m.energy > 0) m.energy -= 0.006 - if (m.energy < 0.1) { + if (m.energy < 0.1 && m.immuneCycle < m.cycle) { m.damage(0.0002 * simulation.dmgScale); } const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); @@ -1065,7 +1065,7 @@ const spawn = { const nodes = 6 const angle = 2 * Math.PI / nodes - spawn.allowShields = false; //don't want shields on individual boss mobs + spawn.allowShields = false; //don't want shields on individual mobs for (let i = 0; i < nodes; ++i) { spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12); @@ -1086,7 +1086,7 @@ const spawn = { World.add(engine.world, consBB[consBB.length - 1]); } //spawn shield around all nodes - spawn.bossShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25); + spawn.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25); spawn.allowShields = true; }, timeSkipBoss(x, y, radius = 55) { @@ -1185,10 +1185,96 @@ const spawn = { this.checkStatus(); this.attraction(); this.repulsion(); - //laser beam this.laserBeam(); }; }, + historyBoss(x, y, radius = 30) { + if (tech.dynamoBotCount > 0) { + spawn.randomLevelBoss(x, y, ["cellBossCulture", "bomberBoss", "powerUpBoss"]) + return + } + mobs.spawn(x, y, 0, radius, "transparent"); + let me = mob[mob.length - 1]; + Matter.Body.setDensity(me, 0.3); //extra dense //normal is 0.001 + me.laserRange = 550; + me.seeAtDistance2 = 2000000; + me.showHealthBar = false; //drawn in this.awake + me.delayLimit = 60 + Math.floor(60 * Math.random()); + me.followDelay = 600 - Math.floor(60 * Math.random()) + me.stroke = "transparent"; //used for drawGhost + me.collisionFilter.mask = cat.bullet + me.memory = Infinity + me.onDeath = function() { + powerUps.spawnBossPowerUp(this.position.x, this.position.y) + }; + me.awake = function() { + this.checkStatus(); + + //health bar needs to be here because the position is being set + const h = this.radius * 0.3; + const w = this.radius * 2; + const x = this.position.x - w / 2; + const y = this.position.y - w * 0.7; + ctx.fillStyle = "rgba(100, 100, 100, 0.3)"; + ctx.fillRect(x, y, w, h); + ctx.fillStyle = "rgba(150,0,255,0.7)"; + ctx.fillRect(x, y, w * this.health, h); + + //draw eye + const unit = Vector.normalise(Vector.sub(m.pos, this.position)) + const eye = Vector.add(Vector.mult(unit, 15), this.position) + ctx.beginPath(); + ctx.arc(eye.x, eye.y, 4, 0, 2 * Math.PI); + ctx.moveTo(this.position.x + 20 * unit.x, this.position.y + 20 * unit.y); + ctx.lineTo(this.position.x + 30 * unit.x, this.position.y + 30 * unit.y); + ctx.strokeStyle = this.stroke; + ctx.lineWidth = 2; + ctx.stroke(); + + ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); + // ctx.lineDashOffset = 6*(simulation.cycle % 215); + if (this.distanceToPlayer() < this.laserRange) { + if (m.energy > 0.003) m.energy -= 0.003 + if (m.immuneCycle < m.cycle && m.energy < 0.1) m.damage(0.0003 * simulation.dmgScale); + ctx.beginPath(); + ctx.moveTo(eye.x, eye.y); + ctx.lineTo(m.pos.x, m.pos.y); + ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000); + ctx.lineWidth = 2; + ctx.strokeStyle = "rgb(150,0,255)"; + ctx.stroke(); + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); + ctx.fillStyle = "rgba(150,0,255,0.15)"; + ctx.fill(); + } + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.laserRange * 0.9, 0, 2 * Math.PI); + ctx.strokeStyle = "rgba(150,0,255,0.5)"; + ctx.lineWidth = 1; + ctx.stroke(); + ctx.setLineDash([]); + ctx.fillStyle = "rgba(150,0,255,0.03)"; + ctx.fill(); + if (!m.isBodiesAsleep && !this.isStunned && !this.isSlowed) { + if (this.followDelay > this.delayLimit) this.followDelay -= 0.2; + let history = m.history[(m.cycle - Math.floor(this.followDelay)) % 600] + Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player + } + } + + me.do = function() { + if (this.seePlayer.recall || (!(simulation.cycle % this.seePlayerFreq) && this.distanceToPlayer2() < this.seeAtDistance2 && !m.isCloak)) { + setTimeout(() => { + this.do = this.awake + this.stroke = "rgba(205,0,255,0.5)" + this.fill = "rgba(205,0,255,0.1)" + this.seePlayer.yes = true + }, 2000); + } + this.checkStatus(); + }; + }, focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) { radius = Math.ceil(radius * 0.7); mobs.spawn(x, y, 4, radius, "rgb(0,0,255)"); @@ -2403,8 +2489,8 @@ const spawn = { //snake tail const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40) - spawn.lineBoss(x + 105, y, "snakeBody", nodes); - //constraint boss with first 3 mobs in lineboss + spawn.lineGroup(x + 105, y, "snakeBody", nodes); + //constraint with first 3 mobs in line consBB[consBB.length] = Constraint.create({ bodyA: mob[mob.length - nodes], bodyB: mob[mob.length - 1 - nodes], @@ -2520,7 +2606,7 @@ const spawn = { }; } }, - bossShield(targets, x, y, radius, stiffness = 0.4) { + groupShield(targets, x, y, radius, stiffness = 0.4) { const nodes = targets.length mobs.spawn(x, y, 9, radius, "rgba(220,220,255,0.9)"); let me = mob[mob.length - 1]; @@ -2532,7 +2618,7 @@ const spawn = { me.collisionFilter.mask = cat.bullet; for (let i = 0; i < nodes; ++i) { mob[mob.length - i - 2].isShielded = true; - //constrain to all mob nodes in boss + //constrain to all mob nodes in group consBB[consBB.length] = Constraint.create({ bodyA: me, bodyB: mob[mob.length - i - 2], @@ -2567,7 +2653,7 @@ const spawn = { //complex constrained mob templates********************************************************************** //******************************************************************************************************* allowShields: true, - nodeBoss( + nodeGroup( x, y, spawn = "striker", @@ -2577,7 +2663,7 @@ const spawn = { sideLength = Math.ceil(Math.random() * 100) + 70, // distance between each node mob stiffness = Math.random() * 0.03 + 0.005 ) { - this.allowShields = false; //don't want shields on individual boss mobs + this.allowShields = false; //don't want shields on individual group mobs const angle = 2 * Math.PI / nodes let targets = [] for (let i = 0; i < nodes; ++i) { @@ -2588,20 +2674,20 @@ const spawn = { whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)]; } this[whoSpawn](x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius); - targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields + targets.push(mob[mob.length - 1].id) //track who is in the group, for shields } if (Math.random() < 0.3) { this.constrain2AdjacentMobs(nodes, stiffness * 2, true); } else { this.constrainAllMobCombos(nodes, stiffness); } - //spawn shield for entire boss + //spawn shield for entire group if (nodes > 2 && Math.random() < 0.998) { - this.bossShield(targets, x, y, sideLength + 2.5 * radius + nodes * 6 - 25); + this.groupShield(targets, x, y, sideLength + 2.5 * radius + nodes * 6 - 25); } this.allowShields = true; }, - lineBoss( + lineGroup( x, y, spawn = "striker", @@ -2611,7 +2697,7 @@ const spawn = { l = Math.ceil(Math.random() * 80) + 30, stiffness = Math.random() * 0.06 + 0.01 ) { - this.allowShields = false; //don't want shields on individual boss mobs + this.allowShields = false; //don't want shields on individual group mobs for (let i = 0; i < nodes; ++i) { let whoSpawn = spawn; if (spawn === "random") { diff --git a/js/tech.js b/js/tech.js index 00dd0d5..eaca70b 100644 --- a/js/tech.js +++ b/js/tech.js @@ -105,14 +105,14 @@ const tech = { return dmg * tech.slowFire * tech.aimDamage }, duplicationChance() { - return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.04 + tech.duplicateChance + m.duplicateChance + return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + m.duplicateChance }, totalBots() { return tech.dynamoBotCount + tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount }, tech: [{ name: "integrated armament", - description: "increase damage by 25%
your inventory can only hold 1 gun", + description: `increase damage by 25%
your inventory can only hold 1 gun`, maxCount: 1, count: 0, allowed() { @@ -121,9 +121,17 @@ const tech = { requires: "no more than 1 gun", effect() { tech.isOneGun = true; + // + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].name === "CPT gun") tech.tech[i].description = `adds the CPT gun to your inventory
it rewinds your health, velocity, and position
replaces your current gun
` + } + }, remove() { tech.isOneGun = false; + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].name === "CPT gun") tech.tech[i].description = `adds the CPT gun to your inventory
it rewinds your health, velocity, and position` + } } }, { @@ -510,13 +518,13 @@ const tech = { }, { name: "iridium-192", - description: "explosions release gamma radiation
60% more damage over 4 seconds", + description: "explosions release gamma radiation
100% more damage, but over 4 seconds", maxCount: 1, count: 0, allowed() { - return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 + return tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1) }, - requires: "an explosive damage source", + requires: "an explosive damage source, not ammonium nitrate or nitroglycerin", effect: () => { tech.isExplodeRadio = true; }, @@ -530,9 +538,9 @@ const tech = { maxCount: 9, count: 0, allowed() { - return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 + return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1) }, - requires: "an explosive damage source", + requires: "an explosive damage source, not iridium-192", effect: () => { tech.explosiveRadius += 0.2; }, @@ -546,9 +554,9 @@ const tech = { maxCount: 1, count: 0, allowed() { - return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 + return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1) }, - requires: "an explosive damage source", + requires: "an explosive damage source, not iridium-192", effect: () => { tech.isSmallExplosion = true; }, @@ -626,7 +634,7 @@ const tech = { }, { name: "impact shear", - description: "mobs release a nail when they die
nails target nearby mobs", + description: "mobs release a nail when they die
nails target nearby mobs", maxCount: 9, count: 0, allowed() { @@ -1318,9 +1326,8 @@ const tech = { document.getElementById("health").style.display = "inline" document.getElementById("health-bg").style.display = "inline" document.getElementById("dmg").style.backgroundColor = "#f67"; - m.health = Math.min(m.maxHealth, m.energy); + m.health = Math.max(Math.min(m.maxHealth, m.energy), 0.1); m.displayHealth(); - } }, { @@ -1739,7 +1746,7 @@ const tech = { } }, { - name: "Bayesian statistics", + name: "stimulated emission", description: "20% chance to duplicate spawned power ups
after a collision, eject 1 tech", maxCount: 1, count: 0, @@ -1756,24 +1763,60 @@ const tech = { if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal } }, + // { + // name: "stimulated emission", + // description: "6% chance to duplicate spawned power ups
duplication chance can't exceed 100%", + // maxCount: 9, + // count: 0, + // allowed() { + // return tech.duplicationChance() < 1 + // }, + // requires: "below 100% duplication chance", + // effect() { + // tech.duplicateChance += 0.06 + // simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw + // }, + // remove() { + // tech.duplicateChance = 0 + // if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal + // } + // }, { - name: "stimulated emission", - description: "6% chance to duplicate spawned power ups
duplication chance can't exceed 100%", - maxCount: 9, + name: "futures exchange", + description: "clicking × to cancel a field, tech, or gun
adds 4.5% power up duplication chance", + maxCount: 1, count: 0, allowed() { - return tech.duplicationChance() < 1 + return tech.duplicationChance() < 1 && !tech.isDeterminism }, - requires: "below 100% duplication chance", + requires: "below 100% duplication chance, not determinism", effect() { - tech.duplicateChance += 0.06 + tech.isCancelDuplication = true + tech.cancelCount = 0 simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw }, remove() { - tech.duplicateChance = 0 + tech.isCancelDuplication = false + // tech.cancelCount = 0 if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal } }, + { + name: "commodities exchange", + description: "clicking × to cancel a field, tech, or gun
spawns 6 heals, ammo, and research", + maxCount: 1, + count: 0, + allowed() { + return tech.isCancelDuplication + }, + requires: "futures exchange", + effect() { + tech.isCancelRerolls = true + }, + remove() { + tech.isCancelRerolls = false + } + }, { name: "correlated damage", description: "your chance to duplicate power ups
increases your damage by the same percent", @@ -1796,7 +1839,7 @@ const tech = { maxCount: 1, count: 0, allowed() { - return tech.duplicationChance() > 0.25 + return tech.duplicationChance() > 0.2 }, requires: "some duplication chance", effect() { @@ -1806,42 +1849,6 @@ const tech = { tech.isDuplicateBoss = false; } }, - { - name: "futures exchange", - description: "clicking × to cancel a field, tech, or gun
adds 4% power up duplication chance", - maxCount: 1, - count: 0, - allowed() { - return tech.duplicationChance() < 1 && !tech.isDeterminism - }, - requires: "below 100% duplication chance, not determinism", - effect() { - tech.isCancelDuplication = true - tech.cancelCount = 0 - simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw - }, - remove() { - tech.isCancelDuplication = false - // tech.cancelCount = 0 - if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal - } - }, - { - name: "commodities exchange", - description: "clicking × to cancel a field, tech, or gun
spawns 6 heals, ammo, or research", - maxCount: 1, - count: 0, - allowed() { - return tech.duplicationChance() > 0 && !tech.isDeterminism - }, - requires: "a chance to duplicate power ups, not determinism", - effect() { - tech.isCancelRerolls = true - }, - remove() { - tech.isCancelRerolls = false - } - }, { name: "exchange symmetry", description: "convert 1 a random tech into 3 new guns
recursive tech lose all stacks", @@ -1974,7 +1981,7 @@ const tech = { }, { name: "dark patterns", - description: "reduce combat difficulty by 1 level
add 16 junk tech to the potential pool", + description: "reduce combat difficulty by 1 level
add several junk tech to the potential pool", maxCount: 1, isNonRefundable: true, isCustomHide: true, @@ -2183,7 +2190,7 @@ const tech = { //************************************************** { name: "CPT gun", - description: "adds the CPT gun to your inventory
it rewinds your health, velocity, and position", + description: `adds the CPT gun to your inventory
it rewinds your health, velocity, and position`, isGunTech: true, maxCount: 1, count: 0, @@ -3820,7 +3827,7 @@ const tech = { maxCount: 1, count: 0, allowed() { - return m.fieldUpgrades[m.fieldMode].name === "plasma torch" + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" }, requires: "plasma torch", effect() { @@ -4123,33 +4130,35 @@ const tech = { } ], addLoreTechToPool() { //adds lore tech to tech pool - tech.tech.push({ - name: `undefined`, - description: `${lore.techCount+1}/10
add copies of this to the potential tech pool`, - maxCount: 1, - count: 0, - isLore: true, - isNonRefundable: true, - isCustomHide: true, - allowed() { - return true - }, - requires: "", - effect() { - setTimeout(() => { //a short delay, I can't remember why - lore.techCount++ - if (lore.techCount > 9) { - tech.removeLoreTechFromPool(); - } else { - for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech - if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech[i].description = `${lore.techCount+1}/10
add copies of this to the potential tech pool` + if (!simulation.isCheating) { + tech.tech.push({ + name: `undefined`, + description: `${lore.techCount+1}/10
add copies of this to the potential tech pool`, + maxCount: 1, + count: 0, + isLore: true, + isNonRefundable: true, + isCustomHide: true, + allowed() { + return true + }, + requires: "", + effect() { + setTimeout(() => { //a short delay, I can't remember why + lore.techCount++ + if (lore.techCount > 9) { + tech.removeLoreTechFromPool(); + } else { + for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech + if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech[i].description = `${lore.techCount+1}/10
add copies of this to the potential tech pool` + } + for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool() } - for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool() - } - }, 1); - }, - remove() {} - }) + }, 1); + }, + remove() {} + }) + } }, junk: [ // { @@ -4474,7 +4483,7 @@ const tech = { }, { name: "quantum black hole", - description: "use all your energy to
spawn inside the event horizon of a black hole boss", + description: "use all your energy to spawn inside the event horizon of a huge black hole", maxCount: 1, count: 0, isNonRefundable: true, diff --git a/style.css b/style.css index 5a0f003..b14932e 100644 --- a/style.css +++ b/style.css @@ -636,8 +636,8 @@ summary { } .junk { - background: hsl(255, 46%, 72%); - border-radius: 25%; + background: hsl(254, 59%, 74%); + border-radius: 35%; /* animation: 3s linear infinite alternate pulse; */ } diff --git a/todo.txt b/todo.txt index bd3010d..6fba6fe 100644 --- a/todo.txt +++ b/todo.txt @@ -1,12 +1,19 @@ ******************************************************** NEXT PATCH ******************************************************** +blocking uses 33% less energy -tech cloning requires > 25% dup chance, and is now only 2x (was 3x) your dup chance for a second boss -playing with the 4 community levels now removes 4 random levels from the level list +tech: stimulated emission removed +tech: Bayesian statistics renamed stimulated emission +tech: futures exchange gives 4.5% per cancel (up from 4%) -tech: dark patterns - reduce combat difficulty by 1 level and add 16 junk tech to the potential tech pool +new level boss: follows you like the dynamo-bot, but is not friend + will not spawn if you have a dynamo-bot + (probably will be rebalanced in next patch) ******************************************************** BUGS ******************************************************** +make mobs that spawn other mobs limit spawns to line of sight + orange mobs + (only once on my computer) once every 7 second check isn't running code power ups don't teleport to exit complex spin statistics isn't activating @@ -31,19 +38,29 @@ tech: dark patterns - reduce combat difficulty by 1 level and add 16 junk tech t ******************************************************** TODO ******************************************************** -reduce 3 difficulty, randomize all mods when you... - take damage - switch guns - pick up a tech +tech: when you switch guns switch a random bot to a different bot. If the bot you had was upgraded the new one will be too. + or switch all bots + +tech: buff block throwing + require +100% damage for blocks + works with pilot wave? + + +lore: a tutorial / lore intro + needs to be optional so it doesn't slow experienced players + put something on the intro map + maybe a button triggers something + +tech: add an eject button for each power up in the pause menu + also list all bot types in pause menu + with option to eject? add back in gamepad support + but does anyone care? https://github.com/landgreen/landgreen.github.io/search?q=gamepadconnected mechanic: gain damage when there are fewer bullets -junk tech - switch input keys: left-right, up-down? - rename intro level to something lore related give undefined tech different effects at different localSettings.loreCount values @@ -329,7 +346,7 @@ n-gon outreach ideas ******************************************************** LORE ******************************************************** cool names for tech - strange loop, ansatz + strange loop, ansatz, Bayesian statistics voice singing with pitch? @@ -343,7 +360,12 @@ chapter 2: scientists verify that bot can really hear them chapter 3: why is the bot attacking things? player is the bot and also the mobs, and the levels. player is the entire simulation why is the player attacking itself? - learn console commands to manipulate the simulation + learn console commands to manipulate the simulation? + unlock hard and why difficulty? + but what about easy? + maybe remove easy, and replace with a check box that makes the game easy, but in a different way + disable lore, but respawn on the level you die at? + chapter 4: why does the simulation exists? started to research new tech and test in a simulated world