lore chapters: 3,4

2 more lore chapters (5 total now)
entering testing mode makes a sound now

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

mobs have a new trait mob[i].damageReduction
This commit is contained in:
landgreen
2021-07-21 07:01:46 -07:00
parent d50cd540fa
commit 34d295cf48
11 changed files with 503 additions and 247 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -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;

View File

@@ -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
//**********************************************************************

View File

@@ -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,

View File

@@ -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(<span style="color:#888; font-size: 70%;">${Date.now()} ms</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, Infinity);
simulation.makeTextLog(`input.audio(<span style="color:#888; font-size: 70%;">${(Date.now()/1000).toFixed(0)} s</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, 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(<span style="color:#888; font-size: 70%;">${Date.now()} ms</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, Infinity);
simulation.makeTextLog(`input.audio(<span style="color:#888; font-size: 70%;">${(Date.now()/1000).toFixed(0)} s</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, 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.”<br>-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 <span class='color-symbol'>=</span> ${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(`<span class='color-var'>lore</span>.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)
},
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 <span class='color-symbol'>=</span> 0; i <span class='color-symbol'><</span> localSettings.levelsClearedLastGame <span class='color-symbol'>/</span> 3; i<span class='color-symbol'>++</span>)`);
simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") <em>//simulation superposition</em>}`);
localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}

View File

@@ -94,7 +94,7 @@ const spawn = {
} else if (tech.isResearchBoss) {
if (powerUps.research.count > 3) {
powerUps.research.changeRerolls(-4)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>-=</span> 5<br>${powerUps.research.count}`)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>-=</span> 4<br>${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

View File

@@ -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: `<strong class='color-s'>freeze</strong> all mobs for <strong>7</strong> seconds<br>after receiving <strong class='color-harm'>harm</strong>`,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.isSlowFPS
},
@@ -1889,8 +1894,8 @@
description: `<strong>slow</strong> <strong>time</strong> by <strong>50%</strong> after receiving <strong class='color-harm'>harm</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>20%</strong>`,
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: "<strong>colliding</strong> with mobs gives you <strong>2048</strong> <strong class='color-f'>energy</strong>", //<br>reduce <strong class='color-harm'>harm</strong> by <strong>15%</strong>
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 <strong class='color-d'>damage</strong> by <strong>60%</strong>, but<br><strong class='color-g'>ammo</strong> will no longer <strong>spawn</strong>`,
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: "<strong>6%</strong> of <strong class='color-d'>damage</strong> done recovered as <strong class='color-f'>energy</strong>",
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 <strong>died</strong> in the last <strong>5 seconds</strong><br><span style = 'font-size:90%;'>increase <strong class='color-d'>damage</strong> by <strong>99%</strong> else decrease it by <strong>33%</strong></span>",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
@@ -2379,8 +2385,8 @@
description: "if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>66%</strong> else increase it by <strong>15%</strong>",
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 <strong class='color-d'>damage</strong> by <strong>90%</strong><br>lose <strong>11</strong> <strong class='color-h'>health</strong> when you pick up a <strong class='color-m'>tech</strong>",
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 <strong>maximum</strong> <strong class='color-h'>health</strong> by <strong>50</strong>",
// 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 <strong>maximum</strong> <strong class='color-h'>health</strong> by <strong>100</strong><br><strong>landings</strong> that force you to crouch cause <strong class='color-harm'>harm</strong>",
@@ -2617,8 +2603,8 @@
description: "after <strong>anthropic principle</strong> prevents your <strong>death</strong><br>increase <strong class='color-d'>damage</strong> by <strong>137.03599%</strong> 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 <strong class='color-harm'>harm</strong> by <strong>33%</strong><br>after <strong>dying</strong>, continue in an <strong class='alt'>alternate reality</strong>",
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<br>at least 4 research",
requires: "at least 3 research and not superdeterminism",
effect() {
tech.renormalization = true;
},
@@ -2750,12 +2736,12 @@
description: "<strong>66%</strong> decreased <strong><em>delay</em></strong> after firing<br>when you have no <strong class='color-r'>research</strong> 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 <strong>100%</strong> <strong class='color-dup'>duplication</strong> chance<br>immediately spawn <strong>8 bosses</strong>",
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 <strong class='flicker'>frequency</strong> of finding copies of<br>recursive <strong class='color-m'>tech</strong> you already have by <strong>10000%</strong>",
description: "increase the <strong class='flicker'>frequency</strong> of finding copies of<br>recursive <strong class='color-m'>tech</strong> you already have by <strong>1000%</strong>",
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 <strong class='color-p' style='letter-spacing: 2px;'>spores</strong> with <strong>50%</strong> fewer <strong class='color-p'>worms</strong><br><strong class='color-p'>worms</strong> do <strong>200%</strong> more <strong class='color-d'>damage</strong>",
description: "<strong class='color-p' style='letter-spacing: 2px;'>spores</strong> develop into <strong>1/2</strong> as many <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br><strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> do <strong>200%</strong> more <strong class='color-d'>damage</strong>",
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 <strong>laser</strong> 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

View File

@@ -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