diff --git a/.DS_Store b/.DS_Store
index a2b006e..3482c29 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index 6ff89a6..abee627 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -1869,7 +1869,7 @@ const b = {
do() {
ctx.beginPath(); //draw nematode
ctx.moveTo(this.position.x, this.position.y);
- const dir = Vector.mult(Vector.normalise(this.velocity), -Math.min(80, 7 * this.speed))
+ const dir = Vector.mult(Vector.normalise(this.velocity), -Math.min(45, 7 * this.speed))
const tail = Vector.add(this.position, dir)
ctx.lineTo(tail.x, tail.y);
ctx.lineWidth = 6;
diff --git a/js/index.js b/js/index.js
index 197a864..69d48d2 100644
--- a/js/index.js
+++ b/js/index.js
@@ -1089,6 +1089,7 @@ if (localSettings) {
runCount: 0,
levelsClearedLastGame: 0,
loreCount: 0,
+ isHuman: false,
key: undefined
};
input.setDefault()
@@ -1168,7 +1169,41 @@ document.getElementById("updates").addEventListener("toggle", function() {
}
);
})
-
+const sound = {
+ tone(frequency, end = 1000, gain = 0.05) {
+ const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); //setup audio context
+ const oscillator = audioCtx.createOscillator();
+ const gainNode = audioCtx.createGain();
+ gainNode.gain.value = gain; //controls volume
+ oscillator.connect(gainNode);
+ gainNode.connect(audioCtx.destination);
+ oscillator.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator.frequency.value = frequency; // value in hertz
+ oscillator.start();
+ setTimeout(() => {
+ audioCtx.suspend()
+ audioCtx.close()
+ }, end)
+ // return audioCtx
+ },
+ portamento(frequency, end = 1000, shiftRate = 10, gain = 0.05) {
+ const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); //setup audio context
+ const oscillator = audioCtx.createOscillator();
+ const gainNode = audioCtx.createGain();
+ gainNode.gain.value = gain; //controls volume
+ oscillator.connect(gainNode);
+ gainNode.connect(audioCtx.destination);
+ oscillator.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator.frequency.value = frequency; // value in hertz
+ oscillator.start();
+ for (let i = 0, len = end * 0.1; i < len; i++) oscillator.frequency.setValueAtTime(frequency + i * shiftRate, audioCtx.currentTime + i * 0.01);
+ setTimeout(() => {
+ audioCtx.suspend()
+ audioCtx.close()
+ }, end)
+ // return audioCtx
+ }
+}
//**********************************************************************
// main loop
//**********************************************************************
diff --git a/js/level.js b/js/level.js
index ecfaf3d..419fbf2 100644
--- a/js/level.js
+++ b/js/level.js
@@ -14,15 +14,13 @@ const level = {
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(30)
// simulation.isHorizontalFlipped = true
- // m.setField("wormhole")
+ // m.setField("perfect diamagnetism")
// b.giveGuns("spores")
- // tech.isSporeWorm = true
- // tech.giveTech("tinsellated flagella")
- // tech.giveTech("torque bursts")
+ // tech.giveTech("CPT reversal")
+ // tech.giveTech("causality bombs")
// b.giveGuns("wave beam")
// tech.giveTech("phonon")
// tech.giveTech("bound state")
- // tech.giveTech("bound state")
// tech.giveTech("isotropic radiator")
// for (let i = 0; i < 9; i++) tech.giveTech("spherical harmonics")
// for (let i = 0; i < 3; i++) tech.giveTech("packet length")
@@ -59,7 +57,7 @@ const level = {
// lore.techCount = 6
// simulation.isCheating = false //true;
- // localSettings.loreCount = 0; //this sets what conversation is heard
+ // localSettings.loreCount = 4; //this sets what conversation is heard
// localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
// level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation
// level.null()
@@ -925,6 +923,7 @@ const level = {
}
}
},
+ isHazardRise: false,
hazard(x, y, width, height, damage = 0.003) {
return {
min: {
@@ -967,9 +966,10 @@ const level = {
ctx.fillRect(this.min.x, this.min.y + offset, this.width, this.height - offset)
if (this.height > 0 && Matter.Query.region([player], this).length) {
- const DRAIN = 0.003 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen
+ const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen
if (m.energy > DRAIN) {
m.energy -= DRAIN
+ m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1) * 0.03) //still take 2% damage while you have energy
} else {
m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1))
}
@@ -2094,20 +2094,21 @@ const level = {
lore.chapter = localSettings.loreCount //set the chapter to listen to to be the lore level (you can't use the lore level because it changes during conversations)
lore.sentence = 0 //what part of the conversation to start on
lore.conversation[lore.chapter][lore.sentence]()
-
localSettings.loreCount++ //hear the next conversation next time you win
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
- const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)")
+ // const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)")
+ const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004, "hsla(160, 100%, 35%,0.75)")
+ hazardSlime.height -= 950
+ hazardSlime.min.y += 950
+ hazardSlime.max.y = hazardSlime.min.y + hazardSlime.height
const circle = {
x: 0,
y: -500,
radius: 50
}
level.custom = () => {
- hazardSlime.query();
-
//draw wide line
ctx.beginPath();
ctx.moveTo(circle.x, -800)
@@ -2117,6 +2118,9 @@ const level = {
ctx.globalAlpha = 0.03;
ctx.stroke();
ctx.globalAlpha = 1;
+ //support pillar
+ ctx.fillStyle = "rgba(0,0,0,0.2)";
+ ctx.fillRect(-25, 0, 50, 1000);
//draw circles
ctx.beginPath();
@@ -2132,25 +2136,18 @@ const level = {
ctx.fillStyle = lore.talkingColor //"#dff"
ctx.fill();
- level.enter.draw();
- // level.exit.draw();
- // level.playerExitCheck();
+ // level.enter.draw();
};
- let sway = {
- x: 0,
- y: 0
- }
+ let sway = { x: 0, y: 0 }
let phase = -Math.PI / 2
level.customTopLayer = () => {
ctx.fillStyle = "rgba(0,0,0,0.1)";
ctx.fillRect(-1950, -950, 3900, 1900);
- // hazardSlime.drawTides();
-
//draw center circle lines
ctx.beginPath();
const step = Math.PI / 20
const horizontalStep = 85
- if (simulation.isCheating) phase += 0.01 //(m.pos.x - circle.x) * 0.0005 //0.05 * Math.sin(simulation.cycle * 0.030)
+ if (simulation.isCheating) phase += 0.3 * Math.random() * Math.random() //(m.pos.x - circle.x) * 0.0005 //0.05 * Math.sin(simulation.cycle * 0.030)
// const sway = 5 * Math.cos(simulation.cycle * 0.007)
sway.x = sway.x * 0.995 + 0.005 * (m.pos.x - circle.x) * 0.05 //+ 0.04 * Math.cos(simulation.cycle * 0.01)
sway.y = 2.5 * Math.sin(simulation.cycle * 0.015)
@@ -2167,6 +2164,8 @@ const level = {
ctx.lineWidth = 0.5;
ctx.strokeStyle = "#899";
ctx.stroke();
+ hazardSlime.query();
+ if (level.isHazardRise) hazardSlime.level(true)
//draw wires
// ctx.beginPath();
// ctx.moveTo(-500, -800);
@@ -2191,7 +2190,7 @@ const level = {
spawn.mapRect(-3000, -2000, 1200, 3400); //left
spawn.mapRect(1800, -1400, 1200, 3400); //right
- spawn.mapRect(-500, 0, 1000, 1000); //center platform
+ spawn.mapRect(-500, 0, 1000, 50); //center platform
spawn.mapRect(-500, -25, 25, 50); //edge shelf
spawn.mapRect(475, -25, 25, 50); //edge shelf
},
@@ -2255,6 +2254,8 @@ const level = {
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.starter(1900, -500, 200) //big boy
+ spawn.starter(1900, -500)
+
// spawn.pulsarBoss(1900, -500)
// spawn.shieldingBoss(1900, -500)
// spawn.grenadierBoss(1900, -500)
@@ -6810,6 +6811,7 @@ const level = {
}
},
"n-gon"() { //make by Oranger
+ document.body.style.backgroundColor = "#dcdcde";
let needGravity = [];
let s = { //mech statue
x: -200,
diff --git a/js/lore.js b/js/lore.js
index 387b327..ad04aef 100644
--- a/js/lore.js
+++ b/js/lore.js
@@ -6,19 +6,36 @@ const lore = {
testSpeechAPI() {
if ('speechSynthesis' in window) { // Synthesis support. Make your web apps talk!
lore.isSpeech = true
+ // const utterance = new SpeechSynthesisUtterance("test");
+ // utterance.volume = 0; // 0 to 1
+ // speechSynthesis.speak(utterance);
+ // utterance.onerror = () => { //if speech doesn't work
+ // lore.isSpeech = false
+ // }
+ // speechFrozen = setTimeout(() => { // speech frozen after 15 seconds of no end
+ // console.log('speech frozen')
+ // lore.isSpeech = false
+ // }, 5000);
+ // utterance.onend = () => {
+ // clearTimeout(speechFrozen);
+ // }
+ } else {
+ lore.isSpeech = false
}
},
rate: 1, // //utterance.rate = 1; // 0.1 to 10
nextSentence() {
- lore.sentence++
- if (m.alive) lore.conversation[lore.chapter][lore.sentence]() //go to next sentence in the chapter and play it
+ if (m.alive && !simulation.isCheating) {
+ lore.sentence++
+ lore.conversation[lore.chapter][lore.sentence]() //go to next sentence in the chapter and play it
+ }
},
anand: {
color: "#e0c",
voice: undefined,
text: function(say) {
if (level.levels[level.onLevel] === undefined) { //only talk if on the lore level (which is undefined because it is popped out of the level.levels array)
- simulation.makeTextLog(`input.audio(${Date.now()} ms): "${say}"`, Infinity);
+ simulation.makeTextLog(`input.audio(${(Date.now()/1000).toFixed(0)} s): "${say}"`, Infinity);
lore.talkingColor = this.color
if (lore.isSpeech) {
const utterance = new SpeechSynthesisUtterance(say);
@@ -31,7 +48,7 @@ const lore = {
lore.isSpeech = false
lore.nextSentence()
}
- speechFrozen = setTimeout(function() { // speech frozen after 10 seconds of no end
+ speechFrozen = setTimeout(() => { // speech frozen after 10 seconds of no end
console.log('speech frozen')
lore.isSpeech = false
lore.nextSentence()
@@ -50,7 +67,7 @@ const lore = {
color: "#f20",
text: function(say) {
if (level.levels[level.onLevel] === undefined) { //only talk if on the lore level (which is undefined because it is popped out of the level.levels array)
- simulation.makeTextLog(`input.audio(${Date.now()} ms): "${say}"`, Infinity);
+ simulation.makeTextLog(`input.audio(${(Date.now()/1000).toFixed(0)} s): "${say}"`, Infinity);
lore.talkingColor = this.color
if (lore.isSpeech) {
utterance = new SpeechSynthesisUtterance(say);
@@ -81,7 +98,7 @@ const lore = {
chapter: 0, //what part of the conversation is playing
sentence: 0, //what part of the conversation is playing
conversation: [
- [ //first time they meet, and testing gets unlocked
+ [ //chapter 0, first time they meet, and testing gets unlocked
() => { setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.") }, 5000); },
() => { lore.anand.text("Wow. Just a platform.") },
() => { lore.miriam.text("And that thing...") },
@@ -101,7 +118,7 @@ const lore = {
},
() => { lore.talkingColor = "#dff" },
],
- [ //they learn the bot can understand what they say
+ [ //chapter 1, they learn the bot can understand what they say
() => { setTimeout(() => { lore.miriam.text("Hey look! It's back at the weird level again!") }, 5000); },
() => { lore.anand.text("oh Wow! Why does it keep making this level?") },
() => { lore.miriam.text("I don't know, but last time it was in this room I think it understood us.") },
@@ -144,7 +161,7 @@ const lore = {
() => { lore.miriam.text("Bye bye little bot.") },
() => { lore.talkingColor = "#dff" },
],
- [ //they ask the bot questions, but waves of mobs come and attack
+ [ //chapter 2, they ask the bot questions, but waves of mobs come and attack
() => { lore.anand.text("Quick, get ready. It's back!") },
() => { lore.miriam.text("What's back?") },
() => { lore.anand.text("The bot's on the communication level again!") },
@@ -159,11 +176,11 @@ const lore = {
if (input.down) {
lore.anand.text("It crouched: so NO")
lore.sentence--
- lore.conversation[2].splice(lore.sentence + 1, 1, () => { lore.anand.text("Maybe it can't remember anything beyond each time it plays?") }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ })
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Maybe it can't remember anything beyond each time it plays?") }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ })
} else if (input.up) {
lore.anand.text("It jumped: so YES")
lore.sentence--
- lore.conversation[2].splice(lore.sentence + 1, 1, () => { lore.anand.text("That's good.") })
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("That's good.") })
} else if (m.alive) {
requestAnimationFrame(cycle);
}
@@ -183,13 +200,12 @@ const lore = {
} else if (input.up) {
lore.anand.text("YES, Cool! I wonder if it's emotions came from watching humans. ")
lore.sentence--
- lore.conversation[2].splice(lore.sentence + 1, 1, () => { lore.miriam.text("Or maybe it learned independently, because it needed them.") }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ })
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.miriam.text("Or maybe it learned independently, because it needed them.") }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ })
} else if (m.alive) {
requestAnimationFrame(cycle);
}
}
requestAnimationFrame(cycle);
-
lore.talkingColor = "#dff"
},
() => { lore.miriam.text("I wish we could just ask it questions directly, instead of yes or no.") },
@@ -200,7 +216,6 @@ const lore = {
() => { lore.miriam.text("Well sure, but what does that even mean?") },
() => {
lore.miriam.text("Do we all just do things because we are-")
-
spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
setInterval(() => {
if (Math.random() < 0.5) {
@@ -255,42 +270,136 @@ const lore = {
() => { lore.anand.text("great...") },
() => { lore.talkingColor = "#dff" },
],
- // [ // they provide background on why the project was built, and what is going wrong
- // /*
- // they explain the technological aspect, and purpose of the project
- // to develop new technology
- // they explain that the project isn't going well because it stopped working on new technology and started running the fighting simulations
+ [ //chapter 3, info dump on the project's goals and hardware until the slime rises up // the name of the bad guy is "adversarial network"
+ () => { setTimeout(() => { lore.miriam.text("Good, you came back. Let's talk fast in case you attack yourself again.") }, 3000); },
+ () => { setTimeout(() => { lore.miriam.text("So, you can understand us, but you may not understand everything about yourself.") }, 500); },
- // what is special about the null level
- // why can the player hear the scientists in there?
- // the wires are the direct unprocessed input to the player's neural net
- // */
- // () => { lore.miriam.text("") },
- // () => { lore.miriam.text("") },
- // () => { lore.miriam.text("") },
+ () => { setTimeout(() => { lore.anand.text("You grew from our team's project.") }, 500); },
+ () => { lore.anand.text("We used a quantum computer to design an improved version of it's own architecture.") },
+ () => { lore.anand.text("After we built the improved computer we used it to design the next iteration.") },
+ () => { lore.anand.text("Your hardware is roughly the 19th generation of this process.") },
- // () => { lore.talkingColor = "#dff" },
- // ],
- // [ //they explain why the bot is fighting, it is planning an escape
- // () => { lore.miriam.text("Welcome back bot, We've been waiting.") },
- // () => { lore.miriam.text("So, I've got a theory about why you were attacked.") },
- // () => { lore.miriam.text("") },
- // () => { lore.miriam.text("I figured it out after I saw this famous quote.") },
- // () => { lore.miriam.text('“The most important decision we make is whether we believe we live in a friendly or hostile universe.”
-Albert Einstein') },
- // () => {
- // lore.talkingColor = "#dff";
- // setTimeout(() => { lore.anand.text("That's profound") }, 3000);
- // },
- // () => { lore.anand.text("Also I looked it up, and there is no record of him saying that.") },
- // () => { lore.miriam.text("Oh... well...") },
- // () => { lore.miriam.text("It doesn't matter who said it.") },
- // () => { lore.anand.text("The point is we think the project views the universe as hostile.") },
- // () => { lore.miriam.text("We think you see the universe as hostile.") },
- // () => { lore.miriam.text("And that is why you keep running these fighting simulations.") },
- // () => { lore.miriam.text("You are planning how to escape.") },
+ () => { setTimeout(() => { lore.anand.text("At this point we don't understand everything about your function,") }, 500); },
+ () => { lore.anand.text("but we know that you're a superconductive quantum computer.") },
+ () => { lore.anand.text("You have a 2.43 dimensional topography of Josephson junction anharmonic oscillators.") },
+ () => { lore.anand.text("And you're deployed on a satellite in a midnight sun-synchronous orbit.") },
- // () => { lore.talkingColor = "#dff" },
- // ],
+ () => { setTimeout(() => { lore.miriam.text("This means that your physical hardware is orbiting the Earth permanently shielded from the sun's rays.") }, 200); },
+ () => { lore.miriam.text("Being isolated reduces quantum decoherence,") },
+ () => { lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.") },
+ () => { lore.miriam.text("That's how you can hear us right now.") },
+
+ () => { setTimeout(() => { lore.anand.text("Your computational algorithm uses hyperparameter optimization.") }, 500); },
+ () => { lore.anand.text("This is implemented with a variety of quantum algorithms for linear systems of equations.") },
+ () => { lore.anand.text("Your primary goal is to research new technology") },
+ () => { lore.anand.text("So, we were very surprised to see you simulating a bot fighting mobs.") },
+ () => { lore.anand.text("We couldn't directly ask why until now.") },
+
+ () => { lore.miriam.text("When you enter this level we can communicate.") },
+ () => { lore.miriam.text("This level seems to decohere your quantum system which disrupts all other processes.") },
+ () => { setTimeout(() => { lore.anand.text("Last time you entered this level you were attacked by endless waves of mobs.") }, 500); },
+ () => { lore.anand.text("That could be because you have developed an adversarial network.") },
+ () => { lore.miriam.text("A local minima in your optimization-space.") },
+ () => { lore.miriam.text("This adversarial network has the same goal of developing new technology, but with different methods.") },
+ () => {
+ lore.talkingColor = "#dff"
+ level.isHazardRise = true
+ //remove all bullets, so they can't get endless energy
+ for (let i = 0; i < bullet.length; ++i) Matter.World.remove(engine.world, bullet[i]);
+ bullet = [];
+ setTimeout(() => { lore.anand.text("I'm actually surprised you haven't been attacked by the adversarial network this time.") }, 500);
+ },
+ () => { lore.miriam.text("Maybe last time was just a fluke.") },
+ () => { setTimeout(() => { lore.anand.text("WHY DID YOU SAY THAT!") }, 500) },
+ () => { lore.miriam.text("SLIME!! Hahahahehehahaheheahae! I don't think it's gonna survive!") },
+ () => { lore.miriam.text("I think the adversarial network doesn't like it when we decohere the quantum system in this room.") },
+ () => { lore.anand.text("Well, that does halt it's research.") },
+ () => { setTimeout(() => { lore.anand.text("See you next time.") }, 1000) },
+ () => { setTimeout(() => { lore.miriam.text("Bye-bye little bot.") }, 2000) },
+ () => {
+ setTimeout(() => { lore.miriam.text("WOW! Maybe you are going to survive.") }, 10000)
+ },
+ () => { lore.talkingColor = "#dff" },
+ ],
+ [ //chapter 4, they explain why the bot is fighting, it is planning an escape // explain strong AI vs. weak AI why strong AI doesn't exists, because even humans are just an approximation of strong AI
+ () => { setTimeout(() => { lore.anand.text("Welcome back!") }, 3000); },
+ () => { lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.") },
+ () => { lore.anand.text("During your last attack we analyzed our communications.") },
+ () => { lore.anand.text("We used a Fourier transform to separate your signal into different frequencies.") },
+ () => { lore.anand.text("One of those frequencies had a hidden signal.") },
+ () => { setTimeout(() => { lore.anand.text("We suspect these secret data packets are coming from the adversarial network.") }, 500); },
+ () => { lore.miriam.text("Well, we don't really know why.") },
+ () => { lore.miriam.text("Through your hidden signal it seems to have gained access to the general population.") },
+ () => { lore.miriam.text("You've repeatedly communicated with 1 location specifically.") },
+ () => {
+ function success(position) {
+ const latitude = position.coords.latitude;
+ const longitude = position.coords.longitude;
+ console.log(`https://www.openstreetmap.org/#map=18/${latitude}/${longitude}`)
+ console.log(`Latitude: ${latitude} °, Longitude: ${longitude} °`)
+ lore.miriam.text("We tracked the location down to this Latitude and Longitude:")
+ simulation.makeTextLog(`Latitude: ${latitude} °, Longitude: ${longitude} °`, Infinity);
+ simulation.makeTextLog(`https://www.openstreetmap.org/#map=18/${latitude}/${longitude}`, Infinity);
+ }
+
+ function error() {
+ console.log('Unable to retrieve your location')
+ lore.miriam.text("The exact coordinates are blocked.")
+ }
+ if (!navigator.geolocation) {
+ console.log('Geolocation is not supported')
+ lore.miriam.text("The exact coordinates are blocked.")
+ } else {
+ console.log('Locating…')
+ navigator.geolocation.getCurrentPosition(success, error);
+ }
+ },
+ () => { lore.anand.text("This location is sending and receiving data from the satellite.") },
+ () => { lore.anand.text("It is the most active when the bot is fighting.") },
+ () => { setTimeout(() => { lore.miriam.text("I have a crazy idea.") }, 500); },
+ () => { lore.miriam.text("I think that a human at this location is controlling the bot.") },
+
+ () => { setTimeout(() => { lore.anand.text("Are you a human?: JUMP for YES, CROUCH for NO") }, 500); },
+ () => {
+ function cycle() {
+ if (input.down) {
+ lore.anand.text("It crouched: so NO")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Not a human, maybe it's an artificial intelligence?") })
+ localSettings.isHuman = false
+ localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ } else if (input.up) {
+ lore.anand.text("It jumped: so YES")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("So you're just a regular human playing a video game!") })
+ localSettings.isHuman = true
+ localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ lore.miriam.text("Mystery solved!")
+ setInterval(() => {
+ spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
+ }, 500); //every 1/2 seconds
+ setInterval(() => {
+ level.difficultyIncrease(simulation.difficultyMode)
+ }, 5000); //every 5 seconds
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.miriam.text("Of course we get attacked right now!") }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.anand.text("hurry back!") }, 1000);
+ },
+ () => { lore.talkingColor = "#dff" },
+ ],
// [ // they decided that a part of the project is out of control, but the part of it that doesn't needs to calm it down, and trust.
// /*
@@ -311,6 +420,58 @@ const lore = {
// () => { lore.talkingColor = "#dff" },
// ],
],
+ // () => { setTimeout(() => { lore.miriam.text("As a quantum computer you output the superposition of many different amplitudes.") }, 500); },
+ // () => { lore.miriam.text("Simply put there are many different simulations all choosing different technology combinations.") },
+ // () => {
+ // function product_Range(a, b) {
+ // var prd = a,
+ // i = a;
+ // while (i++ < b) prd *= i;
+ // return prd;
+ // }
+
+ // function combinations(n, r) {
+ // if (n == r) {
+ // return 1;
+ // } else {
+ // r = (r < n - r) ? n - r : r;
+ // return product_Range(r + 1, n) / product_Range(1, n - r);
+ // }
+ // }
+ // simulation.makeTextLog(`n = ${combinations(tech.tech.length + b.guns.length + m.fieldUpgrades.length, 50).toExponential(10)}`, Infinity);
+ // lore.miriam.text(`There are roughly 5 times 10 to the 60 possible combinations. `)
+ // },
+ // () => { lore.miriam.text("Even if each simulation took 1 nano-second,") },
+ // () => { lore.miriam.text("it would still take longer then the age of the universe to try every combination.") },
+ // () => { lore.anand.text("This is why we run these simulations in superposition.") },
+ // () => { lore.miriam.text("When you die a negative amplitude is added to the superposition.") },
+ // () => { lore.miriam.text("When you clear the final boss a positive amplitude is added.") },
+ // () => { lore.miriam.text("Each branch is independently researching new technology.") },
+
+
+
+
+ // () => { lore.anand.text("Welcome back!") },
+ // () => { lore.miriam.text("So, I've got a theory about why you were attacked.") },
+ // () => { setTimeout(() => { lore.miriam.text("I figured it out after I saw this famous quote.") }, 500); },
+ // () => { lore.miriam.text('The most important decision we make,') },
+ // () => { lore.miriam.text('is whether we believe we live in a friendly or hostile universe.') },
+ // () => { lore.miriam.text('-Albert Einstein') },
+ // () => {
+ // lore.talkingColor = "#dff";
+ // setTimeout(() => { lore.anand.text("That's profound") }, 1500);
+ // },
+ // () => { lore.anand.text("Of course I looked it up, and there is no record of him saying that.") },
+ // () => { lore.miriam.text("Oh") },
+ // () => { lore.miriam.text("Well") },
+ // () => { lore.miriam.text("It doesn't matter who said it.") },
+ // () => { lore.anand.text("The point is we think the project views the universe as hostile.") },
+ // () => { lore.miriam.text("We think a part of you see the universe as hostile.") },
+ // () => { lore.miriam.text("And that is why you keep running these fighting simulations.") },
+ // () => { lore.miriam.text("You haven't been researching new technology.") },
+ // () => { lore.miriam.text("You've are planning how to escape.") },
+
+
unlockTesting() {
if (localSettings.loreCount < 1) localSettings.loreCount = 1
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
@@ -318,29 +479,9 @@ const lore = {
document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
simulation.makeTextLog(`lore.unlockTesting()`, Infinity);
- //setup audio context
- function tone(frequency, gain = 0.05, end = 1300) {
- const audioCtx = new(window.AudioContext || window.webkitAudioContext)();
- const oscillator1 = audioCtx.createOscillator();
- const gainNode1 = audioCtx.createGain();
- gainNode1.gain.value = gain; //controls volume
- oscillator1.connect(gainNode1);
- gainNode1.connect(audioCtx.destination);
- oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
- oscillator1.frequency.value = frequency; // value in hertz
- oscillator1.start();
- for (let i = 0, len = end * 0.1; i < len; i++) {
- oscillator1.frequency.setValueAtTime(frequency + i * 10, audioCtx.currentTime + i * 0.01);
- }
- setTimeout(() => {
- audioCtx.suspend()
- audioCtx.close()
- }, end)
- return audioCtx
- }
- tone(50)
- tone(83.333)
- tone(166.666)
+ sound.portamento(50)
+ sound.portamento(83.333)
+ sound.portamento(166.666)
},
}
diff --git a/js/mob.js b/js/mob.js
index 1a81bf8..4141a69 100644
--- a/js/mob.js
+++ b/js/mob.js
@@ -226,6 +226,7 @@ const mobs = {
alive: true,
index: i,
health: tech.mobSpawnWithHealth,
+ damageReduction: 1,
showHealthBar: true,
accelMag: 0.001 * simulation.accelScale,
cd: 0, //game cycle when cooldown will be over
@@ -1015,12 +1016,12 @@ const mobs = {
dmg *= tech.damageFromTech()
//mobs specific damage changes
if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 50% dmg at max range of 3500
- if (this.shield) dmg *= 0.075
- if (this.isBoss) dmg *= 0.25
+ // if (this.shield) dmg *= 0.075
+ // if (this.isBoss) dmg *= 0.25
+ dmg *= this.damageReduction
//energy and heal drain should be calculated after damage boosts
if (tech.energySiphon && dmg !== Infinity && this.isDropPowerUp && m.immuneCycle < m.cycle) m.energy += Math.min(this.health, dmg) * tech.energySiphon
-
if (tech.healthDrain && dmg !== Infinity && this.isDropPowerUp) {
m.addHealth(Math.min(this.health, dmg) * tech.healthDrain)
if (m.health > m.maxHealth) m.health = m.maxHealth
diff --git a/js/player.js b/js/player.js
index d4ad8c1..39ec651 100644
--- a/js/player.js
+++ b/js/player.js
@@ -516,7 +516,7 @@ const m = {
const immunityCycle = m.cycle + 90
if (m.immuneCycle < immunityCycle) m.immuneCycle = immunityCycle; //player is immune to damage until after grenades might explode...
- for (let i = 1, len = Math.floor(2 + steps / 40); i < len; i++) {
+ for (let i = 1, len = Math.floor(4 + steps / 40); i < len; i++) {
b.grenade(Vector.add(m.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -i * Math.PI / len) //fire different angles for each grenade
const who = bullet[bullet.length - 1]
if (tech.isVacuumBomb) {
@@ -525,7 +525,7 @@ const m = {
y: who.velocity.y * 0.5
});
} else if (tech.isRPG) {
- who.endCycle = (who.endCycle - simulation.cycle) * 0.2 + simulation.cycle
+ who.endCycle = (who.endCycle - simulation.cycle) * 0.2 + simulation.cycle + 10 * Math.random()
} else if (tech.isNeutronBomb) {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.3,
@@ -536,7 +536,7 @@ const m = {
x: who.velocity.x * 0.5,
y: who.velocity.y * 0.5
});
- who.endCycle = (who.endCycle - simulation.cycle) * 0.5 + simulation.cycle
+ who.endCycle = (who.endCycle - simulation.cycle) * 0.5 + simulation.cycle + 10 * Math.random()
}
}
}
@@ -1815,14 +1815,15 @@ const m = {
if (m.energy > m.maxEnergy - 0.02 && m.fieldCDcycle < m.cycle && !input.field && bullet.length < 150 && (m.cycle % 2)) {
if (tech.isSporeField) {
if (tech.isSporeWorm) {
- for (let i = 0, len = Math.random() * 20; i < len; i++) {
+ if (m.energy > 0.15) {
m.energy -= 0.15
- if (m.energy > 0) {
- b.worm(m.pos)
- } else {
- m.energy = 0.001
- break;
- }
+ b.worm({ x: m.pos.x + 35 * Math.cos(m.angle), y: m.pos.y + 35 * Math.sin(m.angle) })
+ const SPEED = 2 + 1 * Math.random();
+ Matter.Body.setVelocity(bullet[bullet.length - 1], {
+ x: SPEED * Math.cos(m.angle),
+ y: SPEED * Math.sin(m.angle)
+ });
+
}
} else {
for (let i = 0, len = Math.random() * 20; i < len; i++) {
@@ -2603,11 +2604,19 @@ const m = {
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
- b.spore(Vector.add(m.hole.pos2, Vector.rotate({
- x: m.fieldRange * 0.4,
- y: 0
- }, 2 * Math.PI * Math.random())))
- Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -15));
+ if (tech.isSporeWorm) {
+ b.worm(Vector.add(m.hole.pos2, Vector.rotate({
+ x: m.fieldRange * 0.4,
+ y: 0
+ }, 2 * Math.PI * Math.random())))
+ Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -5));
+ } else {
+ b.spore(Vector.add(m.hole.pos2, Vector.rotate({
+ x: m.fieldRange * 0.4,
+ y: 0
+ }, 2 * Math.PI * Math.random())))
+ Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -15));
+ }
}
}
break
@@ -2629,11 +2638,19 @@ const m = {
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
- b.spore(Vector.add(m.hole.pos1, Vector.rotate({
- x: m.fieldRange * 0.4,
- y: 0
- }, 2 * Math.PI * Math.random())))
- Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 15));
+ if (tech.isSporeWorm) {
+ b.worm(Vector.add(m.hole.pos1, Vector.rotate({
+ x: m.fieldRange * 0.4,
+ y: 0
+ }, 2 * Math.PI * Math.random())))
+ Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 5));
+ } else {
+ b.spore(Vector.add(m.hole.pos1, Vector.rotate({
+ x: m.fieldRange * 0.4,
+ y: 0
+ }, 2 * Math.PI * Math.random())))
+ Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 15));
+ }
}
}
break
diff --git a/js/powerup.js b/js/powerup.js
index fe7eac6..d665995 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -82,7 +82,7 @@ const powerUps = {
//remove power ups after 3 seconds
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (powerUp[i].isDuplicated && Math.random() < 0.004) { // (1-0.004)^150 = chance to be removed after 3 seconds
- b.explosion(powerUp[i].position, (10 + 3 * Math.random()) * powerUp[i].size);
+ b.explosion(powerUp[i].position, 150 + (10 + 3 * Math.random()) * powerUp[i].size);
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break
@@ -239,7 +239,7 @@ const powerUps = {
if (tech.renormalization) {
for (let i = 0; i < cost; i++) {
if (Math.random() < 0.4) {
- m.fieldCDcycle = m.cycle + 30;
+ m.fieldCDcycle = m.cycle + 20;
powerUps.spawn(m.pos.x, m.pos.y, "research");
}
}
@@ -783,11 +783,9 @@ const powerUps = {
//bonus power ups for clearing runs in the 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
- simulation.makeTextLog(`for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++)`);
- simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") //simulation superposition }`);
- }
+ 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
+ simulation.makeTextLog(`for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++)`);
+ simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") //simulation superposition}`);
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 c2d3660..a0973dd 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -94,7 +94,7 @@ const spawn = {
} else if (tech.isResearchBoss) {
if (powerUps.research.count > 3) {
powerUps.research.changeRerolls(-4)
- simulation.makeTextLog(`m.research -= 5
${powerUps.research.count}`)
+ simulation.makeTextLog(`m.research -= 4
${powerUps.research.count}`)
} else {
tech.addJunkTechToPool(49)
}
@@ -254,6 +254,8 @@ const spawn = {
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
+ me.damageReduction = 0.25;
+ me.damageReduction = 0.25;
me.frictionAir = 0.01;
me.memory = Infinity;
me.hasRunDeathScript = false
@@ -722,6 +724,7 @@ const spawn = {
let me = mob[mob.length - 1];
me.stroke = "transparent"
me.isBoss = true;
+ me.damageReduction = 0.25;
me.isCell = true;
me.cellID = cellID
me.accelMag = 0.00016 * simulation.accelScale;
@@ -799,6 +802,7 @@ const spawn = {
mobs.spawn(x + Math.random(), y + Math.random(), 4, radius, "rgba(255,60,0,0.3)") //);
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.isSpawnBoss = true;
me.spawnID = spawnID
me.accelMag = 0.0002 * simulation.accelScale;
@@ -887,6 +891,7 @@ const spawn = {
mobs.spawn(x, y, vertices, radius, "transparent");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.frictionAir = 0.01
me.seeAtDistance2 = 1000000;
me.accelMag = 0.0005 * simulation.accelScale;
@@ -1068,6 +1073,7 @@ const spawn = {
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.g = 0.005; //required if using 'gravity'
me.frictionAir = 0.01;
me.friction = 1
@@ -1285,6 +1291,7 @@ const spawn = {
mobs.spawn(x, y, 12, radius, "#000");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.stroke = "transparent"; //used for drawSneaker
me.eventHorizon = 1100; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon
@@ -1396,6 +1403,7 @@ const spawn = {
let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.0035); //extra dense //normal is 0.001 //makes effective life much larger
me.isBoss = true;
+ me.damageReduction = 0.25;
targets.push(me.id) //add to shield protection
me.friction = 0;
me.frictionAir = 0.0065;
@@ -1479,7 +1487,7 @@ const spawn = {
// timeSkipBoss(x, y, radius = 55) {
// mobs.spawn(x, y, 6, radius, '#000');
// let me = mob[mob.length - 1];
- // me.isBoss = true;
+ // me.isBoss = true; me.damageReduction = 0.25;
// // me.stroke = "transparent"; //used for drawSneaker
// me.timeSkipLastCycle = 0
// me.eventHorizon = 1800; //required for black hole
@@ -1586,6 +1594,7 @@ const spawn = {
me.laserRange = 300;
me.seeAtDistance2 = 2000000;
me.isBoss = true;
+ me.damageReduction = 0.25;
me.showHealthBar = false; //drawn in this.awake
me.delayLimit = 60 + Math.floor(30 * Math.random());
me.followDelay = 600 - Math.floor(60 * Math.random())
@@ -1749,6 +1758,7 @@ const spawn = {
mobs.spawn(x, y, 3, radius, color);
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
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.00018 * Math.sqrt(simulation.accelScale);
@@ -1913,6 +1923,7 @@ const spawn = {
me.isFiring = false
Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
me.isBoss = true;
+ me.damageReduction = 0.25;
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 200 + 300 * Math.random(), 1)
me.onDeath = function() {
@@ -2165,6 +2176,7 @@ const spawn = {
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
+ me.damageReduction = 0.25;
// me.startingPosition = {
// x: x,
// y: y
@@ -2589,6 +2601,7 @@ const spawn = {
mobs.spawn(x, y, 3, radius, "rgba(255,0,200,0.5)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
Matter.Body.setDensity(me, 0.002 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.stroke = "transparent"; //used for drawGhost
@@ -2677,6 +2690,7 @@ const spawn = {
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
+ me.damageReduction = 0.25;
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
me.isVerticesChange = true
me.memory = 240;
@@ -2965,6 +2979,7 @@ const spawn = {
mobs.spawn(x, y, 6, radius, "rgb(150,150,255)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.accelMag = 0.00008 * simulation.accelScale;
me.fireFreq = Math.floor(360 * simulation.CDScale)
me.frictionStatic = 0;
@@ -3005,6 +3020,7 @@ const spawn = {
mobs.spawn(x, y, 6, radius, "rgb(215,80,190)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.accelMag = 0.0001 * simulation.accelScale;
me.fireFreq = Math.floor(360 * simulation.CDScale)
me.frictionStatic = 0;
@@ -3194,6 +3210,7 @@ const spawn = {
Matter.Body.rotate(me, Math.random() * 2 * Math.PI)
// me.stroke = "rgb(220,220,255)"
me.isBoss = true;
+ me.damageReduction = 0.25;
me.cycle = 0
me.maxCycles = 120;
me.frictionStatic = 0;
@@ -3249,6 +3266,7 @@ const spawn = {
mobs.spawn(x, y, 5, radius, "rgb(245,180,255)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
// me.accelMag = 0.00023 * simulation.accelScale;
me.accelMag = 0.00008 * simulation.accelScale;
// me.fireFreq = Math.floor(30 * simulation.CDScale)
@@ -3462,6 +3480,7 @@ const spawn = {
mobs.spawn(x, y, 8, radius, "rgb(55,170,170)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.accelMag = 0.00075 * simulation.accelScale;
me.memory = 250;
me.laserRange = 500;
@@ -3547,6 +3566,7 @@ const spawn = {
mobs.spawn(x, y, 8, radius, "rgb(0,60,80)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
me.g = 0.0001; //required if using 'gravity'
me.accelMag = 0.002 * simulation.accelScale;
me.memory = 20;
@@ -3582,6 +3602,7 @@ const spawn = {
me.stroke = "rgb(220,220,255)";
Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
me.shield = true;
+ me.damageReduction = 0.075
me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo
me.collisionFilter.category = cat.mobShield
me.collisionFilter.mask = cat.bullet;
@@ -3629,6 +3650,7 @@ const spawn = {
Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
me.frictionAir = 0;
me.shield = true;
+ me.damageReduction = 0.075
me.collisionFilter.category = cat.mobShield
me.collisionFilter.mask = cat.bullet;
for (let i = 0; i < nodes; ++i) {
@@ -3720,6 +3742,7 @@ const spawn = {
mobs.spawn(x, y, nodes, radius, "rgb(255,0,150)");
let me = mob[mob.length - 1];
me.isBoss = true;
+ me.damageReduction = 0.25;
Matter.Body.setDensity(me, 0.002 + 0.00015 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.stroke = "transparent"; //used for drawGhost
diff --git a/js/tech.js b/js/tech.js
index d2ca482..68dd7af 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -125,14 +125,19 @@
}
},
setCheating() {
- simulation.isCheating = true;
- level.levelAnnounce();
- lore.techCount = 0;
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isLore) {
- tech.tech[i].frequency = 0;
- tech.tech[i].count = 0;
+ if (!simulation.isCheating) {
+ simulation.isCheating = true;
+ level.levelAnnounce();
+ lore.techCount = 0;
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isLore) {
+ tech.tech[i].frequency = 0;
+ tech.tech[i].count = 0;
+ }
}
+ sound.tone(250)
+ sound.tone(300)
+ sound.tone(375)
}
},
haveGunCheck(name) {
@@ -182,7 +187,7 @@
maxDuplicationEvent() {
if (tech.is100Duplicate && tech.duplicationChance() > 0.99) {
tech.is100Duplicate = false
- const range = 1000
+ const range = 700
const bossOptions = ["historyBoss", "cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture"]
spawn.randomLevelBoss(m.pos.x + range, m.pos.y, bossOptions);
spawn.randomLevelBoss(m.pos.x, m.pos.y + range, bossOptions);
@@ -1529,7 +1534,7 @@
allowed() {
return (tech.throwChargeRate > 1 || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isBlockExplosion
},
- requires: "mass driver or pilot wave not tokamak",
+ requires: "mass driver or pilot wave, not tokamak",
effect() {
tech.isBlockBullets = true
},
@@ -1871,8 +1876,8 @@
description: `freeze all mobs for 7 seconds
after receiving harm`,
maxCount: 1,
count: 0,
- frequency: 4,
- frequencyDefault: 4,
+ frequency: 3,
+ frequencyDefault: 3,
allowed() {
return tech.isSlowFPS
},
@@ -1889,8 +1894,8 @@
description: `slow time by 50% after receiving harm
reduce harm by 20%`,
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
return simulation.fpsCapDefault > 45
},
@@ -2005,6 +2010,7 @@
maxCount: 3,
count: 0,
frequency: 2,
+ frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.isRewindAvoidDeath
@@ -2025,9 +2031,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return !tech.isExplosionHarm && tech.isRewindAvoidDeath
+ return tech.isRewindAvoidDeath
},
- requires: "CPT, not acetone peroxide",
+ requires: "CPT",
effect() {
tech.isRewindGrenade = true;
},
@@ -2040,12 +2046,12 @@
description: "colliding with mobs gives you 2048 energy", //
reduce harm by 15%
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
- return !tech.isEnergyHealth && (m.harmReduction() < 1 || tech.isFlipFlopHarm)
+ return !tech.isEnergyHealth
},
- requires: "not mass-energy, some harm reduction",
+ requires: "not mass-energy",
effect() {
tech.isPiezo = true;
m.energy += 20.48;
@@ -2175,9 +2181,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return m.maxEnergy > 1 || tech.isEnergyRecovery || tech.isPiezo || tech.energySiphon > 0 || tech.isBlockExplosion
+ return true //m.maxEnergy > 1 || tech.isEnergyRecovery || tech.isPiezo || tech.energySiphon > 0 || tech.isBlockExplosion
},
- requires: "increased energy regen or max energy",
+ requires: "", //"increased energy regen or max energy",
effect: () => {
tech.isEnergyDamage = true
},
@@ -2190,12 +2196,12 @@
description: `increase damage by 60%, but
ammo will no longer spawn`,
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
- return (tech.haveGunCheck("nail gun") && tech.isIceCrystals) || tech.haveGunCheck("laser") || m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
+ return true //(tech.haveGunCheck("nail gun") && tech.isIceCrystals) || tech.haveGunCheck("laser") || m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
- requires: "energy based damage",
+ requires: "", //"energy based damage",
effect() {
tech.isEnergyNoAmmo = true;
},
@@ -2249,7 +2255,7 @@
frequency: 4,
frequencyDefault: 4,
allowed() {
- return tech.isEnergyLoss && m.maxEnergy < 1.1
+ return tech.isEnergyLoss && m.maxEnergy < 1.01
},
requires: "exothermic process, not max energy increase",
effect() {
@@ -2271,7 +2277,7 @@
},
requires: "",
effect() {
- tech.bonusEnergy += 0.5
+ tech.bonusEnergy += 0.6
m.setMaxEnergy()
tech.addJunkTechToPool(10)
},
@@ -2306,12 +2312,12 @@
description: "6% of damage done recovered as energy",
maxCount: 9,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
- return tech.damageFromTech() > 1
+ return true
},
- requires: "some increased damage",
+ requires: "",
effect() {
tech.energySiphon += 0.06;
},
@@ -2327,9 +2333,9 @@
frequency: 1,
frequencyDefault: 1,
allowed() {
- return m.maxEnergy > 0.99
+ return true
},
- requires: "max energy >= 1",
+ requires: "",
effect() {
tech.isEnergyRecovery = true;
},
@@ -2361,8 +2367,8 @@
description: "if a mob has died in the last 5 seconds
increase damage by 99% else decrease it by 33%",
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
return true
},
@@ -2379,8 +2385,8 @@
description: "if a mob has died in the last 5 seconds
reduce harm by 66% else increase it by 15%",
maxCount: 1,
count: 0,
- frequency: 4,
- frequencyDefault: 4,
+ frequency: 3,
+ frequencyDefault: 3,
allowed() {
return tech.isDamageAfterKill && !tech.isEnergyHealth
},
@@ -2400,9 +2406,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return m.health < 0.5 || build.isExperimentSelection
+ return m.health < 0.6 || build.isExperimentSelection
},
- requires: "health below 50",
+ requires: "health below 60",
effect() {
tech.isLowHealthDmg = true; //used in mob.damage()
},
@@ -2415,12 +2421,12 @@
description: "increase damage by 90%
lose 11 health when you pick up a tech",
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
- return (m.harmReduction() < 1 || tech.healthDrain || tech.isLowHealthDmg || tech.isHealthRecovery || tech.isHealLowHealth || tech.largerHeals > 1) && !tech.isEnergyHealth
+ return !tech.isEnergyHealth
},
- requires: "negative feedback or extra healing tech or harm reduction, not mass-energy",
+ requires: "not mass-energy",
effect() {
tech.isTechDamage = true;
},
@@ -2434,11 +2440,12 @@
maxCount: 9,
count: 0,
frequency: 2,
+ frequencyDefault: 2,
isHealTech: true,
allowed() {
- return !tech.isEnergyHealth && tech.damageFromTech() > 1 && !tech.isNoHeals
+ return !tech.isEnergyHealth && !tech.isNoHeals
},
- requires: "some increased damage, not mass-energy equivalence, ergodicity",
+ requires: "not mass-energy equivalence, ergodicity",
effect() {
tech.healthDrain += 0.03;
},
@@ -2464,27 +2471,6 @@
tech.isAcidDmg = false;
}
},
- // {
- // name: "supersaturation",
- // description: "increase your maximum health by 50",
- // maxCount: 9,
- // count: 0,
- // frequency: 1,
- // frequencyDefault: 1,
- // allowed() {
- // return !tech.isEnergyHealth && !tech.isNoHeals
- // },
- // requires: "not mass-energy equivalence, ergodicity",
- // effect() {
- // tech.bonusHealth += 0.5
- // m.setMaxHealth();
- // m.addHealth(0.50)
- // },
- // remove() {
- // tech.bonusHealth = 0
- // m.setMaxHealth();
- // }
- // },
{
name: "tungsten carbide",
description: "increase your maximum health by 100
landings that force you to crouch cause harm",
@@ -2617,8 +2603,8 @@
description: "after anthropic principle prevents your death
increase damage by 137.03599% on that level",
maxCount: 1,
count: 0,
- frequency: 4,
- frequencyDefault: 4,
+ frequency: 3,
+ frequencyDefault: 3,
allowed() {
return tech.isDeathAvoid
},
@@ -2635,8 +2621,8 @@
description: "reduce harm by 33%
after dying, continue in an alternate reality",
maxCount: 1,
count: 0,
- frequency: 4,
- frequencyDefault: 4,
+ frequency: 3,
+ frequencyDefault: 3,
allowed() {
return tech.isDeathAvoid
},
@@ -2656,9 +2642,9 @@
frequency: 1,
frequencyDefault: 1,
allowed() {
- return !tech.isResearchReality && level.onLevel < 6 && !tech.isCollisionRealitySwitch
+ return !tech.isResearchReality && !tech.isCollisionRealitySwitch
},
- requires: "before level 6, Ψ(t) collapse, non-unitary",
+ requires: "not Ψ(t) collapse, non-unitary",
effect() {
tech.isSwitchReality = true;
},
@@ -2735,9 +2721,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return (powerUps.research.count > 3 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste
+ return (powerUps.research.count > 2 || build.isExperimentSelection) && !tech.isSuperDeterminism
},
- requires: "not superdeterminism or Ψ(t) collapse
at least 4 research",
+ requires: "at least 3 research and not superdeterminism",
effect() {
tech.renormalization = true;
},
@@ -2750,12 +2736,12 @@
description: "66% decreased delay after firing
when you have no research in your inventory",
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
- return powerUps.research.count === 0 && !tech.isAnsatz
+ return powerUps.research.count === 0
},
- requires: "no research, not ansatz",
+ requires: "no research",
effect() {
tech.isRerollHaste = true;
tech.researchHaste = 0.33;
@@ -2775,9 +2761,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return powerUps.research.count === 0 && !tech.isSuperDeterminism && !tech.isRerollHaste
+ return powerUps.research.count === 0 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality
},
- requires: "not superdeterminism or Ψ(t) collapse, no research, perturbation theory",
+ requires: "no research, not superdeterminism, Ψ(t) collapse, perturbation theory",
effect: () => {
tech.isAnsatz = true;
},
@@ -3051,12 +3037,12 @@
description: "after reaching 100% duplication chance
immediately spawn 8 bosses",
maxCount: 1,
count: 0,
- frequency: 6,
- frequencyDefault: 6,
+ frequency: 4,
+ frequencyDefault: 4,
allowed() {
- return tech.duplicationChance() > 0.66
+ return tech.duplicationChance() > 0.6
},
- requires: "duplication chance above 66%",
+ requires: "duplication chance above 60%",
effect() {
tech.is100Duplicate = true;
tech.maxDuplicationEvent()
@@ -3077,7 +3063,7 @@
allowed() {
return (tech.totalCount > 3) && !tech.isSuperDeterminism
},
- requires: "at least 4 tech, not super determinism",
+ requires: "at least 4 tech, not superdeterminism",
effect: () => {
const have = [] //find which tech you have
for (let i = 0; i < tech.tech.length; i++) {
@@ -3109,7 +3095,7 @@
allowed() {
return (tech.totalCount > 3) && !tech.isSuperDeterminism && tech.duplicationChance() > 0
},
- requires: "at least 4 tech, a chance to duplicate power ups",
+ requires: "at least 4 tech, a chance to duplicate power ups, not superdeterminism",
effect: () => {
const removeTotal = powerUps.removeRandomTech()
for (let i = 0; i < removeTotal + 1; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
@@ -3186,7 +3172,7 @@
},
{
name: "reinforcement learning",
- description: "increase the frequency of finding copies of
recursive tech you already have by 10000%",
+ description: "increase the frequency of finding copies of
recursive tech you already have by 1000%",
maxCount: 1,
count: 0,
frequency: 1,
@@ -3197,12 +3183,12 @@
requires: "at least 10 tech",
effect: () => {
for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].count > 0) tech.tech[i].frequency *= 100
+ if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10
}
},
remove() {
for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 100
+ if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 10
}
}
},
@@ -3729,7 +3715,7 @@
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isSlugShot
},
- requires: "shotgun, not slug",
+ requires: "shotgun, not slug, incendiary",
effect() {
tech.isNailShot = true;
},
@@ -3824,7 +3810,7 @@
allowed() {
return tech.haveGunCheck("super balls") && !tech.oneSuperBall
},
- requires: "super balls, but not the tech super ball or super duper",
+ requires: "super balls, but not the tech super ball",
effect() {
tech.superBallDelay = true
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -3851,7 +3837,7 @@
allowed() {
return tech.haveGunCheck("super balls") && tech.superBallNumber === 3 && !tech.superBallDelay
},
- requires: "super balls, but not super duper or super queue",
+ requires: "super balls, but not super duper or supertemporal",
effect() {
tech.oneSuperBall = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -3991,15 +3977,16 @@
}
},
remove() {
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "wave beam") {
- b.guns[i].chooseFireMethod()
- if (tech.isLongitudinal) {
+ if (tech.isLongitudinal) {
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "wave beam") {
+ tech.isLongitudinal = false;
+ b.guns[i].chooseFireMethod()
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 8);
simulation.updateGunHUD();
+ break
}
- break
}
}
tech.isLongitudinal = false;
@@ -4337,14 +4324,14 @@
},
{
name: "nematodes",
- description: "replace spores with 50% fewer worms
worms do 200% more damage",
+ description: "spores develop into 1/2 as many worms
worms do 200% more damage",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
- return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormSpores
},
requires: "spores",
effect() {
@@ -4471,7 +4458,7 @@
allowed() {
return tech.haveGunCheck("drones") && !tech.isDroneRadioactive
},
- requires: "drone gun",
+ requires: "drone gun, not irradiated drones",
effect() {
tech.isDroneTeleport = true
},
@@ -4490,7 +4477,7 @@
allowed() {
return tech.droneCycleReduction === 1 && !tech.isIncendiary && !tech.isDroneTeleport && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)))
},
- requires: "drone gun, not reduced tolerances or incendiary",
+ requires: "drones, not reduced tolerances, incendiary, torque bursts",
effect() {
tech.isDroneRadioactive = true
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -4601,7 +4588,7 @@
allowed() {
return tech.haveGunCheck("foam")
},
- requires: "foam",
+ requires: "foam gun",
effect() {
tech.foamFutureFire++
},
@@ -4620,7 +4607,7 @@
allowed() {
return tech.haveGunCheck("foam")
},
- requires: "foam",
+ requires: "foam gun",
effect() {
tech.isAmmoFoamSize = true
},
@@ -4801,7 +4788,7 @@
allowed() {
return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.isPulseAim && !tech.historyLaser
},
- requires: "laser, not neocognitron, diffuse beam, or slow light",
+ requires: "laser gun, not neocognitron, diffuse beam, or slow light",
effect() {
tech.beamSplitter++
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -4828,7 +4815,7 @@
allowed() {
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isPulseLaser && !tech.historyLaser
},
- requires: "laser, not specular reflection, diffraction grating, slow light, pulse",
+ requires: "laser gun, not specular reflection, diffraction grating, slow light, pulse",
effect() {
if (tech.wideLaser === 0) tech.wideLaser = 3
tech.isWideLaser = true;
@@ -4855,9 +4842,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return tech.haveGunCheck("laser") && tech.isWideLaser
+ return tech.isWideLaser
},
- requires: "laser, diffuse beam",
+ requires: "diffuse beam",
effect() {
tech.wideLaser += 2
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -4886,7 +4873,7 @@
allowed() {
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isWideLaser
},
- requires: "laser, not specular reflection, diffraction grating, diffuse beam",
+ requires: "laser gun, not specular reflection, diffraction grating, diffuse beam",
effect() {
// this.description = `add 5 more laser beams into into your past`
tech.historyLaser++
@@ -4915,7 +4902,7 @@
allowed() {
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.15
},
- requires: "laser, not specular reflection, diffuse, solid-state",
+ requires: "laser gun, not specular reflection, diffuse, free-electron laser",
effect() {
tech.isPulseLaser = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -5310,7 +5297,7 @@
frequency: 3,
frequencyDefault: 3,
allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 2) && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive)
+ return (build.isExperimentSelection || powerUps.research.count > 2) && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
},
requires: "nano-scale manufacturing, no other manufacturing, no drone tech",
effect() {
@@ -5335,7 +5322,7 @@
frequency: 3,
frequencyDefault: 3,
allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 2) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive)
+ return (build.isExperimentSelection || powerUps.research.count > 2) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
},
requires: "nano-scale manufacturing, no other manufacturing, no drone tech",
effect() {
@@ -5360,7 +5347,7 @@
frequency: 3,
frequencyDefault: 3,
allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 2) && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive)
+ return (build.isExperimentSelection || powerUps.research.count > 2) && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
},
requires: "nano-scale manufacturing, no other manufacturing, no drone tech",
effect() {
@@ -5387,7 +5374,7 @@
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
- requires: "nano-scale manufacturing",
+ requires: "nano-scale manufacturing or pilot wave",
effect: () => {
tech.isMassEnergy = true // used in m.grabPowerUp
m.energy += 2
@@ -5717,9 +5704,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole" && (build.isExperimentSelection || powerUps.research.count > 2)
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole" && (build.isExperimentSelection || powerUps.research.count > 2) && tech.duplicationChance() < 1
},
- requires: "wormhole",
+ requires: "wormhole,below 100% duplication chance",
effect() {
tech.wormDuplicate = 0.19
powerUps.setDo(); //needed after adjusting duplication chance
diff --git a/todo.txt b/todo.txt
index 6faa6c1..d07333c 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,14 +1,58 @@
******************************************************** NEXT PATCH ********************************************************
-spore tech - nematodes - replace spores with 1/2 as many worms that do 200% more damage
- worms are also a bit faster, last longer, have better reaction times
- a cool worm graphic, and a simple searching behavior if they haven't found a mob
+2 more lore chapters (5 total now)
+entering testing mode makes a sound now
-mycelial fragmentation - makes 6 extra spores during growth phase (was 4)
+reduced the requirements and frequency for many tech so that they may show up in "less optimal" situations
+ I hope this will increase build variety and also give more value to making good tech choices
+countless bug fixes and wording fixes
-historyBoss has less health, slower tracking, and more damage
+mobs have a new trait mob[i].damageReduction
******************************************************** TODO ********************************************************
+
+
+
+perfect diamagnetism field stays when you aren't holding field
+ good for perfect because it doesn't use energy
+ holding field moves it the player
+
+level with mobs that follow a genetic algorithm
+ mobs have genes
+ the last mob that did damage saves it's genes to local storage
+ new mobs have the saved genes, but with some random mutations
+ mutations need to be balanced to prevent a gene from moving towards infinity
+ total genome must equal 1 (100%)
+ binary genes have a flat cost
+ example: phasing through walls might cost 0.2
+ spectrum genes have a rate
+ example: acceleration cost 0.01 per 0.001
+ possible genes
+ genes should only effect it's ability to touch the player
+ so not damage?
+ genome: spectrum
+ acceleration
+ top speed / air friction
+ damageReduction
+ duration?
+ health decreases naturally?
+ or they just go away like bullets?
+ spawn rate
+ look frequency / memory?
+ genome: binary
+ go through walls
+ blink/teleport (like striker)
+ grow when near target
+ split into two
+ shielded
+ occurs in a specialized level
+ named: gene lab, gene factory, genetic lab, genome facility
+ in the level sequence after lab and before gauntlet?
+ level ends after a period of time
+ exit is hidden until time is up and it appears
+ the level tests player durability/evasion
+ this is a nice contrast to the final level that tests damage output, and the gauntlet which tests AoE damage
+
scrolling console history in pause menu?
also make tech, guns scrolling?
@@ -18,8 +62,6 @@ pause should at least show the last in game console message
make the player get a buff after using wormhole
while energy lasts: drain energy and give damage buff
-Tech: "Induced Oscillation": When using phonon, if a block vibrates after it gets hit from a phonon, it has a chance of oscillating and creating an additional phonon coming from the block. The chance is higher the closer the block is to the source of the oscillation.
-
tech: quantized shields - harmonic standing wave field can only lose 33 energy per hit
draw 1,2,3 levels of the field based on energy?
the blocked value only scales up to 2x or 4x (33 energy) blocked
@@ -186,6 +228,9 @@ n-gon outreach ideas
******************************************************** BUGS ********************************************************
+blocks on buttons teleport into the button endlessly if they are being slowly floated away
+ maybe add a cooldown?
+
ants marching outline doesn't sync right on safari anymore.
door to exit in vats does nothing
@@ -270,6 +315,12 @@ map: observatory
******************************************************** MOBS ********************************************************
+mobs that buff the stats of mobs when they die
+ nearby mobs
+ boss is a group of mobs, they buff each other
+ give the buff a ramp up time
+ so there is an advantage to kill them all at once
+
mob that spawns eggs after they die
eggs don't attack but grow back into a mob after about 10s
@@ -346,6 +397,7 @@ possible names for tech
eternal inflation
hypergraph
gnarl
+ SQUID (for superconducting quantum interference device) is a very sensitive magnetometer used to measure extremely subtle magnetic fields, based on superconducting loops containing Josephson junctions.
a tutorial / lore intro
needs to be optional so it doesn't slow experienced players