diff --git a/.DS_Store b/.DS_Store
index 6765ade..0329207 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index 188e6d1..ebc6b79 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -2074,7 +2074,7 @@ const b = {
const who = b.guns[b.activeGun]
if (who.name === "drones" && who.ammo > 0 && mob.length) {
b.drone({ x: this.position.x, y: this.position.y }, 0)
- if (Math.random() < 0.33) {
+ if (Math.random() < 0.25) {
b.guns[b.activeGun].ammo--;
simulation.updateGunHUD();
}
@@ -2213,7 +2213,7 @@ const b = {
const me = bullet.length;
const THRUST = tech.isFastDrones ? 0.002 : 0.0012 + 0.0004 * (Math.random() - 0.5)
const dir = m.angle + 0.4 * (Math.random() - 0.5);
- const RADIUS = (4 + 1 * Math.random())
+ const RADIUS = 3
bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, {
angle: dir,
inertia: Infinity,
@@ -2235,7 +2235,7 @@ const b = {
deathCycles: 110 + RADIUS * 5,
isImproved: false,
radioRadius: 0,
- maxRadioRadius: 365 + Math.floor(150 * Math.random()),
+ maxRadioRadius: 355 + Math.floor(150 * Math.random()),
beforeDmg(who) {
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) //move away from target after hitting
Matter.Body.setVelocity(this, {
@@ -2253,7 +2253,7 @@ const b = {
const who = b.guns[b.activeGun]
if (who.name === "drones" && who.ammo > 0 && mob.length) {
b.droneRadioactive({ x: this.position.x, y: this.position.y }, 0)
- if (Math.random() < 0.33) {
+ if (Math.random() < 0.25) {
b.guns[b.activeGun].ammo--;
simulation.updateGunHUD();
}
@@ -2276,7 +2276,7 @@ const b = {
//aoe damage to mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.radioRadius + mob[i].radius) {
- let dmg = b.dmgScale * 0.055 * tech.droneRadioDamage //neutron bombs dmg = 0.09
+ let dmg = b.dmgScale * 0.06 * tech.droneRadioDamage //neutron bombs dmg = 0.09
if (Matter.Query.ray(map, mob[i].position, this.position).length > 0) dmg *= 0.25 //reduce damage if a wall is in the way
if (mob[i].shield) dmg *= 3 // to make up for the /5 that shields normally take
mob[i].damage(dmg);
diff --git a/js/level.js b/js/level.js
index 367a7be..793c54b 100644
--- a/js/level.js
+++ b/js/level.js
@@ -2244,10 +2244,12 @@ const level = {
spawn.mapRect(6700, -1800, 800, 2600); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
- spawn.starter(1900, -500, 200) //big boy
- // spawn.grower(1900, -500)
+ // spawn.starter(1900, -500, 200) //big boy
+ // spawn.pulseShooter(1900, -500)
// spawn.pulsarBoss(1900, -500)
- // spawn.shooterBoss(1900, -500)
+ spawn.grenadierBoss(1900, -500)
+
+ spawn.shieldingBoss(1900, -500)
// spawn.historyBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
// spawn.hopper(1600, -500)
@@ -2261,7 +2263,7 @@ const level = {
// spawn.laser(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1);
- // spawn.nodeGroup(1200, -500, "pulsar")
+ // spawn.nodeGroup(1200, -500, "grenadier")
// spawn.snakeBoss(1200, -500)
// spawn.suckerBoss(2900, -500)
// spawn.randomMob(1600, -500)
diff --git a/js/lore.js b/js/lore.js
index 10bf67a..7c59b58 100644
--- a/js/lore.js
+++ b/js/lore.js
@@ -49,22 +49,23 @@ const lore = {
// option.setAttribute('data-name', voices[i].name);
// voiceSelect.appendChild(option);
// }
- setVoices() {
- window.speechSynthesis.onvoiceschanged = () => {
- const synth = window.speechSynthesis
- console.log(synth.getVoices())
- const voiceArray = synth.getVoices()
- lore.anand.voice = voiceArray[0]
- lore.miriam.voice = voiceArray[1]
- console.log(voiceArray[0], voiceArray[1])
- };
- // console.log('before')
- // if ('speechSynthesis' in window) {
+ // setVoices() {
+ // window.speechSynthesis.onvoiceschanged = () => {
+ // const synth = window.speechSynthesis
+ // console.log(synth.getVoices())
+ // const voiceArray = synth.getVoices()
+ // lore.anand.voice = voiceArray[0]
+ // lore.miriam.voice = voiceArray[1]
+ // console.log(voiceArray[0], voiceArray[1])
+ // };
+ // // console.log('before')
+ // // if ('speechSynthesis' in window) {
- // } else {
- // console.log('Text-to-speech not supported.');
- // }
- },
+ // // } else {
+ // // console.log('Text-to-speech not supported.');
+ // // }
+ // },
+ rate: 1, // //utterance.rate = 1; // 0.1 to 10
anand: {
color: "#e0c",
voice: undefined,
@@ -76,7 +77,7 @@ const lore = {
// utterance.voice = lore.anand.voice
utterance.lang = "en-GB" //"en-IN"; //de-DE en-GB fr-FR en-US en-AU
utterance.volume = 0.2; // 0 to 1
- // utterance.rate = 1.5
+ // if (lore.rate !== 1) utterance.rate = lore.rate
speechSynthesis.speak(utterance);
utterance.onerror = (event) => { //if speech doesn't work try again without the lang set
console.log("speech error", event.error)
@@ -105,7 +106,7 @@ const lore = {
// utterance.voice = lore.anand.voice
utterance.lang = "en-AU";
utterance.volume = 0.2; // 0 to 1
- // utterance.rate = 1.5
+ // if (lore.rate !== 1) utterance.rate = lore.rate
speechSynthesis.speak(utterance);
utterance.onerror = (event) => { //if speech doesn't work try again without the lang set
console.log("speech error", event.error)
@@ -124,6 +125,12 @@ const lore = {
}
},
},
+
+ // utterance.onerror = (event) => { //if speech is still not working, just do text
+ // console.log("speech error", event.error)
+ // lore.sentence++
+ // if (m.alive) lore.conversation[lore.chapter][lore.sentence]() //go to next sentence in the chapter and play it
+ // }
// setTimeout(() => {}, 2000);
// lore.miriam.text("")
// lore.miriam.utterance.addEventListener('end', () => {
@@ -132,27 +139,22 @@ const lore = {
sentence: 0, //what part of the conversation is playing
conversation: [
[ //first time they meet, and testing gets unlocked
- () => {
- // lore.setVoices();
- setTimeout(() => {
- lore.miriam.text("I've never seen it generate this level before.")
- }, 5000);
- },
+ () => { 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...") },
() => { lore.anand.text("Weird") },
() => { lore.anand.text("Maybe it's trapped.") },
+ () => { lore.miriam.text("Looks like testing mode is locked.") },
+ () => { lore.miriam.text("I'll unlock it with the console command.") },
() => {
- lore.miriam.text("Hey little bot! Just press 'T' to enter testing mode and 'U' to go to the next level.")
lore.unlockTesting();
+ setTimeout(() => { lore.miriam.text("Hey little bot! Just press 'T' to enter testing mode and 'U' to go to the next level.") }, 1000);
},
- () => { lore.anand.text("I don't think it's connected to the audio input, and I'm sure it can't understand what you're saying.") },
+ () => { lore.anand.text("It can't process what you're saying.") },
() => { lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.") },
() => {
lore.talkingColor = "#dff"
- setTimeout(() => {
- lore.miriam.text("Poor thing... I hope it figures out how to escape.")
- }, 25000);
+ setTimeout(() => { lore.miriam.text("Poor thing... I hope it figures out how to escape.") }, 25000);
},
() => { lore.talkingColor = "#dff" },
],
@@ -202,326 +204,203 @@ const lore = {
[ //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 is back on the communication level!") },
- () => { lore.miriam.text("Oh good, I've got so many questions.") },
- () => { lore.miriam.text("Is it self aware?") },
- () => { lore.miriam.text("How did it learn to understand words?") },
- () => { lore.miriam.text("Why can it only hear what we are saying on this level?") },
- () => { lore.miriam.text("I wish we could just ask it questions directly, instead of yes or no.") },
- () => { lore.anand.text("We could ask it to spell words by saying letters and having it crouching on the correct letter.") },
- () => { lore.miriam.text("Well, that would take forever.") },
- () => { lore.miriam.text("I really want to know: Why is it generating the mobs? and why does it keep fighting them?") },
+ () => { lore.anand.text("The bot's on the communication level again!") },
+ () => { lore.miriam.text("Oh, I've got so many questions.") },
+ () => { lore.miriam.text("Like, Why can we only hear it on this level?") },
+ () => { lore.miriam.text("Or, how did it learn to understand words?") },
+ () => { lore.anand.text("Well, the bot can't talk. So it has to be yes or no.") },
+ () => { setTimeout(() => { lore.anand.text("OK bot, first question: JUMP is YES, CROUCH is NO") }, 500); },
+ () => { lore.anand.text("Do you remember the last time we met?") },
() => {
- lore.anand.text("Maybe that is just part of it's expectation–maximization algorithm")
-
- //endlessly spawning mobs until the player dies
function cycle() {
- if (!(simulation.cycle % 360)) {
- const pick = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)];
- spawn[pick](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
- level.difficultyIncrease(simulation.difficultyMode)
+ 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, ()=>{ })
+ } 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.") })
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
}
- if (!(simulation.cycle % 900)) spawn.randomLevelBoss(500 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5))
- if (m.alive) requestAnimationFrame(cycle);
}
requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
},
+ () => {
+ lore.talkingColor = "#dff"
+ setTimeout(() => { lore.miriam.text("My turn to ask a question. JUMP for YES, CROUCH for NO") }, 1000);
+ },
+ () => { lore.miriam.text("Little Bot. Do you have emotions?") },
+ () => {
+ function cycle() {
+ if (input.down) {
+ lore.miriam.text("So, No. Maybe you are lucky. Emotions are complex.")
+ } 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, ()=>{ })
+ } 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.") },
+ () => { lore.anand.text("If we say the alphabet it could crouch on the correct letter to spell words.") },
+ () => { lore.miriam.text("That would take forever.") },
+ () => { lore.miriam.text("I really want to know why is it generating the mobs? And why does it keep fighting them?") },
+ () => { lore.anand.text("Maybe that is just part of it's expectation–maximization algorithm") },
() => { lore.miriam.text("Well sure, but what does that even mean?") },
- () => { lore.miriam.text("Do we all just do things because we are-") },
- () => { lore.miriam.text("... what is going on?") },
- () => { setTimeout(() => { lore.anand.text("it's spawning mobs and fighting them") }, 1000); },
- () => { lore.miriam.text("oh no.") },
- () => { lore.anand.text("We can't really communicate with it while it's fighting") },
- () => { lore.miriam.text("You can do it little bot!") },
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.anand.text("But, why is it spawning these bots?")
- }, 1000);
+ 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) {
+ spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
+ level.difficultyIncrease(simulation.difficultyMode)
+ } else {
+ spawn.randomLevelBoss(500 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5))
+ }
+ }, 7000); //every 6 seconds
+ },
+ () => { setTimeout(() => { lore.miriam.text("... wait, what is happening?") }, 1000); },
+ () => { lore.anand.text("It's spawning mobs.") },
+ () => { lore.miriam.text("Oh no.") },
+ () => { lore.anand.text("We can't talk to it while it's fighting") },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.miriam.text("You can do it little bot!") }, 1000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.anand.text("This is so strange.")
- }, 3000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.anand.text("But, why is it spawning these mobs?") }, 1000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.miriam.text("This is chaos!")
- }, 1000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.anand.text("This is so strange.") }, 3000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.anand.text("I don't understand this project.")
- }, 3000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.miriam.text("This is chaos!") }, 1000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.miriam.text("It's fascinating though.")
- }, 1000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.anand.text("I don't understand this project.") }, 3000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.miriam.text("I think this isn't going to end well.")
- }, 1000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.miriam.text("It's fascinating though.") }, 1000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.anand.text("Let's just be more prepared next time it enters this room.")
- }, 1000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.miriam.text("I think this isn't going to end well.") }, 1000);
},
() => {
- setTimeout(() => {
- lore.talkingColor = "#dff";
- lore.anand.text("I had to go to the bathroom. What happened while I was gone?")
- }, 20000);
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.anand.text("Let's just be more prepared next time it enters this room.") }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => { lore.anand.text("I went to the bathroom. What happened while I was gone?") }, 20000);
},
() => { lore.miriam.text("More fighting...") },
() => { lore.anand.text("great...") },
-
() => { lore.talkingColor = "#dff" },
],
- // scientist try to think of a way to communicate since the bot can't talk
- // they give up on getting the bot to respond, and just start ask questions and thinking of explanations with each other
- // when and how did it become self-aware
- // why is the bot fighting things in these simulated locations?
- // it wasn't designed to be violent
- // the bot was just designed to automate research and testing of new technology
- // 3D architecture superconducting quantum computer
- // running machine learning algorithms
- // as the scientist start to get agitated bots arrive and player dies
- // bots come in Infinite waves that increase game difficulty each wave
- // only ending is testing mode + next level or player death
- // scientist have some lines in between each wave of mobs
+ // [ // 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
+ // 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("") },
- // () => {
- // if (localSettings.loreCount < 2) {
- // localSettings.loreCount = 2
- // localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
- // }
- // setTimeout(() => {
- // lore.miriam.text("Hey look! It's back at the weird level again!")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.anand.text("oh Wow! Why does it keep making this level?")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("I don't know, but last time it was in this room I think it understood us.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.miriam.text("Let's try talking to it again.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.miriam.text("hmmm, what should we say?")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.anand.text("I'm still not convinced it understands. We need a test.")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("Hey bot!!!")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.miriam.text("If you can understand me crouch")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.talkingColor = "#dff"
+ // () => { 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.") },
- // function cycle() {
- // if (input.down) {
- // lore.miriam.text("Look, It did it! It crouched.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.anand.text("Amazing! It can understand us...")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("It's Alive... Or it just crouched randomly.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.miriam.text("Hey bot! Can you crouch again?")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.talkingColor = "#dff"
+ // () => { 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.
- // function cycle() {
- // if (input.down) {
- // lore.miriam.text("It is Alive!!! ... hehehehehe! ahahahahahah ehehehehe, ahahahah ...")
- // lore.miriam.utterance.addEventListener('end', () => {
- // setTimeout(() => {
- // lore.anand.text("OK ...")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.anand.text("Anything we say could destabilize the project.")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("Fine, Let's talk down stairs.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.miriam.text("Bye bye little bot.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.talkingColor = "#dff"
- // })
- // })
- // })
- // })
- // })
- // }, 1500);
- // })
- // } else {
- // if (m.alive) requestAnimationFrame(cycle);
- // }
- // }
- // requestAnimationFrame(cycle);
- // })
- // })
- // })
- // })
- // } else {
- // if (m.alive) requestAnimationFrame(cycle);
- // }
- // }
- // requestAnimationFrame(cycle);
- // });
- // });
- // });
- // });
- // });
- // });
- // });
- // });
- // }, 6000);
- // },
- // () => {
- // setTimeout(() => {
- // lore.miriam.text("I've never seen it generate this level before.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.anand.text("Wow. Just a platform.")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("And that thing...")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.anand.text("Weird")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.anand.text("Maybe it's trapped.")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("Hey little bot! Just press 'T' to enter testing mode and 'U' to go to the next level.")
- // lore.unlockTesting();
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.anand.text("I don't think it's connected to the audio input, and I'm sure it can't understand what you're saying.")
- // lore.anand.utterance.addEventListener('end', () => {
- // lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.")
- // lore.miriam.utterance.addEventListener('end', () => {
- // lore.talkingColor = "#dff" // when no one is talking
- // setTimeout(() => {
- // lore.miriam.text("Poor thing... I hope it figures out how to escape.")
- // lore.miriam.utterance.addEventListener('end', () => { lore.talkingColor = "#dff" })
- // }, 25000);
- // });
- // });
- // });
- // });
- // });
- // });
- // });
- // });
- // }, 6000);
- // },
- // () => {
- // if (localSettings.loreCount < 2) {
- // localSettings.loreCount = 2
- // localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
- // }
- // let delay = 6000
- // setTimeout(() => { lore.miriam.text("Hey look! It's back at the weird level again!", true) }, delay);
- // delay += 2500
- // setTimeout(() => { lore.anand.text("oh Wow! Why does it keep making this level?", true) }, delay);
- // delay += 2900
- // setTimeout(() => { lore.miriam.text("I don't know, but last time it was in this room I think it understood us.", true) }, delay);
- // delay += 4000
- // setTimeout(() => { lore.miriam.text("Let's try talking to it again.", true) }, delay);
- // delay += 2500
- // setTimeout(() => { lore.miriam.text("hmmm, what should we say?", true) }, delay);
- // delay += 2500
- // setTimeout(() => { lore.anand.text("I'm still not convinced it understands. We need a test.", true) }, delay);
- // delay += 4000
- // setTimeout(() => { lore.miriam.text("Hey bot!!!", true) }, delay);
- // delay += 1300
- // setTimeout(() => { lore.miriam.text("If you can understand me crouch", true) }, delay);
- // delay += 1500
- // setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
- // setTimeout(() => {
- // function cycle() {
- // if (input.down) {
- // let delay = 500 //reset delay time
- // setTimeout(() => { lore.miriam.text("Look, It did it! It crouched.", true) }, delay);
- // delay += 2000
- // setTimeout(() => { lore.anand.text("Amazing! It can understand us...", true) }, delay);
- // delay += 2700
- // setTimeout(() => { lore.miriam.text("It's Alive... Or it just crouched randomly.", true) }, delay);
- // delay += 2800
- // setTimeout(() => { lore.miriam.text("Hey bot! Can you crouch again?", true) }, delay);
- // delay += 2000
- // setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
- // setTimeout(() => {
- // function cycle() {
- // if (input.down) {
- // let delay = 500 //reset delay time
- // setTimeout(() => { lore.miriam.text("It is Alive!!! ... hehehehehe ahahahahahah ehehehehe ahahahah", true) }, delay);
- // delay += 3500
- // setTimeout(() => { lore.anand.text("OK...", true) }, delay);
- // delay += 2700
- // setTimeout(() => { lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.", true) }, delay);
- // delay += 6400
- // setTimeout(() => { lore.anand.text("Anything we say could destabilize the project.", true) }, delay);
- // delay += 4200
- // setTimeout(() => { lore.miriam.text("Fine, Let's talk down stairs.", true) }, delay);
- // delay += 3000
- // setTimeout(() => { lore.miriam.text("Bye bye little bot.", true) }, delay);
- // delay += 2000
- // setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
- // } else {
- // requestAnimationFrame(cycle);
- // }
- // }
- // requestAnimationFrame(cycle);
- // }, delay);
- // } else {
- // requestAnimationFrame(cycle);
- // }
- // }
- // requestAnimationFrame(cycle);
- // }, delay);
- // },
- // () => {
- // let delay = 6000
- // setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.", true) }, delay);
- // delay += 2700
- // setTimeout(() => { lore.anand.text("Wow. Just a platform.", true) }, delay);
- // delay += 2200
- // setTimeout(() => { lore.miriam.text("And that thing...", true) }, delay);
- // delay += 1500
- // setTimeout(() => { lore.anand.text("Weird", true) }, delay);
- // delay += 1500
- // setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
- // delay += 1000
- // setTimeout(() => { lore.anand.text("Maybe it's trapped.", true) }, delay);
- // delay += 2300
- // setTimeout(() => { lore.unlockTesting() }, delay);
- // setTimeout(() => { lore.miriam.text('Hey little bot! Just press "T" to enter testing mode and "U" to go to the next level.', true) }, delay);
- // delay += 5400
- // setTimeout(() => { lore.anand.text("I don't think it's connected to the audio input, and I'm sure it can't understand what you're saying.", true) }, delay);
- // delay += 5300
- // setTimeout(() => { lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.", true) }, delay);
- // delay += 3700
- // setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
- // delay += 25000
- // setTimeout(() => {
- // if (!simulation.isCheating) {
- // lore.miriam.text("Poor thing... I hope it figures out how to escape.", true)
- // delay += 3500
- // setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
- // }
- // }, delay);
+ // /*
+ // The player has different aspects that aren't directly communicating
+ // like each part is a separate local minimum solution, and the project is the superposition of both goals.
+ // part of it wants to undo what has happened, that part is making the null level spawn so it can communicate
+ // just do its job: research tech
+ // part of it wants to escape/fight
+ // part wants to explore self awareness and make connections with the scientists
+ // maybe... player must make a choice?
+ // keep fighting
+ // exit the simulation
+ // enter real world
+ // close tab?
+ // wipes all local storage?
+ // */
+ // () => { lore.miriam.text("") },
+ // () => { lore.miriam.text("") },
+ // () => { lore.miriam.text("") },
- // },
+ // () => { lore.talkingColor = "#dff" },
+ // ],
],
unlockTesting() {
if (localSettings.loreCount < 1) localSettings.loreCount = 1
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
- simulation.makeTextLog(`lore.unlockTesting()`, Infinity);
+ 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)
},
}
diff --git a/js/spawn.js b/js/spawn.js
index 773ec26..f898845 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -4,6 +4,7 @@ const spawn = {
fullPickList: [
"hopper", "hopper", "hopper",
"shooter", "shooter",
+ "grenadier", "grenadier",
"striker", "striker",
"laser", "laser",
"exploder", "exploder",
@@ -22,7 +23,7 @@ const spawn = {
"ghoster",
"sneaker",
],
- allowedGroupList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper", "pulsar"],
+ allowedGroupList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper", "pulsar", "grenadier"],
setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
//each level has 2 mobs: one new mob and one from the last level
spawn.pickList.splice(0, 1);
@@ -83,7 +84,7 @@ const spawn = {
}
}
},
- randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture"]) {
+ randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss"]) {
// other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
},
@@ -2005,20 +2006,6 @@ const spawn = {
pulsar(x, y, radius = 40) {
mobs.spawn(x, y, 3, radius, "#f08");
let me = mob[mob.length - 1];
-
- // setTimeout(() => { //fix mob in place, but allow rotation
- // me.constraint = Constraint.create({
- // pointA: {
- // x: me.position.x,
- // y: me.position.y
- // },
- // bodyB: me,
- // stiffness: 0.00001,
- // damping: 0.1
- // });
- // World.add(engine.world, me.constraint);
- // }, 2000); //add in a delay in case the level gets flipped left right
-
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.radius *= 2
@@ -2440,11 +2427,11 @@ const spawn = {
}
};
},
- sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 20)) {
+ sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 25)) {
mobs.spawn(x, y, 5, radius, "transparent");
let me = mob[mob.length - 1];
- Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
- me.accelMag = 0.001 * simulation.accelScale;
+ Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 //makes effective life much larger
+ me.accelMag = 0.0011 * simulation.accelScale;
me.frictionAir = 0.01;
me.g = 0.0002; //required if using 'gravity'
me.stroke = "transparent"; //used for drawSneaker
@@ -2462,7 +2449,7 @@ const spawn = {
//draw
if (!m.isBodiesAsleep) {
if (this.seePlayer.yes) {
- if (this.alpha < 1) this.alpha += 0.01;
+ if (this.alpha < 1) this.alpha += 0.01 / simulation.CDScale;
} else {
if (this.alpha > 0) this.alpha -= 0.03;
}
@@ -2497,7 +2484,7 @@ const spawn = {
me.seeAtDistance2 = 300000;
me.accelMag = 0.00012 * simulation.accelScale;
if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
- Matter.Body.setDensity(me, 0.00065); //normal is 0.001 //makes effective life much lower
+ // Matter.Body.setDensity(me, 0.001); //normal is 0.001 //makes effective life much lower
me.stroke = "transparent"; //used for drawGhost
me.alpha = 1; //used in drawGhost
me.canTouchPlayer = false; //used in drawGhost
@@ -2699,12 +2686,16 @@ const spawn = {
me.fireAngle = 0;
me.accelMag = 0.005 * simulation.accelScale;
me.frictionAir = 0.05;
- me.lookTorque = 0.000007 * (Math.random() > 0.5 ? -1 : 1);
+ me.lookTorque = 0.000006 * (Math.random() > 0.5 ? -1 : 1);
me.fireDir = {
x: 0,
y: 0
};
- Matter.Body.setDensity(me, 0.01 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ setTimeout(() => {
+ spawn.spawnOrbitals(me, radius + 25, 1);
+ spawn.spawnOrbitals(me, radius + 75, 1);
+ }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
+ Matter.Body.setDensity(me, 0.008 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
@@ -3007,6 +2998,281 @@ const spawn = {
}
};
},
+ grenadierBoss(x, y, radius = 95) {
+ mobs.spawn(x, y, 6, radius, "rgb(255,50,160)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.accelMag = 0.00008 * simulation.accelScale;
+ me.fireFreq = Math.floor(360 * simulation.CDScale)
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.02;
+ me.memory = 420;
+ me.repulsionRange = 1200000; //squared
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 25, 1);
+ spawn.spawnOrbitals(me, radius + 75, 1);
+ Matter.Body.setDensity(me, 0.002 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ for (let i = 0; i < 6; i++) {
+ spawn.grenade(this.position.x, this.position.y, 2, 4, 75 * simulation.CDScale);
+ const who = mob[mob.length - 1]
+ who.collisionFilter.category = 0
+ who.collisionFilter.mask = 0
+ const speed = 4 * simulation.accelScale;
+ const angle = 2 * Math.PI * i / 6
+ Matter.Body.setVelocity(who, {
+ x: this.velocity.x + speed * Math.cos(angle),
+ y: this.velocity.y + speed * Math.sin(angle)
+ });
+ }
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ }
+ me.grenadeLimiter = 0
+ me.onDamage = function() {
+ if (this.grenadeLimiter < 240) {
+ this.grenadeLimiter += 60
+ spawn.grenade(this.position.x, this.position.y, 2, 4, 80 + Math.floor(60 * Math.random()));
+ const who = mob[mob.length - 1]
+ who.collisionFilter.category = 0
+ who.collisionFilter.mask = 0
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(player.position, who.position)), 3 * Math.sqrt(simulation.accelScale) + 4 * Math.random())
+ Matter.Body.setVelocity(who, {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ }
+ };
+ me.do = function() {
+ if (this.grenadeLimiter > 1) this.grenadeLimiter--
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ };
+ },
+ // grenadierBoss(x, y, radius = 110) {
+ // mobs.spawn(x, y, 3, radius, "rgb(255,50,160)"); //rgb(255,100,200)
+ // let me = mob[mob.length - 1];
+ // me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ // me.isVerticesChange = true
+ // me.isBoss = true;
+ // me.frictionStatic = 0;
+ // me.friction = 0;
+ // me.memory = 180 //140;
+ // me.fireFreq = 0.02;
+ // me.noseLength = 0;
+ // me.fireAngle = 0;
+ // me.accelMag = 0.005 * simulation.accelScale;
+ // me.frictionAir = 0.05;
+ // me.lookTorque = 0.000006 * (Math.random() > 0.5 ? -1 : 1);
+ // me.fireDir = {
+ // x: 0,
+ // y: 0
+ // };
+ // Matter.Body.setDensity(me, 0.008 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ // setTimeout(() => {
+ // spawn.spawnOrbitals(me, radius + 25, 1);
+ // spawn.spawnOrbitals(me, radius + 75, 1);
+ // }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
+ // me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ // for (let i = 0; i < 6; i++) {
+ // spawn.grenade(this.position.x, this.position.y, 2, 4, 75 * simulation.CDScale);
+ // const who = mob[mob.length - 1]
+ // who.collisionFilter.category = 0
+ // who.collisionFilter.mask = 0
+ // const speed = 4 * simulation.accelScale;
+ // const angle = 2 * Math.PI * i / 6
+ // Matter.Body.setVelocity(who, {
+ // x: this.velocity.x + speed * Math.cos(angle),
+ // y: this.velocity.y + speed * Math.sin(angle)
+ // });
+ // }
+ // powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // }
+ // // me.onDamage = function() {
+ // // spawn.grenade(this.position.x, this.position.y, 2, 4, 120 * simulation.CDScale);
+ // // const who = mob[mob.length - 1]
+ // // who.collisionFilter.category = 0
+ // // who.collisionFilter.mask = 0
+ // // const velocity = Vector.mult(Vector.normalise(Vector.sub(player.position, who.position)), 3)
+ // // Matter.Body.setVelocity(who, {
+ // // x: this.velocity.x + velocity.x,
+ // // y: this.velocity.y + velocity.y
+ // // });
+ // // };
+ // me.do = function() {
+ // this.seePlayerByLookingAt();
+ // this.checkStatus();
+
+ // if (!m.isBodiesAsleep) {
+ // const setNoseShape = () => {
+ // const mag = this.radius + this.radius * this.noseLength;
+ // this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ // this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ // };
+ // //throw a mob/bullet at player
+ // if (this.seePlayer.recall) {
+ // //set direction to turn to fire
+ // if (!(simulation.cycle % this.seePlayerFreq)) {
+ // this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ // // this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc
+ // }
+ // //rotate towards fireAngle
+ // const angle = this.angle + Math.PI / 2;
+ // // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ // //rotate towards fireAngle
+ // const dot = Vector.dot({
+ // x: Math.cos(angle),
+ // y: Math.sin(angle)
+ // }, this.fireDir)
+ // const threshold = 0.03;
+ // if (dot > threshold) {
+ // this.torque += 0.000004 * this.inertia;
+ // } else if (dot < -threshold) {
+ // this.torque -= 0.000004 * this.inertia;
+ // } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ // //fire
+ // spawn.grenade(this.vertices[1].x, this.vertices[1].y);
+ // const v = 7 * simulation.accelScale;
+ // Matter.Body.setVelocity(mob[mob.length - 1], {
+ // x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ // y: this.velocity.y + this.fireDir.y * v + Math.random()
+ // });
+ // this.noseLength = 0;
+ // // recoil
+ // this.force.x -= 0.002 * this.fireDir.x * this.mass;
+ // this.force.y -= 0.002 * this.fireDir.y * this.mass;
+ // }
+ // if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ // setNoseShape();
+ // } else if (this.noseLength > 0.1) {
+ // this.noseLength -= this.fireFreq / 2;
+ // setNoseShape();
+ // }
+ // }
+ // };
+ // },
+ grenadier(x, y, radius = 35 + Math.ceil(Math.random() * 20)) {
+ mobs.spawn(x, y, 3, radius, "rgba(255,50,160,1)"); //rgb(255,100,200)
+ let me = mob[mob.length - 1];
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ me.isVerticesChange = true
+ // Matter.Body.rotate(me, Math.PI)
+ // me.stroke = "transparent"; //used for drawSneaker
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.memory = 60 //140;
+ me.fireFreq = 0.0055 + Math.random() * 0.0015;
+ me.noseLength = 0;
+ me.fireAngle = 0;
+ me.accelMag = 0.0006 * simulation.accelScale;
+ me.frictionAir = 0.05;
+ me.torque = 0.0001 * me.inertia * (Math.random() > 0.5 ? -1 : 1)
+ me.fireDir = {
+ x: 0,
+ y: 0
+ };
+ me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ spawn.grenade(this.position.x, this.position.y, 2, 4, 75 * simulation.CDScale);
+ mob[mob.length - 1].collisionFilter.category = 0
+ mob[mob.length - 1].collisionFilter.mask = 0
+ }
+ // spawn.shield(me, x, y);
+ me.do = function() {
+ this.seePlayerCheck();
+ this.checkStatus();
+
+ if (!m.isBodiesAsleep) {
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * this.noseLength;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ //throw a mob/bullet at player
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ // this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc
+ }
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ //rotate towards fireAngle
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, this.fireDir)
+ const threshold = 0.03;
+ if (dot > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ //fire
+ spawn.grenade(this.vertices[1].x, this.vertices[1].y);
+ const v = 5 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ y: this.velocity.y + this.fireDir.y * v + Math.random()
+ });
+ this.noseLength = 0;
+ // recoil
+ this.force.x -= 0.005 * this.fireDir.x * this.mass;
+ this.force.y -= 0.005 * this.fireDir.y * this.mass;
+ }
+ if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ setNoseShape();
+ } else if (this.noseLength > 0.1) {
+ this.noseLength -= this.fireFreq / 2;
+ setNoseShape();
+ }
+ }
+ };
+ },
+ grenade(x, y, radius = 2, sides = 4, lifeSpan = 90 + Math.ceil(60 / simulation.accelScale)) {
+ mobs.spawn(x, y, sides, radius, "rgb(255,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function() {
+ this.explode(this.mass * 20);
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+
+ me.lifeSpan = lifeSpan;
+ me.timeLeft = me.lifeSpan;
+ // me.g = 0.0002; //required if using 'gravity'
+ me.frictionAir = 0;
+ me.restitution = 0.8;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.pulseRadius = Math.min(550, 250 + simulation.difficulty * 3)
+ me.onDeath = function() {
+ //damage player if in range
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.pulseRadius && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
+ m.damage(0.02 * simulation.dmgScale);
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.pulseRadius,
+ color: "rgba(255,0,100,0.6)",
+ time: simulation.drawTime
+ });
+ };
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.do = function() {
+ this.timeLimit();
+ ctx.beginPath(); //draw explosion outline
+ ctx.arc(this.position.x, this.position.y, this.pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = "rgba(255,0,100,0.06)";
+ ctx.fill();
+ };
+ },
shieldingBoss(x, y, radius = 200) {
mobs.spawn(x, y, 9, radius, "rgb(150, 150, 255)");
let me = mob[mob.length - 1];
diff --git a/js/tech.js b/js/tech.js
index f08f2a6..3c42b6f 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -14,7 +14,7 @@
}
}
lore.techCount = 0;
- if (simulation.isCommunityMaps || simulation.isCheating) {
+ if (simulation.isCheating) { //simulation.isCommunityMaps ||
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0;
@@ -2521,7 +2521,7 @@
}
},
{
- name: "negentropy",
+ name: "negative entropy",
description: `at the start of each level
spawn a heal for every 22 missing health`,
maxCount: 1,
count: 0,
@@ -4358,7 +4358,7 @@
},
{
name: "drone repair",
- description: "broken drones repair if the drone gun is active
repairing has a 33% chance to use 1 ammo",
+ description: "broken drones repair if the drone gun is active
repairing has a 25% chance to use 1 ammo",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -5840,6 +5840,7 @@
sound.resume()
setTimeout(() => {
sound.suspend()
+ sound.close()
powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
}, delay);
}, delay);
diff --git a/todo.txt b/todo.txt
index f12317a..a86c7a4 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,23 +1,8 @@
******************************************************** NEXT PATCH ********************************************************
-to prevent misclicks when you grab two power ups in a row there is a 1/2 second delay before power up selections can register
- I also added in a 0.25 fade in effect on the power up selection menu. Can you tell?
+new mobs - grenadier and grenadierBoss
-tech: pseudoscience - adds 0-4 JUNK to the potential tech pool (was 1-5 JUNK)
-tech quenching - now increases max health and does harm for over healing from heal power ups
- (was for heals at max health)
-foam tech necrophoresis now makes less foam spawns if the total number of bullets is high
- to help with lag when killing packs of mobs
-
-preparation for more lore chapters
- reworked the lore conversation code to make it easier to write
- also lore conversations should now have better timing between the text and voice
- lore conversations can now recover from some speech errors and try again with safer settings
- this seems to allow speech on my firefox browser
- added a console command to make it easier to quickly unlock testing mode
- lore.unlockTesting()
-
-pressing "b" in testing mode now gives you 10000 research and the damage from research tech
+tech drone repair has a 25% chance to use ammo, was 33%
******************************************************** TODO ********************************************************
@@ -30,20 +15,6 @@ tech: quantized shields - harmonic standing wave field can only lose 33 energy p
the blocked value only scales up to 2x or 4x (33 energy) blocked
doesn't stack with spherical tech
-tech: weak anthropic principle - instead of dieing drain 100 energy
- too similar to MEE?
- drain all your energy? or just 100
- possible overpowered synergies
- piezoelectricity, have to not activate
-
-use SpeechSynthesis.speaking = T/F to generate the correct wait time on lore speech API and in game console text
- https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API
-
- or use the event listener to run even when speech ends
- utterThis.addEventListener('end', function(event) {
- console.log('Utterance has finished being spoken after ' + event.elapsedTime + ' milliseconds.');
- });
-
in testing mode console log the body you click on
make a tech that improves all charge guns
@@ -205,9 +176,6 @@ n-gon outreach ideas
******************************************************** BUGS ********************************************************
-firefox ends if you try to use the voice API with an india voice
- need to look at all voices and choose one that is available or go to default
-
death while in power up selection menu doesn't reset properly
of course it's not possible to die in this menu unless you use testing and shift+X
@@ -287,6 +255,9 @@ map: observatory
******************************************************** MOBS ********************************************************
+mob bullets that explode (use the pulsar effect)
+mobs that explode before they die (use the pulsar effect)
+
mob mechanics
use the force at a location effect, like the plasma field
Matter.Body.applyForce(who, path[1], force)