diff --git a/img/martingale.webp b/img/martingale.webp new file mode 100644 index 0000000..8f1e712 Binary files /dev/null and b/img/martingale.webp differ diff --git a/img/strange loop.webp b/img/strange loop.webp new file mode 100644 index 0000000..ed374c3 Binary files /dev/null and b/img/strange loop.webp differ diff --git a/index.html b/index.html index 83d1ea6..e345a6d 100644 --- a/index.html +++ b/index.html @@ -242,91 +242,6 @@ - - diff --git a/js/index.js b/js/index.js index cb0033c..41a1fe1 100644 --- a/js/index.js +++ b/js/index.js @@ -1409,14 +1409,16 @@ window.addEventListener("keydown", function (event) { if (event.key === "X") m.death(); //only uppercase switch (event.key.toLowerCase()) { case "o": - simulation.isAutoZoom = false; - simulation.zoomScale /= 0.9; - simulation.setZoom(); + // simulation.isAutoZoom = false; + // simulation.zoomScale /= 0.9; + // simulation.setZoom(); + simulation.zoomTransition(simulation.zoomScale / 0.9) break; case "i": - simulation.isAutoZoom = false; - simulation.zoomScale *= 0.9; - simulation.setZoom(); + // simulation.isAutoZoom = false; + // simulation.zoomScale *= 0.9; + // simulation.setZoom(); + simulation.zoomTransition(simulation.zoomScale * 0.9) break case "`": powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "research"); diff --git a/js/level.js b/js/level.js index eecb410..9bd03a6 100644 --- a/js/level.js +++ b/js/level.js @@ -9,7 +9,7 @@ const level = { onLevel: -1, levelsCleared: 0, // playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"], - //see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later + //see level.populateLevels: (initial, ... , reservoir or factory, reactor, ... , subway, final) added later playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"], communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo"], trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"], @@ -36,22 +36,24 @@ const level = { // b.giveGuns("harpoon") //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[8].ammo = 100000000 // requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") }); - // for (let i = 0; i < 1; ++i) tech.giveTech("Higgs mechanism") - // for (let i = 0; i < 1; ++i) tech.giveTech("topological defect") - // for (let i = 0; i < 1; ++i) tech.giveTech("Hilbert space") + // for (let i = 0; i < 1; ++i) tech.giveTech("martingale") + // for (let i = 0; i < 1; ++i) tech.giveTech("paradigm shift") + // for (let i = 0; i < 1; ++i) tech.giveTech("bubble fusion") // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") }); // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) }); + // m.skin.hexagon(); - // for (let i = 0; i < 1; i++) tech.giveTech("cascading failure") + + // for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide") // for (let i = 0; i < 1; ++i) tech.giveTech("induction furnace") // for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense") // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research"); // for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); - // level.skyscrapers(); + // level.testing(); // for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500) - // for (let i = 0; i < 10; ++i) spawn.starter(1900, -500, 50) + // for (let i = 0; i < 4; ++i) spawn.stinger(1900, -500) // for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500) // spawn.beetleBoss(1900, -500, 25) // spawn.slasher2(2000, -1150) @@ -62,7 +64,7 @@ const level = { // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // for (let i = 0; i < 40; ++i) tech.giveTech() - level[simulation.isTraining ? "walk" : "intro"]() //normal starting level ************************************************** + level[simulation.isTraining ? "walk" : "initial"]() //normal starting level ************************************************** // spawn.bodyRect(2425, -120, 200, 200); // console.log(body[body.length - 1].mass) @@ -74,9 +76,9 @@ const level = { // for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo"); // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false); //lore testing + // simulation.isCheating = false //true; // for (let i = 0; i < 5; i++) tech.giveTech("undefined") // lore.techCount = 2 - // simulation.isCheating = false //true; // level.levelsCleared = 10 // localSettings.loreCount = 5 //this sets what conversation is heard // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage @@ -284,6 +286,150 @@ const level = { tech.isDeathAvoidedThisLevel = false; simulation.updateTechHUD(); simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map + + + //pop up new level info screen for a few seconds + if (!simulation.isChoosing && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor")) { //level.levels[level.onLevel] === "subway" || + //pause + if (!simulation.paused) { + simulation.paused = true; + simulation.isChoosing = true; //stops p from un pausing on key down + // build.pauseGrid() + // document.body.style.cursor = "auto"; + } + //build level info + document.getElementById("choose-grid").style.gridTemplateColumns = "250px" + let text = `
` + for (let i = 0; i < level.levels.length; i++) { + if (i < level.levelsCleared) { + text += `
${level.levels[i]}
` + } else if (i === level.levelsCleared) { + // text += `
${level.levels[i]}
` + text += `
${level.levels[i]}
` + } else { + text += `
${level.levels[i]}
` //blurry text + // ???????? text + // text += `
` + // for (let j = 0; j < level.levels[i].length; j++) text += `?` + // text += `
` + } + } + text += `
` + + document.getElementById("choose-grid").innerHTML = text + //show level info + document.getElementById("choose-grid").style.opacity = "1" + document.getElementById("choose-grid").style.transitionDuration = "0.25s"; //how long is the fade in on + document.getElementById("choose-grid").style.visibility = "visible" + + simulation.draw.cons(); + simulation.draw.body(); + level.customTopLayer(); + let count = simulation.testing ? 0 : 240 + let newLevelDraw = () => { + count-- + if (count > 0) { + requestAnimationFrame(newLevelDraw); + } else { //unpause + // document.body.style.cursor = "none"; + if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 30; //player is immune to damage for 30 cycles + if (simulation.paused) requestAnimationFrame(cycle); + if (m.alive) simulation.paused = false; + simulation.isChoosing = false; //stops p from un pausing on key down + build.unPauseGrid() + document.getElementById("choose-grid").style.opacity = "0" + setTimeout(() => { + document.getElementById("choose-grid").style.visibility = "hidden" + }, 1000); + } + //draw + simulation.wipe(); + m.look(); + simulation.camera(); + // if (count < 30) { + // } + // if (count < 60) { + // simulation.draw.cons(); + // simulation.draw.body(); + // level.customTopLayer(); + // simulation.draw.body(); + // simulation.draw.drawMapPath(); + // mobs.draw(); + // } else + // if (count < 240) { + simulation.draw.wireFrame(); + // } + // else if (count === 91) { //hide text boss + // document.getElementById("choose-grid").style.opacity = "0" + // setTimeout(() => { + // document.getElementById("choose-grid").style.visibility = "hidden" + // }, 1000); + // } + ctx.restore(); + simulation.drawCursor(); + } + requestAnimationFrame(newLevelDraw); + + + // // clear + // requestAnimationFrame(() => { + // simulation.wipe(); + // }); + + // //wireframe + // setTimeout(() => { + // requestAnimationFrame(() => { + // simulation.wipe(); + // simulation.camera(); + // simulation.draw.wireFrame(); + // ctx.restore(); + // }); + // }, 500); + + // //almost normal draw + // setTimeout(() => { + // requestAnimationFrame(() => { + // simulation.wipe(); + // simulation.camera(); + // // ctx.fillStyle = "rgba(0,0,0,0.66)" + // // ctx.fill(simulation.draw.mapPath); + // simulation.draw.drawMapPath(); + // ctx.restore(); + // }); + // }, 1000); + + // //normal draw + // setTimeout(() => { + // requestAnimationFrame(() => { + // simulation.wipe(); + // simulation.camera(); + // // level.custom(); + // simulation.draw.cons(); + // simulation.draw.body(); + // // m.draw(); + // // m.hold(); + // level.customTopLayer(); + // simulation.draw.drawMapPath(); + // ctx.restore(); + // }); + // }, 1500); + + // //unpause + // setTimeout(() => { + // document.body.style.cursor = "none"; + // if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles + // if (simulation.paused) requestAnimationFrame(cycle); + // if (m.alive) simulation.paused = false; + // simulation.isChoosing = false; //stops p from un pausing on key down + // build.unPauseGrid() + + // document.getElementById("choose-grid").style.opacity = "0" + // // document.getElementById("choose-grid").style.visibility = "hidden" + // setTimeout(() => { + // document.getElementById("choose-grid").style.visibility = "hidden" + // }, 1000); + // }, 2000); + } } }, populateLevels() { //run a second time if URL is loaded @@ -335,7 +481,7 @@ const level = { level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, Math.random() < 0.5 ? "factory" : "reservoir"); //add level to the back half of the randomized levels list level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech - level.levels.unshift("intro"); //add level to the start of the randomized levels list + level.levels.unshift("initial"); //add level to the start of the randomized levels list level.levels.push("subway"); //add level to the end of the randomized levels list level.levels.push("final"); //add level to the end of the randomized levels list } @@ -1911,7 +2057,7 @@ const level = { powerUps.addResearchToLevel() //needs to run after mobs are spawned }, testing() { - simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode + // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode document.body.style.backgroundColor = "#fff"; // color.map = "#444" //custom map color @@ -2158,7 +2304,7 @@ const level = { spawn.mapRect(-500, -25, 25, 50); //edge shelf spawn.mapRect(475, -25, 25, 50); //edge shelf }, - intro() { + initial() { if (level.levelsCleared === 0) { //if this is the 1st level of the game if (simulation.difficultyMode > 2) spawn.setSpawnList() // hard and why difficulty don't begin with starter mobs @@ -2216,7 +2362,7 @@ const level = { } else { for (let i = 0; i < 60; i++) { setTimeout(() => { - if (level.levels[level.onLevel] === "intro") spawn.sneaker(2100, -1500 - 50 * i); + if (level.levels[level.onLevel] === "initial") spawn.sneaker(2100, -1500 - 50 * i); }, 2000 + 500 * i); } } @@ -2457,6 +2603,7 @@ const level = { document.body.style.backgroundColor = "#ddd"; for (let i = 0; i < 16; i++) powerUps.spawn(4600 + 40 * i, -30, "ammo"); + if (simulation.difficultyMode > 4) for (let i = 0; i < 8; i++) powerUps.spawn(4600 + 40 * i, -30, "ammo"); //extra ammo on why difficulty spawn.mapRect(-1950, 0, 8200, 1800); //ground spawn.mapRect(-1950, -1500, 1800, 1900); //left wall @@ -3832,19 +3979,19 @@ const level = { for (let i = 0; i < 250; i++) spawn.starter(-2700 + 2400 * Math.random(), -1300 - 500 * Math.random()) } else { 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.22 / 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); + for (let i = 0, len = scale * 0.13 / 6; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) + for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); } 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 + for (let i = 0, len = scale * 0.22; 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 + for (let i = 0, len = scale * 0.13; 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 + for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15 } } } @@ -3919,6 +4066,7 @@ const level = { isDoorsLocked = true 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"); + if (simulation.difficultyMode > 4) for (let i = 0; i < 8; i++) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo"); //extra ammo on why difficulty const scale = Math.pow(simulation.difficulty, 0.7) //hard around 30, why around 54 if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { for (let i = 0; i < 250; i++) spawn.starter(300 + 2400 * Math.random(), -1300 - 500 * Math.random()) @@ -12158,7 +12306,10 @@ const level = { spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(1500, -10, 100, 20); level.defaultZoom = 1800 - simulation.setZoom(1200); + // simulation.setZoom(1200); + simulation.zoomTransition(1200) + + document.body.style.backgroundColor = "#daa69f"; color.map = "#600"; @@ -12567,7 +12718,9 @@ const level = { level.exit.y = -2030; relocateTo(50, -2050); simulation.fallHeight = -1000; - simulation.setZoom(1800); + // simulation.setZoom(1800); + simulation.zoomTransition(1800) + templePlayer.startAnim = -1; templePlayer.drawExit = false; } diff --git a/js/lore.js b/js/lore.js index c841ea4..ff5372e 100644 --- a/js/lore.js +++ b/js/lore.js @@ -1092,7 +1092,7 @@ const lore = { () => { setTimeout(() => { - lore.anand.text("How ever it thinks it can learn and, I think we showed it that nonviolence is an option,") + lore.anand.text("How ever it thinks it can learn, and I think we showed it that nonviolence is an option,") }, 1000); }, () => { @@ -1116,7 +1116,7 @@ const lore = { }, 1000); }, () => { - lore.anand.text("me too") + lore.anand.text("Me too,") }, () => { lore.anand.text("but I'm also pretty hungry, wanna go get some food?") diff --git a/js/mob.js b/js/mob.js index 18434b1..9f5a004 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1350,16 +1350,7 @@ const mobs = { this.leaveBody = false; // no body since it turned into the bot } if (tech.isAddRemoveMaxHealth) { - if (this.isBoss && this.isDropPowerUp) { - powerUps.spawn(this.position.x + 20, this.position.y, "tech", false) - powerUps.spawn(this.position.x - 20, this.position.y, "research", false) - powerUps.spawn(this.position.x - 40, this.position.y, "research", false) - powerUps.spawn(this.position.x + 40, this.position.y, "research", false) - powerUps.spawn(this.position.x, this.position.y + 20, "research", false) - powerUps.spawn(this.position.x, this.position.y - 20, "heal", false) - powerUps.spawn(this.position.x, this.position.y + 40, "heal", false) - powerUps.spawn(this.position.x, this.position.y - 40, "heal", false) - } else { + if (!this.isBoss) { const amount = 0.005 if (tech.isEnergyHealth) { if (m.maxEnergy > amount) { @@ -1371,12 +1362,34 @@ const mobs = { m.setMaxHealth(); } } + + // if (this.isBoss && this.isDropPowerUp) { + // powerUps.spawn(this.position.x + 20, this.position.y, "tech", false) + // powerUps.spawn(this.position.x - 20, this.position.y, "research", false) + // powerUps.spawn(this.position.x - 40, this.position.y, "research", false) + // powerUps.spawn(this.position.x + 40, this.position.y, "research", false) + // powerUps.spawn(this.position.x, this.position.y + 20, "research", false) + // powerUps.spawn(this.position.x, this.position.y - 20, "heal", false) + // powerUps.spawn(this.position.x, this.position.y + 40, "heal", false) + // powerUps.spawn(this.position.x, this.position.y - 40, "heal", false) + // } else { + // const amount = 0.005 + // if (tech.isEnergyHealth) { + // if (m.maxEnergy > amount) { + // tech.healMaxEnergyBonus -= amount + // m.setMaxEnergy(); + // } + // } else if (m.maxHealth > amount) { + // tech.extraMaxHealth -= amount //decrease max health + // m.setMaxHealth(); + // } + // } } if (tech.cloakDuplication && !this.isBoss) { tech.cloakDuplication -= 0.01 powerUps.setPowerUpMode(); //needed after adjusting duplication chance } - } else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) { + } else if (tech.isShieldAmmo && this.shield && !this.isExtraShield && this.isDropPowerUp) { let type = tech.isEnergyNoAmmo ? "heal" : "ammo" if (Math.random() < 0.4) { type = "heal" diff --git a/js/player.js b/js/player.js index 7877e7d..1bafbbb 100644 --- a/js/player.js +++ b/js/player.js @@ -539,7 +539,7 @@ const m = { }, baseHealth: 1, setMaxHealth() { - m.maxHealth = m.baseHealth + tech.extraMaxHealth + 2.22 * tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth + m.maxHealth = m.baseHealth + tech.extraMaxHealth + 3 * tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth document.getElementById("health-bg").style.width = `${Math.floor(300 * m.maxHealth)}px` simulation.makeTextLog(`m.maxHealth = ${m.maxHealth.toFixed(2)}`) if (m.health > m.maxHealth) m.health = m.maxHealth; @@ -564,7 +564,7 @@ const m = { // if (tech.healthDrain) dmg *= 1 + 3.33 * tech.healthDrain //tech.healthDrain = 0.03 at one stack //cause more damage if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.973 ** m.coupling if (tech.isLowHealthDefense) dmg *= 1 - Math.max(0, 1 - m.health) * 0.8 - if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.33 + if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.26 if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4) if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1 if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0193, 0.88) //capped at speed of 55 @@ -572,7 +572,7 @@ const m = { if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05 if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots() if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; - if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3 + if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.27 if (tech.isTurret && m.crouch) dmg *= 0.34; if (tech.isFirstDer && b.inventory[0] === b.activeGun) dmg *= 0.85 ** b.inventory.length if (tech.isEnergyHealth) { @@ -725,7 +725,7 @@ const m = { tech.isDeathAvoidedThisLevel = true powerUps.research.changeRerolls(-1) simulation.makeTextLog(`m.research--
${powerUps.research.count}`) - for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); + for (let i = 0; i < 16; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); m.energy = m.maxEnergy + 0.1 if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds simulation.wipe = function () { //set wipe to have trails @@ -755,7 +755,7 @@ const m = { powerUps.research.changeRerolls(-1) simulation.makeTextLog(`m.research--
${powerUps.research.count}`) - for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); + for (let i = 0; i < 16; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0.03)"; @@ -1274,23 +1274,29 @@ const m = { m.drawLeg("#5f5f5f"); m.calcLeg(0, 1); m.drawLeg("#555"); + ctx.rotate(m.angle); + + const size = 33 ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); + ctx.lineTo(size * 1, size * 0) + ctx.lineTo(size * 0.5, size * 0.866) + ctx.lineTo(size * -0.5, size * 0.866) + ctx.lineTo(size * -1, size * 0) + ctx.lineTo(size * -0.5, size * -0.866) + ctx.lineTo(size * 0.5, size * -0.866) + ctx.lineTo(size * 1, size * 0) + ctx.lineTo(size * 0.5, size * 0) ctx.fillStyle = m.bodyGradient ctx.fill(); - // ctx.fillStyle = grdRad - // ctx.fill(); - ctx.strokeStyle = "#000"; + ctx.strokeStyle = "#333"; ctx.lineWidth = 1.5; - ctx.rotate(m.angle); - ctx.beginPath(); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); - ctx.fillStyle = "#fff" - ctx.fill(); - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.stroke(); + + ctx.beginPath(); + ctx.arc(15, 0, 3, 0, 2 * Math.PI); + ctx.fillStyle = "#333" + ctx.fill(); + ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal powerUps.boost.draw() @@ -1482,8 +1488,6 @@ const m = { // console.log(simulation.zoomScale) simulation.setZoom(1800 + 400 * Math.sin(m.cycle * 0.0075)) - - } }, dilate2() { @@ -1645,6 +1649,95 @@ const m = { ctx.restore(); } }, + hexagon() { + m.isAltSkin = true + m.color = { + hue: 0, + sat: 0, + light: 100, + } + // m.setFillColors(); + m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)` + m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)` + let grd = ctx.createLinearGradient(-30, 0, 30, 0); + grd.addColorStop(0, m.fillColorDark); + grd.addColorStop(0.7, m.fillColor); + // grd.addColorStop(1, m.fillColor); + m.bodyGradient = grd + + m.draw = function () { + ctx.fillStyle = m.fillColor; + m.walk_cycle += m.flipLegs * m.Vx; + ctx.save(); + ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20) + ctx.translate(m.pos.x, m.pos.y); + m.calcLeg(Math.PI, -3); + m.drawLeg("#4a4a4a"); + m.calcLeg(0, 0); + m.drawLeg("#333"); + ctx.rotate(m.angle); + + const size = 32 + ctx.beginPath(); + ctx.lineTo(size * 1, size * 0) + ctx.lineTo(size * 0.5, size * 0.866) + ctx.lineTo(size * -0.5, size * 0.866) + ctx.lineTo(size * -1, size * 0) + ctx.lineTo(size * -0.5, size * -0.866) + ctx.lineTo(size * 0.5, size * -0.866) + ctx.lineTo(size * 1, size * 0) + ctx.fillStyle = m.bodyGradient + ctx.fill(); + ctx.arc(15, 0, 4, 0, 2 * Math.PI); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 2; + ctx.stroke(); + ctx.restore(); + m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() + } + m.drawLeg = function (stroke) { + // if (simulation.mouseInGame.x > m.pos.x) { + if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) { + m.flipLegs = 1; + } else { + m.flipLegs = -1; + } + ctx.save(); + ctx.scale(m.flipLegs, 1); //leg lines + ctx.beginPath(); + ctx.moveTo(m.hip.x, m.hip.y); + ctx.lineTo(m.knee.x, m.knee.y); + ctx.lineTo(m.foot.x, m.foot.y); + ctx.strokeStyle = stroke; + ctx.lineWidth = 6; + ctx.stroke(); + + //toe lines + ctx.beginPath(); + ctx.moveTo(m.foot.x, m.foot.y); + ctx.lineTo(m.foot.x - 15, m.foot.y + 5); + ctx.moveTo(m.foot.x, m.foot.y); + ctx.lineTo(m.foot.x + 15, m.foot.y + 5); + ctx.lineWidth = 3; + ctx.stroke(); + + //hip joint + ctx.beginPath(); + ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI); + //knee joint + ctx.moveTo(m.knee.x + 5, m.knee.y); + ctx.arc(m.knee.x, m.knee.y, 5, 0, 2 * Math.PI); + //foot joint + ctx.moveTo(m.foot.x + 5, m.foot.y); + ctx.arc(m.foot.x, m.foot.y, 5, 0, 2 * Math.PI); + ctx.fillStyle = "#000"; + ctx.fill(); + // ctx.lineWidth = 2; + // ctx.stroke(); + ctx.restore(); + } + }, stubs() { m.isAltSkin = true m.draw = function () { diff --git a/js/powerup.js b/js/powerup.js index 562a8b2..0e23a4e 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -326,7 +326,7 @@ const powerUps = { return } if (tech.isCancelDuplication) { - tech.duplication += 0.043 + tech.duplication += 0.047 tech.maxDuplicationEvent() simulation.makeTextLog(`tech.duplicationChance() += ${0.043}`) simulation.circleFlare(0.043); @@ -361,7 +361,7 @@ const powerUps = { // } } if (tech.isAnsatz && powerUps.research.count < 1) { - for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); + for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); } // document.getElementById("choose-grid").style.display = "none" document.getElementById("choose-grid").style.visibility = "hidden" @@ -466,28 +466,30 @@ const powerUps = { if (m.alive && powerUps.research.count >= cost) { requestAnimationFrame(cycle); this.isMakingBots = true - } else { - this.isMakingBots = false - } - if (!simulation.paused && !simulation.isChoosing && !(simulation.cycle % 60)) { - powerUps.research.count -= cost - b.randomBot() - if (tech.renormalization) { - for (let i = 0; i < cost; i++) { - if (Math.random() < 0.46) { - m.fieldCDcycle = m.cycle + 20; - powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research"); + + if (!simulation.paused && !simulation.isChoosing && !(simulation.cycle % 60)) { + powerUps.research.count -= cost + b.randomBot() + if (tech.renormalization) { + for (let i = 0; i < cost; i++) { + if (Math.random() < 0.47) { + m.fieldCDcycle = m.cycle + 20; + powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research"); + } } } } + } else { + this.isMakingBots = false } } requestAnimationFrame(cycle); } + if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) { document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}` } - if (tech.renormalization && Math.random() < 0.46 && amount < 0) { + if (tech.renormalization && Math.random() < 0.47 && amount < 0) { for (let i = 0, len = -amount; i < len; i++) powerUps.spawn(m.pos.x, m.pos.y, "research"); } if (tech.isRerollHaste) { @@ -1412,6 +1414,31 @@ const powerUps = { } } } + + + if (tech.isAddRemoveMaxHealth) { + powerUps.spawn(x + 20, y, "tech", false) + powerUps.spawn(x - 20, y, "research", false) + powerUps.spawn(x - 40, y, "research", false) + powerUps.spawn(x + 40, y, "research", false) + powerUps.spawn(x, y + 20, "research", false) + powerUps.spawn(x, y - 20, "heal", false) + powerUps.spawn(x, y + 40, "heal", false) + powerUps.spawn(x, y - 40, "heal", false) + // if (this.isBoss && this.isDropPowerUp) { + // } else { + // const amount = 0.005 + // if (tech.isEnergyHealth) { + // if (m.maxEnergy > amount) { + // tech.healMaxEnergyBonus -= amount + // m.setMaxEnergy(); + // } + // } else if (m.maxHealth > amount) { + // tech.extraMaxHealth -= amount //decrease max health + // m.setMaxHealth(); + // } + // } + } } }, chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris @@ -1501,11 +1528,11 @@ const powerUps = { }, pauseEjectTech(index) { if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) { - if (Math.random() < 0.2 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) { + if (Math.random() < 0.03 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) { tech.removeTech(index) - // powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); } else { powerUps.ejectTech(index) + m.damage(0.06) } document.getElementById(`${index}-pause-tech`).style.textDecoration = "line-through" document.getElementById(`${index}-pause-tech`).style.animation = "" diff --git a/js/simulation.js b/js/simulation.js index 4b73590..fdb0940 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -24,7 +24,6 @@ const simulation = { mobs.healthBar(); m.draw(); m.hold(); - // v.draw(); //working on visibility work in progress level.customTopLayer(); simulation.draw.drawMapPath(); b.fire(); @@ -33,10 +32,8 @@ const simulation = { if (!m.isBodiesAsleep) b.bulletDo(); simulation.drawCircle(); simulation.runEphemera(); - // simulation.clip(); ctx.restore(); simulation.drawCursor(); - // simulation.pixelGraphics(); }, testingLoop() { simulation.gravity(); @@ -505,47 +502,52 @@ const simulation = { simulation.zoom = canvas.height / zoomScale; //sets starting zoom scale }, zoomTransition(newZoomScale, step = 2) { + //old version + // if (simulation.isAutoZoom) { + // const isBigger = (newZoomScale - simulation.zoomScale > 0) ? true : false; + // requestAnimationFrame(zLoop); + // const currentLevel = level.onLevel + + // function zLoop() { + // if (currentLevel !== level.onLevel || simulation.isAutoZoom === false) return //stop the zoom if player goes to a new level + + // if (isBigger) { + // simulation.zoomScale += step + // if (simulation.zoomScale >= newZoomScale) { + // simulation.setZoom(newZoomScale); + // return + // } + // } else { + // simulation.zoomScale -= step + // if (simulation.zoomScale <= newZoomScale) { + // simulation.setZoom(newZoomScale); + // return + // } + // } + + // simulation.setZoom(); + // requestAnimationFrame(zLoop); + // } + // } + + + //rewrite using the ephemera system if (simulation.isAutoZoom) { - const isBigger = (newZoomScale - simulation.zoomScale > 0) ? true : false; - requestAnimationFrame(zLoop); - const currentLevel = level.onLevel - - function zLoop() { - if (currentLevel !== level.onLevel || simulation.isAutoZoom === false) return //stop the zoom if player goes to a new level - - if (isBigger) { + simulation.ephemera.push({ + name: "zoom", + count: simulation.testing ? 0 : 120, //cycles before it self removes + currentLevel: level.onLevel, + do() { + this.count-- + const step = (newZoomScale - simulation.zoomScale) / this.count simulation.zoomScale += step - if (simulation.zoomScale >= newZoomScale) { - simulation.setZoom(newZoomScale); - return + if (this.count < 1 && this.currentLevel === level.onLevel && simulation.isAutoZoom) { + simulation.zoomScale = newZoomScale + simulation.removeEphemera(this.name) } - } else { - simulation.zoomScale -= step - if (simulation.zoomScale <= newZoomScale) { - simulation.setZoom(newZoomScale); - return - } - } - - simulation.setZoom(); - requestAnimationFrame(zLoop); - } - } - }, - zoomInFactor: 0, - startZoomIn(time = 180) { - simulation.zoom = 0; - let count = 0; - requestAnimationFrame(zLoop); - - function zLoop() { - simulation.zoom += canvas.height / simulation.zoomScale / time; - count++; - if (count < time) { - requestAnimationFrame(zLoop); - } else { - simulation.setZoom(); - } + simulation.setZoom(simulation.zoomScale); + }, + }) } }, translatePlayerAndCamera(where) { @@ -974,8 +976,8 @@ const simulation = { } else { Matter.Body.setVelocity(player, { x: 0, y: 0 }); Matter.Body.setPosition(player, { x: level.enter.x + 50, y: level.enter.y - 20 }); - m.damage(0.05 * simulation.difficultyMode); - m.energy -= 0.05 * simulation.difficultyMode + // m.damage(0.02 * simulation.difficultyMode); + // m.energy -= 0.02 * simulation.difficultyMode // move bots for (let i = 0; i < bullet.length; i++) { if (bullet[i].botType) { @@ -1003,15 +1005,28 @@ const simulation = { }); } if (tech.isHealthRecovery) { - const heal = 0.005 * m.maxHealth - m.addHealth(heal) - simulation.drawList.push({ //add dmg to draw queue - x: m.pos.x, - y: m.pos.y, - radius: Math.sqrt(heal) * 150, - color: "rgba(0,255,200,0.5)", - time: 4 - }); + if (tech.isEnergyHealth) { + if (m.immuneCycle < m.cycle) { + m.energy += m.maxEnergy * 0.005 + simulation.drawList.push({ //add dmg to draw queue + x: m.pos.x, + y: m.pos.y, + radius: Math.sqrt(m.maxEnergy * 0.02) * 60, + color: "rgba(0, 204, 255,0.4)", //#0cf + time: 4 + }); + } + } else { + const heal = 0.005 * m.maxHealth + m.addHealth(heal) + simulation.drawList.push({ //add dmg to draw queue + x: m.pos.x, + y: m.pos.y, + radius: Math.sqrt(heal) * 150, + color: "rgba(0,255,200,0.5)", + time: 4 + }); + } } } @@ -1355,7 +1370,7 @@ const simulation = { ctx.textAlign = "center"; ctx.fillText(`(${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})`, simulation.mouse.x, simulation.mouse.y - 20); }, - sight: { //credit to Cornbread for adding this algorithm to n-gon + sight: { //credit to Cornbread2100 for adding this algorithm to n-gon // square: 0, intersectMap: [], //this is precalculated in simulation.draw.lineOfSightPrecalculation() getIntersection(v1, v1End, domain) { diff --git a/js/spawn.js b/js/spawn.js index 5b5b277..a13550e 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -22,9 +22,10 @@ const spawn = { fullPickList: [ "slasher", "slasher", "slasher2", "slasher3", "hopper", "hopper", "hopMother", "hopMother", - "flutter", "flutter", "flutter", "stabber", "stabber", "stabber", "springer", "springer", "springer", + "stinger", "stinger", "stinger", + "flutter", "flutter", "shooter", "shooter", "grenadier", "grenadier", "striker", "striker", @@ -34,7 +35,7 @@ const spawn = { ], mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed mobTypeSpawnIndex: 0, //increases as the mob type cycles - allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter"], + allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter", "stinger"], setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level spawn.pickList.splice(0, 1); const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length] @@ -3837,6 +3838,202 @@ const spawn = { // } }; }, + stinger(x, y, radius = 18 + 4 * Math.random()) { + const color = '#5bc' + mobs.spawn(x, y, 7, radius, color); + let me = mob[mob.length - 1]; + Matter.Body.setDensity(me, 0.0025); //extra dense //normal is 0.001 //makes effective life much larger + // me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + + me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front + Matter.Body.rotate(me, Math.random() * Math.PI * 2); + me.accelMag = 0.0015 + 0.0007 * Math.sqrt(simulation.accelScale); + me.frictionAir = 0.04; + // me.seePlayerFreq = 40 + Math.floor(13 * Math.random()) + me.memory = 240; + me.restitution = 0.8; + me.frictionStatic = 0; + me.friction = 0; + me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1); + me.fireDir = { x: 0, y: 0 } + spawn.shield(me, x, y); + + // me.onDeath = function() {}; + me.flapRate = 0.06 + 0.03 * Math.random() + me.flapRadius = 40 + radius * 3 + me.do = function () { + this.seePlayerByHistory() + this.checkStatus(); + if (this.seePlayer.recall) { + this.force.x += Math.cos(this.angle) * this.accelMag * this.mass + this.force.y += Math.sin(this.angle) * this.accelMag * this.mass + + //set direction to turn to fire + if (!(simulation.cycle % this.seePlayerFreq)) { + this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); + //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles + const mod = (a, n) => a - Math.floor(a / n) * n + const sub = Vector.sub(m.pos, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different + const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI + if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random(); + } + + //rotate towards fireDir + const angle = this.angle + Math.PI / 2; + c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; + const threshold = 0.4; + const turn = 0.00002 * this.inertia + if (c > threshold) { + this.torque += turn; + } else if (c < -threshold) { + this.torque -= turn; + } + + // this.accelMag = 0.0006 + 0.0007 * Math.sqrt(simulation.accelScale); + this.frictionAir = 0.11 + 0.09 * Math.sin(simulation.cycle * this.flapRate - Math.PI / 2) + + const flapArc = 0.8 //don't go past 1.57 for normal flaps + ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)"; + this.wing(this.angle + 2.1 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) + this.wing(this.angle - 2.1 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) + + const seeRange = 550 + 35 * simulation.difficultyMode; + if (this.distanceToPlayer() < seeRange) { + const vertexCollision = function (v1, v1End, domain) { + for (let i = 0; i < domain.length; ++i) { + let vertices = domain[i].vertices; + const len = vertices.length - 1; + for (let j = 0; j < len; j++) { + results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[j], + v2: vertices[j + 1] + }; + } + } + } + results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[0], + v2: vertices[len] + }; + } + } + } + }; + best = { + x: null, + y: null, + dist2: Infinity, + who: null, + v1: null, + v2: null + }; + const seeRangeRandom = seeRange - 200 - 150 * Math.random() + const look = { + x: this.position.x + seeRangeRandom * Math.cos(this.angle), + y: this.position.y + seeRangeRandom * Math.sin(this.angle) + }; + vertexCollision(this.position, look, map); + vertexCollision(this.position, look, body); + if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]); + + // hitting player + if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { + const dmg = 0.002 * simulation.dmgScale; + m.damage(dmg); + //draw damage + ctx.fillStyle = color; + ctx.beginPath(); + ctx.arc(best.x, best.y, 5 + dmg * 1500, 0, 2 * Math.PI); + ctx.fill(); + } + //draw beam + const vertex = 3 + if (best.dist2 === Infinity) best = look; + ctx.beginPath(); + ctx.moveTo(this.vertices[vertex].x, this.vertices[vertex].y); + ctx.lineTo(best.x, best.y); + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); + ctx.stroke(); + ctx.setLineDash([]); + + // ctx.beginPath(); + // ctx.arc(this.vertices[vertex].x, this.vertices[vertex].y, 5, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay + // ctx.fillStyle = color; + // ctx.fill(); + } + // else { + // ctx.beginPath(); + // ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay + // ctx.fillStyle = color; + // ctx.fill(); + // } + } + // else { //flocking behavior (not working yet) + // this.force.x += Math.cos(this.angle) * this.accelMag * this.mass + // this.force.y += Math.sin(this.angle) * this.accelMag * this.mass + // //set direction to turn to fire + // if (!(simulation.cycle % this.seePlayerFreq)) { + // //find nearest mob and maintain a distance + // let nearestMob = null + // let nearestMobDistance = Infinity + // for (let i = 0; i < mob.length; i++) { + // const newMobDistance = Vector.magnitude(Vector.sub(this.position, mob[i].position)) + // if (mob[i].isDropPowerUp && mob[i].alive && newMobDistance < nearestMobDistance) { //&& !mob[i].isBoss + // nearestMobDistance = newMobDistance + // nearestMob = mob[i] + // } + // } + // if (nearestMob) { + // // console.log(nearestMob) + // this.fireDir = Vector.normalise(Vector.sub(nearestMob.position, this.position)); + // //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles + // const mod = (a, n) => { + // return a - Math.floor(a / n) * n + // } + // const sub = Vector.sub(nearestMob.position, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different + // const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI + // if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random(); + // } + // } + // //rotate towards fireDir + // const angle = this.angle + Math.PI / 2; + // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; + // const threshold = 0.4; + // const turn = 0.000025 * this.inertia + // if (c > threshold) { + // this.torque += turn; + // } else if (c < -threshold) { + // this.torque -= turn; + // } + // const flapArc = 0.7 //don't go past 1.57 for normal flaps + // ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)"; + // this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) + // this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius) + // } + }; + }, beetleBoss(x, y, radius = 50) { mobs.spawn(x, y, 7, radius, '#16576b'); let me = mob[mob.length - 1]; diff --git a/js/tech.js b/js/tech.js index 44d1103..347b876 100644 --- a/js/tech.js +++ b/js/tech.js @@ -231,7 +231,7 @@ const tech = { // } // } // } - if (tech.isDivisor && b.activeGun && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77 + if (tech.isDivisor && b.activeGun !== undefined && b.activeGun !== null && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77 if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.85 : 2 if (tech.isDilate) dmg *= 1.5 + 0.6 * Math.sin(m.cycle * 0.0075) if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length @@ -250,11 +250,11 @@ const tech = { if (tech.isBotDamage) dmg *= 1 + 0.06 * b.totalBots() if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage if (tech.isLowEnergyDamage) dmg *= 1 + 0.7 * Math.max(0, 1 - m.energy) - if (tech.energyDamage) dmg *= 1 + m.energy * 0.22 * tech.energyDamage; + if (tech.energyDamage) dmg *= 1 + m.energy * 0.26 * tech.energyDamage; if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.007 - if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 + if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2.11 if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.88, player.speed * 0.0193) - if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.83 + if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.93 if (tech.isAxion && tech.isHarmMACHO) dmg *= 2 - m.defense() if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3; if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit * (2 - m.defense()) // if (!simulation.paused) m.lastHit = 0 @@ -314,7 +314,7 @@ const tech = { }, tech: [{ name: "tungsten carbide", - description: "+222 maximum health
lose health after hard landings", + description: "+300 maximum health
lose health after hard landings", maxCount: 1, count: 0, frequency: 1, @@ -328,7 +328,7 @@ const tech = { tech.hardLanding = 70 tech.isFallingDamage = true; m.setMaxHealth(); - m.addHealth(2.22 / simulation.healScale) + m.addHealth(3 / simulation.healScale) m.skin.tungsten() }, remove() { @@ -402,9 +402,9 @@ const tech = { isAltRealityTech: true, isSkin: true, allowed() { - return !tech.isResearchReality && !tech.isSwitchReality + return !m.isAltSkin && !tech.isResearchReality && !tech.isSwitchReality }, - requires: "not Ψ(t) collapse, many-worlds", + requires: "not skinned, Ψ(t) collapse, many-worlds", damage: 2.42, effect() { m.skin.anodize(); @@ -672,6 +672,43 @@ const tech = { }, remove() { } }, + { + name: "supply chain", + descriptionFunction() { + return `double your current ammo for all your guns
triple the frequency of finding applied science` + }, + maxCount: 9, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + for (let i = 0; i < b.guns.length; i++) { + if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo) + } + simulation.makeGunHUD(); + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].name === "applied science") tech.tech[i].frequency *= 3 + } + }, + remove() { + if (this.count) { + for (let j = 0; j < this.count; j++) { + for (let i = 0; i < b.guns.length; i++) { + if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo) + } + } + simulation.makeGunHUD(); + + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].name === "applied science") tech.tech[i].frequency = 2 + } + } + } + }, { name: "applied science", description: `get a random guntech
for each of your guns`, //spawn ${powerUps.orb.research(1)} and @@ -812,40 +849,6 @@ const tech = { // } } }, - { - name: "supply chain", - descriptionFunction() { - return `double your current ammo
+4% JUNK to tech pool` - }, - maxCount: 9, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return true - }, - requires: "", - effect() { - for (let i = 0; i < b.guns.length; i++) { - if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo) - } - simulation.makeGunHUD(); - this.refundAmount += tech.addJunkTechToPool(0.04) - }, - refundAmount: 0, - remove() { - for (let j = 0; j < this.count; j++) { - for (let i = 0; i < b.guns.length; i++) { - if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo) - } - } - simulation.makeGunHUD(); - if (this.count > 0 && this.refundAmount > 0) { - tech.removeJunkTechFromPool(this.refundAmount) - this.refundAmount = 0 - } - } - }, { name: "logistics", description: `${powerUps.orb.ammo()} give 80% more ammo, but
it's only added to your current gun`, @@ -909,7 +912,7 @@ const tech = { }, { name: "non-renewables", - description: `+88% damage
${powerUps.orb.ammo()} can't spawn`, + description: `+97% damage
${powerUps.orb.ammo()} can't spawn`, maxCount: 1, count: 0, frequency: 1, @@ -918,7 +921,7 @@ const tech = { return !tech.isAmmoFromHealth && !tech.isBoostReplaceAmmo }, requires: "not catabolism, quasiparticles", - damage: 1.88, + damage: 1.97, effect() { tech.damage *= this.damage tech.isEnergyNoAmmo = true; @@ -2068,7 +2071,7 @@ const tech = { }, { name: "decorrelation", - description: "if your gun or field are unused for 2 seconds
+70% defense", + description: "if your gun or field are unused for 2 seconds
+77% defense", maxCount: 1, count: 0, frequency: 1, @@ -2086,7 +2089,7 @@ const tech = { }, { name: "anticorrelation", - description: "if your gun or field are unused for 2 seconds
+100% damage", + description: "if your gun or field are unused for 2 seconds
+111% damage", maxCount: 1, count: 0, frequency: 1, @@ -2785,7 +2788,7 @@ const tech = { }, { name: "overcharge", - description: "+66 maximum energy
+6% JUNK to tech pool", + description: "+66 maximum energy
+5% JUNK to tech pool", maxCount: 9, count: 0, frequency: 1, @@ -2797,7 +2800,7 @@ const tech = { effect() { tech.bonusEnergy += 0.66 m.setMaxEnergy() - this.refundAmount += tech.addJunkTechToPool(0.06) + this.refundAmount += tech.addJunkTechToPool(0.05) }, refundAmount: 0, remove() { @@ -2876,7 +2879,7 @@ const tech = { }, { name: "parasitism", - description: "if a mob has died in the last 5 seconds
+83% damage, inhibit energy generation", + description: "if a mob has died in the last 5 seconds
+93% damage, no passive energy generation", maxCount: 1, count: 0, frequency: 1, @@ -2917,7 +2920,10 @@ const tech = { }, { name: "recycling", - description: "if a mob has died in the last 5 seconds
recover 0.5% of max health per second", + descriptionFunction() { + return `if a mob has died in the last 5 seconds
recover 0.5% of max ${tech.isEnergyHealth ? "energy" : "health"} per second` + }, + description: "", maxCount: 1, count: 0, frequency: 1, @@ -2936,7 +2942,7 @@ const tech = { }, { name: "torpor", - description: "if a mob has not died in the last 5 seconds
+66% defense", + description: "if a mob has not died in the last 5 seconds
+74% defense", maxCount: 1, count: 0, frequency: 1, @@ -3280,7 +3286,7 @@ const tech = { }, 1000); }, descriptionFunction() { - return `once per level, instead of dying
use ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(5)}` + return `once per level, instead of dying
use ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(16)}` }, maxCount: 1, count: 0, @@ -3381,7 +3387,7 @@ const tech = { { name: "Ψ(t) collapse", link: `Ψ(t) collapse`, - description: `spawn ${powerUps.orb.research(16)}
after you research enter an alternate reality`, + description: `spawn ${powerUps.orb.research(21)}
after you research enter an alternate reality`, maxCount: 1, count: 0, frequency: 1, @@ -3391,7 +3397,7 @@ const tech = { return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch }, requires: "not many-worlds, Hilbert space, pseudoscience", - bonusResearch: 16, + bonusResearch: 21, effect() { tech.isResearchReality = true; for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false); @@ -3431,7 +3437,7 @@ const tech = { }, { name: "renormalization", - description: `46% chance to spawn ${powerUps.orb.research(1)} after consuming ${powerUps.orb.research(1)}
+3% JUNK to tech pool`, + description: `47% chance to spawn ${powerUps.orb.research(1)} after consuming ${powerUps.orb.research(1)}
+5% JUNK to tech pool`, maxCount: 1, count: 0, frequency: 2, @@ -3442,7 +3448,7 @@ const tech = { requires: "at least 4 research, not superdeterminism", effect() { tech.renormalization = true; - this.refundAmount += tech.addJunkTechToPool(0.03) + this.refundAmount += tech.addJunkTechToPool(0.05) }, refundAmount: 0, @@ -3481,7 +3487,7 @@ const tech = { }, { name: "ansatz", - description: `after choosing a field, tech, or gun
if you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(2)}`, + description: `after choosing a field, tech, or gun
if you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(3)}`, maxCount: 1, count: 0, frequency: 1, @@ -3501,17 +3507,17 @@ const tech = { name: "Bayesian statistics", // description: `for each ${powerUps.orb.research(1)} in your inventory
+3.8% damage`, descriptionFunction() { - return `spawn ${powerUps.orb.research(this.bonusResearch)}
+3% damage per ${powerUps.orb.research(1)} (${(3 * powerUps.research.count).toFixed(0)}%)` + return `spawn ${powerUps.orb.research(this.bonusResearch)}
+3% damage per ${powerUps.orb.research(1)} in your inventory (${(3 * powerUps.research.count).toFixed(0)}%)` }, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return powerUps.research.count > 2 || build.isExperimentSelection + return powerUps.research.count > 1 || build.isExperimentSelection }, - requires: "at least 3 research", - bonusResearch: 3, + requires: "at least 2 research", + bonusResearch: 6, effect() { powerUps.spawnDelay("research", this.bonusResearch) tech.isRerollDamage = true; @@ -3526,7 +3532,7 @@ const tech = { { name: "mass production", descriptionFunction() { - return `tech always have +3 choices to spawn
${powerUps.orb.ammo(10)} ${powerUps.orb.heal(10)}    or ${powerUps.orb.research(7)}` + return `tech always have +3 choices to spawn
options for   ${powerUps.orb.ammo(1)}   or   ${powerUps.orb.heal(1)}   or   ${powerUps.orb.research(1)}` }, // description: `tech always have +3 choices to spawn
${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)}    or ${powerUps.orb.research(5)}`, maxCount: 1, @@ -3544,8 +3550,10 @@ const tech = { }, { name: "research", - description: `spawn ${powerUps.orb.research(7)}`, - maxCount: 1, + descriptionFunction() { + return `spawn ${this.value > 36 ? this.value + powerUps.orb.research(1) : powerUps.orb.research(this.value)}
next time this effect is improved by ${powerUps.orb.research(5)}` + }, + maxCount: 9, count: 0, frequency: 0, frequencyDefault: 0, @@ -3553,15 +3561,19 @@ const tech = { isMassProduction: true, allowed() { return true }, requires: "", + value: 8, effect() { - powerUps.spawnDelay("research", 7); + powerUps.spawnDelay("research", this.value); + this.value += 5 }, remove() { } }, { name: "ammo", - description: `spawn ${powerUps.orb.ammo(10)}`, - maxCount: 1, + descriptionFunction() { + return `spawn ${this.value > 33 ? this.value + powerUps.orb.ammo(1) : powerUps.orb.ammo(this.value)}
next time this effect is improved by ${powerUps.orb.ammo(7)}` + }, + maxCount: 9, count: 0, frequency: 0, frequencyDefault: 0, @@ -3569,26 +3581,30 @@ const tech = { isMassProduction: true, allowed() { return true }, requires: "", + value: 10, effect() { - powerUps.spawnDelay("ammo", 10); + powerUps.spawnDelay("ammo", this.value); + this.value += 7 }, remove() { } }, { name: "heals", descriptionFunction() { - return `spawn ${powerUps.orb.heal(10)}` + return `spawn ${this.value > 30 ? this.value + powerUps.orb.heal(1) : powerUps.orb.heal(this.value)}
next time this effect is improved by ${powerUps.orb.heal(7)}` }, - maxCount: 1, + maxCount: 9, count: 0, frequency: 0, frequencyDefault: 0, isNonRefundable: true, isMassProduction: true, allowed() { return true }, - requires: "mass production", + requires: "", + value: 10, effect() { - powerUps.spawnDelay("heal", 10); + powerUps.spawnDelay("heal", this.value); + this.value += 7 }, remove() { } }, @@ -3624,7 +3640,7 @@ const tech = { effect() { tech.isBrainstorm = true tech.isBrainstormActive = false - tech.brainStormDelay = 1800 - simulation.difficultyMode * 100 + tech.brainStormDelay = 2000 - simulation.difficultyMode * 100 }, remove() { tech.isBrainstorm = false @@ -3921,7 +3937,11 @@ const tech = { }, { name: "paradigm shift", - description: `when paused clicking a tech ejects it
with a 20% chance to remove without ejecting`, + // description: `when paused clicking a tech ejects it
with a 20% chance to remove without ejecting`, + // description: `when paused clicking a tech ejects it
and a 20% chance to remove without ejecting`, + descriptionFunction() { + return `when paused clicking a tech ejects it
–6 ${tech.isEnergyHealth ? "energy" : "health"} each time and a 3% chance to fail` + }, maxCount: 1, count: 0, frequency: 1, @@ -4154,7 +4174,7 @@ const tech = { }, { name: "futures exchange", - description: "clicking cancel for a field, tech, or gun
gives +4.3% power up duplication chance", + description: "clicking cancel for a field, tech, or gun
gives +4.7% power up duplication chance", // descriptionFunction() { // return `clicking × to cancel a field, tech, or gun
gives +${4.9 - 0.15*simulation.difficultyMode}% power up duplication chance` // }, @@ -4177,7 +4197,7 @@ const tech = { }, { name: "replication", - description: "+9% chance to duplicate spawned power ups
+33% JUNK to tech pool", + description: "+10% chance to duplicate spawned power ups
+33% JUNK to tech pool", maxCount: 9, count: 0, frequency: 1, @@ -4187,7 +4207,7 @@ const tech = { }, requires: "below 100% duplication chance", effect() { - tech.duplicateChance += 0.09 + tech.duplicateChance += 0.1 powerUps.setPowerUpMode(); //needed after adjusting duplication chance if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11); this.refundAmount += tech.addJunkTechToPool(0.33) @@ -4204,7 +4224,7 @@ const tech = { }, { name: "stimulated emission", - description: "+17% chance to duplicate spawned power ups,
but after a collision eject 1 tech", + description: "+19% chance to duplicate spawned power ups,
but after a collision eject 1 tech", maxCount: 1, count: 0, frequency: 1, @@ -4328,6 +4348,34 @@ const tech = { } } }, + { + name: "strange loop", + // description: `+11% damage
removing this doubles it's damage if you take it again`, + description: `+9% damage
removing this gives strange attractor and null hypothesis`, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + isBadRandomOption: true, + allowed() { + return true + }, + requires: "", + damage: 1.09, + effect() { + tech.damage *= this.damage + }, + remove() { + if (this.count > 0 && m.alive) { + tech.damage /= this.damage + this.frequency = 0 + requestAnimationFrame(() => { + tech.giveTech("null hypothesis") + tech.giveTech("strange attractor") + }); + } + } + }, { name: "null hypothesis", description: `+8% damage
removing this spawns ${powerUps.orb.research(15)}`, @@ -4352,6 +4400,35 @@ const tech = { } } }, + { + name: "martingale", + descriptionFunction() { + return `+${(100 * this.damage).toFixed(0)}% damage. After removing this there is a 50%
chance to get it back with double its damage
` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + isBadRandomOption: true, + allowed() { + return true + }, + requires: "", + damage: 0.11, + effect() { + tech.damage *= 1 + this.damage + }, + remove() { + if (this.count > 0 && m.alive) { + tech.damage /= 1 + this.damage + if (Math.random() < 0.5) { + this.damage *= 2 + requestAnimationFrame(() => { tech.giveTech("chaos theory") }); + } + this.frequency = 0 + } + } + }, { name: "Born rule", description: "remove all current tech
spawn new tech to replace them", @@ -4744,6 +4821,8 @@ const tech = { b.guns[0].ammoPack = b.guns[0].defaultAmmoPack; if (b.guns[0].recordedAmmo) b.guns[0].ammo = b.guns[0].recordedAmmo simulation.updateGunHUD(); + + if (this.count) requestAnimationFrame(() => { simulation.updateGunHUD(); }); } tech.isIceCrystals = false; if (b.guns[0].ammo === Infinity) b.guns[0].ammo = 0 @@ -5377,6 +5456,7 @@ const tech = { if (this.count > 0 && b.guns[3].savedAmmo !== undefined) { b.guns[3].ammo = b.guns[3].savedAmmo simulation.updateGunHUD(); + requestAnimationFrame(() => { simulation.updateGunHUD(); }); } else if (b.guns[3].ammo === Infinity) { b.guns[3].ammo = 0 } @@ -7071,7 +7151,7 @@ const tech = { }, { name: "induction furnace", - description: "after using harpoon or grapple to collect power ups
+77% harpoon or grapple damage for 8 seconds", + description: "after using harpoon/grapple to collect power ups
+77% harpoon or grapple damage for 8 seconds", isGunTech: true, maxCount: 1, count: 0, @@ -7091,7 +7171,7 @@ const tech = { }, { name: "brittle", - description: "+88% harpoon and grapple damage
to mobs at maximum health", + description: "+88% harpoon/grapple damage
to mobs at maximum health", isGunTech: true, maxCount: 1, count: 0, @@ -7595,7 +7675,7 @@ const tech = { { name: "electronegativity", descriptionFunction() { - return `+0.22% damage per current stored energy
(+${(22 * m.maxEnergy).toFixed(0)}% damage at max energy)` + return `+0.26% damage per current stored energy
(+${(27 * m.maxEnergy).toFixed(0)}% damage at max energy)` }, // description: "+1% damage per 8 stored energy", isFieldTech: true, diff --git a/style.css b/style.css index 3971c41..f71c38e 100644 --- a/style.css +++ b/style.css @@ -1376,4 +1376,130 @@ summary { .link:hover { text-decoration: underline; +} + +/* +.fade-ins { + animation: 1.5s linear 1s fadeins; +} + +@keyframes fadeins { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} */ +.blurry-text { + color: transparent; + text-shadow: 0 0 9px rgba(0, 0, 0, 0.5); +} + +.unblur { + color: transparent; + text-shadow: 0 0 9px rgba(0, 0, 0, 0.5); + animation: 1.5s ease 1.2s normal forwards 1 unblur; +} + +@keyframes unblur { + 0% { + color: transparent; + text-shadow: 0 0 9px rgba(0, 0, 0, 0.5); + } + + 100% { + /* font-weight: 800; */ + color: #000; + text-shadow: 0 0 0px rgba(0, 0, 0, 0.5); + } +} + +.fade-in { + opacity: 0; + animation: 2s ease 1.5s normal forwards 1 fadein; +} + +.fade-in-fast { + opacity: 0; + animation: 1.5s ease 1s normal forwards 1 fadein; +} + +.fade-in-faster { + opacity: 0; + animation: 2s ease 0.5s normal forwards 1 fadein; +} + +@keyframes fadein { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes dash { + to { + stroke-dashoffset: 0; + } +} + +.draw-lines { + stroke-dasharray: 20; + stroke-dashoffset: 20; + animation: dash 2.4s ease-in forwards; +} + +.draw-lines-dash { + stroke-dasharray: 4; + stroke-dashoffset: 4; + animation: dash 2.4s ease-in forwards; +} + +.draw-lines-o { + stroke-dasharray: 11; + stroke-dashoffset: 11; + animation: dash 2.4s ease-in forwards; +} + +.draw-lines-g { + stroke-dasharray: 17; + stroke-dashoffset: 17; + animation: dash 2.4s ease-in forwards; +} + +.draw-lines-box-1 { + stroke-dasharray: 1000; + stroke-dashoffset: 1000; + animation: dash 5s ease-in forwards; + animation-delay: 0s; +} + +.draw-lines-box-2 { + stroke-dasharray: 1000; + stroke-dashoffset: 1000; + animation: dash 2.6s ease-in forwards; + animation-delay: 1s; +} + +.draw-lines-box-3 { + stroke-dasharray: 1000; + stroke-dashoffset: 1000; + animation: dash 1.15s ease-in forwards; + animation-delay: 1.55s; +} + +.draw-lines3 { + stroke-dasharray: 3000; + stroke-dashoffset: 3000; + animation: dash 3.1s ease-in forwards; +} + +.draw-lines4 { + stroke-dasharray: 300; + stroke-dashoffset: 300; + animation: dash 2.5s ease-in forwards; } \ No newline at end of file diff --git a/todo.txt b/todo.txt index 5351fe1..0deb9e0 100644 --- a/todo.txt +++ b/todo.txt @@ -1,55 +1,21 @@ ******************************************************** NEXT PATCH ************************************************** -mob health tech - tech: cascading failure - +222% damage to mobs below 25% health - tech: yield stress - +55% damage to mobs at maximum health - cloaking tech: topological defect - +88% damage to mobs at maximum health - harpoon tech: brittle - +88% harpoon/grapple damage to mobs at maximum health -cloaking buffs - 50->66% defense while cloaked - recloak 0.25s faster - simplified cloaking field graphics - boson composite drains much less energy while moving through mobs and shields - fixed bug where mines and egg mobs were colliding with player while intangible - patch no longer drains energy when you heal on cloaking - metamaterial absorber gets 17->22% chance to spawn a power up for each mob alive - no-cloning theorem changes to 45->40% duplication and 2->1% duplication loss on killing a mob -finalBoss phases: - new: slow zone, antigravity pulse - nerfed: laser, black hole, orbitals - buffed: oscillation, mobs - improved graphics: boulder - -Hilbert space has a skin. 99->142% damage increase, but randomize tech after taking damage -Higgs mechanism has a skin. +45->77% fire rate, player can't move while firing -induction furnace gives +77% harpoon/grapple damage for 8 seconds after picking up a power up -collider 50->100% chance to combine and randomize power ups -quenching gives more bonus max health at high difficulty level (maybe around 30% more health) -accretion gives 5->7 heal power ups -dynamo bots follow player much closer when you have many of them -scrap-bots don't follow the player as accurately or as quickly - scrap bot duration 13->15 seconds -JUNK tech: planned obsolescence - make 100 scrap bots that last for about 30 seconds - -community map dojo by werid_pusheen - fixed by Cornbread 2100 - -hard mode gets 1 less heal at the start -hard and why difficulty don't begin with starter mobs -hopBullet mobs last 2 seconds less time -adjusted button heights on train station level to be consistently the same height *********************************************************** TODO ***************************************************** -hexagon head skin - maybe give defense - foam tech: increase size of foam and increase duration, but drop speed down, so they come to a stop and just hang allow them to harm player? this is probably just too annoying +Foam slow down mobs twice as much and slowly pulls them towards the ground + +30% foam damage + Half foam velocity + Foam is now effected by gravity + Requires a source of foam and not aerogel + https://en.m.wikipedia.org/wiki/Tungsten_hexafluoride + make a flutter variant just move the wings to the back? @@ -1054,9 +1020,10 @@ add sounds ******************************************************** LORE ******************************************************** +look up sci-fi science ideas here https://projectrho.com/public_html/rocket/ + possible names for tech sidereal - with respect to the stars (an extra rotation for time keeping) - strange loop holonomy - parallel transport of a vector leads to movement (applies to curved space) hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other. swarm intelligence - for a drone tech @@ -1102,9 +1069,9 @@ possible names for tech memetics magnetorquers - produce spin by pushing on earth's magnetic field Josephson junction - superconducting junction - Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity - perturbation + Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity Unruh effect - accelerating makes heat/thermal particles + configuration space - holds the position of everything ******************************************************** CARS IMAGES ********************************************************