grenadier

new mobs - grenadier and grenadierBoss

tech drone repair has a 25% chance to use ammo, was 33%
This commit is contained in:
landgreen
2021-07-06 06:22:58 -07:00
parent 89ade77e14
commit b0b8e09333
7 changed files with 498 additions and 379 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -2074,7 +2074,7 @@ const b = {
const who = b.guns[b.activeGun] const who = b.guns[b.activeGun]
if (who.name === "drones" && who.ammo > 0 && mob.length) { if (who.name === "drones" && who.ammo > 0 && mob.length) {
b.drone({ x: this.position.x, y: this.position.y }, 0) 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--; b.guns[b.activeGun].ammo--;
simulation.updateGunHUD(); simulation.updateGunHUD();
} }
@@ -2213,7 +2213,7 @@ const b = {
const me = bullet.length; const me = bullet.length;
const THRUST = tech.isFastDrones ? 0.002 : 0.0012 + 0.0004 * (Math.random() - 0.5) 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 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, { bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, {
angle: dir, angle: dir,
inertia: Infinity, inertia: Infinity,
@@ -2235,7 +2235,7 @@ const b = {
deathCycles: 110 + RADIUS * 5, deathCycles: 110 + RADIUS * 5,
isImproved: false, isImproved: false,
radioRadius: 0, radioRadius: 0,
maxRadioRadius: 365 + Math.floor(150 * Math.random()), maxRadioRadius: 355 + Math.floor(150 * Math.random()),
beforeDmg(who) { beforeDmg(who) {
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) //move away from target after hitting const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) //move away from target after hitting
Matter.Body.setVelocity(this, { Matter.Body.setVelocity(this, {
@@ -2253,7 +2253,7 @@ const b = {
const who = b.guns[b.activeGun] const who = b.guns[b.activeGun]
if (who.name === "drones" && who.ammo > 0 && mob.length) { if (who.name === "drones" && who.ammo > 0 && mob.length) {
b.droneRadioactive({ x: this.position.x, y: this.position.y }, 0) 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--; b.guns[b.activeGun].ammo--;
simulation.updateGunHUD(); simulation.updateGunHUD();
} }
@@ -2276,7 +2276,7 @@ const b = {
//aoe damage to mobs //aoe damage to mobs
for (let i = 0, len = mob.length; i < len; i++) { 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) { 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 (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 if (mob[i].shield) dmg *= 3 // to make up for the /5 that shields normally take
mob[i].damage(dmg); mob[i].damage(dmg);

View File

@@ -2244,10 +2244,12 @@ const level = {
spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(6700, -1800, 800, 2600); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.starter(1900, -500, 200) //big boy // spawn.starter(1900, -500, 200) //big boy
// spawn.grower(1900, -500) // spawn.pulseShooter(1900, -500)
// spawn.pulsarBoss(1900, -500) // spawn.pulsarBoss(1900, -500)
// spawn.shooterBoss(1900, -500) spawn.grenadierBoss(1900, -500)
spawn.shieldingBoss(1900, -500)
// spawn.historyBoss(1200, -500) // spawn.historyBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400) // spawn.laserTargetingBoss(1600, -400)
// spawn.hopper(1600, -500) // spawn.hopper(1600, -500)
@@ -2261,7 +2263,7 @@ const level = {
// spawn.laser(1200, -500) // spawn.laser(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1); // spawn.shield(mob[mob.length - 1], 1800, -120, 1);
// spawn.nodeGroup(1200, -500, "pulsar") // spawn.nodeGroup(1200, -500, "grenadier")
// spawn.snakeBoss(1200, -500) // spawn.snakeBoss(1200, -500)
// spawn.suckerBoss(2900, -500) // spawn.suckerBoss(2900, -500)
// spawn.randomMob(1600, -500) // spawn.randomMob(1600, -500)

View File

@@ -49,22 +49,23 @@ const lore = {
// option.setAttribute('data-name', voices[i].name); // option.setAttribute('data-name', voices[i].name);
// voiceSelect.appendChild(option); // voiceSelect.appendChild(option);
// } // }
setVoices() { // setVoices() {
window.speechSynthesis.onvoiceschanged = () => { // window.speechSynthesis.onvoiceschanged = () => {
const synth = window.speechSynthesis // const synth = window.speechSynthesis
console.log(synth.getVoices()) // console.log(synth.getVoices())
const voiceArray = synth.getVoices() // const voiceArray = synth.getVoices()
lore.anand.voice = voiceArray[0] // lore.anand.voice = voiceArray[0]
lore.miriam.voice = voiceArray[1] // lore.miriam.voice = voiceArray[1]
console.log(voiceArray[0], voiceArray[1]) // console.log(voiceArray[0], voiceArray[1])
}; // };
// console.log('before') // // console.log('before')
// if ('speechSynthesis' in window) { // // if ('speechSynthesis' in window) {
// } else { // // } else {
// console.log('Text-to-speech not supported.'); // // console.log('Text-to-speech not supported.');
// } // // }
}, // },
rate: 1, // //utterance.rate = 1; // 0.1 to 10
anand: { anand: {
color: "#e0c", color: "#e0c",
voice: undefined, voice: undefined,
@@ -76,7 +77,7 @@ const lore = {
// utterance.voice = lore.anand.voice // utterance.voice = lore.anand.voice
utterance.lang = "en-GB" //"en-IN"; //de-DE en-GB fr-FR en-US en-AU utterance.lang = "en-GB" //"en-IN"; //de-DE en-GB fr-FR en-US en-AU
utterance.volume = 0.2; // 0 to 1 utterance.volume = 0.2; // 0 to 1
// utterance.rate = 1.5 // if (lore.rate !== 1) utterance.rate = lore.rate
speechSynthesis.speak(utterance); speechSynthesis.speak(utterance);
utterance.onerror = (event) => { //if speech doesn't work try again without the lang set utterance.onerror = (event) => { //if speech doesn't work try again without the lang set
console.log("speech error", event.error) console.log("speech error", event.error)
@@ -105,7 +106,7 @@ const lore = {
// utterance.voice = lore.anand.voice // utterance.voice = lore.anand.voice
utterance.lang = "en-AU"; utterance.lang = "en-AU";
utterance.volume = 0.2; // 0 to 1 utterance.volume = 0.2; // 0 to 1
// utterance.rate = 1.5 // if (lore.rate !== 1) utterance.rate = lore.rate
speechSynthesis.speak(utterance); speechSynthesis.speak(utterance);
utterance.onerror = (event) => { //if speech doesn't work try again without the lang set utterance.onerror = (event) => { //if speech doesn't work try again without the lang set
console.log("speech error", event.error) 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); // setTimeout(() => {}, 2000);
// lore.miriam.text("") // lore.miriam.text("")
// lore.miriam.utterance.addEventListener('end', () => { // lore.miriam.utterance.addEventListener('end', () => {
@@ -132,27 +139,22 @@ const lore = {
sentence: 0, //what part of the conversation is playing sentence: 0, //what part of the conversation is playing
conversation: [ conversation: [
[ //first time they meet, and testing gets unlocked [ //first time they meet, and testing gets unlocked
() => { () => { setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.") }, 5000); },
// lore.setVoices();
setTimeout(() => {
lore.miriam.text("I've never seen it generate this level before.")
}, 5000);
},
() => { lore.anand.text("Wow. Just a platform.") }, () => { lore.anand.text("Wow. Just a platform.") },
() => { lore.miriam.text("And that thing...") }, () => { lore.miriam.text("And that thing...") },
() => { lore.anand.text("Weird") }, () => { lore.anand.text("Weird") },
() => { lore.anand.text("Maybe it's trapped.") }, () => { 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(); 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.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.") },
() => { () => {
lore.talkingColor = "#dff" lore.talkingColor = "#dff"
setTimeout(() => { setTimeout(() => { lore.miriam.text("Poor thing... I hope it figures out how to escape.") }, 25000);
lore.miriam.text("Poor thing... I hope it figures out how to escape.")
}, 25000);
}, },
() => { lore.talkingColor = "#dff" }, () => { lore.talkingColor = "#dff" },
], ],
@@ -202,326 +204,203 @@ const lore = {
[ //they ask the bot questions, but waves of mobs come and attack [ //they ask the bot questions, but waves of mobs come and attack
() => { lore.anand.text("Quick, get ready. It's back!") }, () => { lore.anand.text("Quick, get ready. It's back!") },
() => { lore.miriam.text("What's back?") }, () => { lore.miriam.text("What's back?") },
() => { lore.anand.text("The bot is back on the communication level!") }, () => { lore.anand.text("The bot's on the communication level again!") },
() => { lore.miriam.text("Oh good, I've got so many questions.") }, () => { lore.miriam.text("Oh, I've got so many questions.") },
() => { lore.miriam.text("Is it self aware?") }, () => { lore.miriam.text("Like, Why can we only hear it on this level?") },
() => { lore.miriam.text("How did it learn to understand words?") }, () => { lore.miriam.text("Or, how did it learn to understand words?") },
() => { lore.miriam.text("Why can it only hear what we are saying on this level?") }, () => { lore.anand.text("Well, the bot can't talk. So it has to be yes or no.") },
() => { lore.miriam.text("I wish we could just ask it questions directly, instead of yes or no.") }, () => { setTimeout(() => { lore.anand.text("OK bot, first question: JUMP is YES, CROUCH is NO") }, 500); },
() => { lore.anand.text("We could ask it to spell words by saying letters and having it crouching on the correct letter.") }, () => { lore.anand.text("Do you remember the last time we met?") },
() => { 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("Maybe that is just part of it's expectationmaximization algorithm")
//endlessly spawning mobs until the player dies
function cycle() { function cycle() {
if (!(simulation.cycle % 360)) { if (input.down) {
const pick = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; lore.anand.text("It crouched: so NO")
spawn[pick](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5)); lore.sentence--
level.difficultyIncrease(simulation.difficultyMode) 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); 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 expectationmaximization algorithm") },
() => { lore.miriam.text("Well sure, but what does that even mean?") }, () => { 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.miriam.text("Do we all just do things because we are-")
lore.talkingColor = "#dff";
lore.anand.text("But, why is it spawning these bots?") spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
}, 1000); 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.talkingColor = "#dff"; setTimeout(() => { lore.anand.text("But, why is it spawning these mobs?") }, 1000);
lore.anand.text("This is so strange.")
}, 3000);
}, },
() => { () => {
setTimeout(() => { lore.talkingColor = "#dff";
lore.talkingColor = "#dff"; setTimeout(() => { lore.anand.text("This is so strange.") }, 3000);
lore.miriam.text("This is chaos!")
}, 1000);
}, },
() => { () => {
setTimeout(() => { lore.talkingColor = "#dff";
lore.talkingColor = "#dff"; setTimeout(() => { lore.miriam.text("This is chaos!") }, 1000);
lore.anand.text("I don't understand this project.")
}, 3000);
}, },
() => { () => {
setTimeout(() => { lore.talkingColor = "#dff";
lore.talkingColor = "#dff"; setTimeout(() => { lore.anand.text("I don't understand this project.") }, 3000);
lore.miriam.text("It's fascinating though.")
}, 1000);
}, },
() => { () => {
setTimeout(() => { lore.talkingColor = "#dff";
lore.talkingColor = "#dff"; setTimeout(() => { lore.miriam.text("It's fascinating though.") }, 1000);
lore.miriam.text("I think this isn't going to end well.")
}, 1000);
}, },
() => { () => {
setTimeout(() => { lore.talkingColor = "#dff";
lore.talkingColor = "#dff"; setTimeout(() => { lore.miriam.text("I think this isn't going to end well.") }, 1000);
lore.anand.text("Let's just be more prepared next time it enters this room.")
}, 1000);
}, },
() => { () => {
setTimeout(() => { lore.talkingColor = "#dff";
lore.talkingColor = "#dff"; setTimeout(() => { lore.anand.text("Let's just be more prepared next time it enters this room.") }, 1000);
lore.anand.text("I had to go to the bathroom. What happened while I was gone?") },
}, 20000); () => {
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.miriam.text("More fighting...") },
() => { lore.anand.text("great...") }, () => { lore.anand.text("great...") },
() => { lore.talkingColor = "#dff" }, () => { lore.talkingColor = "#dff" },
], ],
// scientist try to think of a way to communicate since the bot can't talk // [ // they provide background on why the project was built, and what is going wrong
// 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 // they explain the technological aspect, and purpose of the project
// why is the bot fighting things in these simulated locations? // to develop new technology
// it wasn't designed to be violent // they explain that the project isn't going well because it stopped working on new technology and started running the fighting simulations
// 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
// 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("") },
// () => { // () => { lore.talkingColor = "#dff" },
// if (localSettings.loreCount < 2) { // ],
// localSettings.loreCount = 2 // [ //they explain why the bot is fighting, it is planning an escape
// localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage // () => { lore.miriam.text("Welcome back bot, We've been waiting.") },
// } // () => { lore.miriam.text("So, I've got a theory about why you were attacked.") },
// setTimeout(() => { // () => { lore.miriam.text("") },
// lore.miriam.text("Hey look! It's back at the weird level again!") // () => { lore.miriam.text("I figured it out after I saw this famous quote.") },
// lore.miriam.utterance.addEventListener('end', () => { // () => { 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.anand.text("oh Wow! Why does it keep making this level?") // () => {
// lore.anand.utterance.addEventListener('end', () => { // lore.talkingColor = "#dff";
// lore.miriam.text("I don't know, but last time it was in this room I think it understood us.") // setTimeout(() => { lore.anand.text("That's profound") }, 3000);
// lore.miriam.utterance.addEventListener('end', () => { // },
// lore.miriam.text("Let's try talking to it again.") // () => { lore.anand.text("Also I looked it up, and there is no record of him saying that.") },
// lore.miriam.utterance.addEventListener('end', () => { // () => { lore.miriam.text("Oh... well...") },
// lore.miriam.text("hmmm, what should we say?") // () => { lore.miriam.text("It doesn't matter who said it.") },
// lore.miriam.utterance.addEventListener('end', () => { // () => { lore.anand.text("The point is we think the project views the universe as hostile.") },
// lore.anand.text("I'm still not convinced it understands. We need a test.") // () => { lore.miriam.text("We think you see the universe as hostile.") },
// lore.anand.utterance.addEventListener('end', () => { // () => { lore.miriam.text("And that is why you keep running these fighting simulations.") },
// lore.miriam.text("Hey bot!!!") // () => { lore.miriam.text("You are planning how to escape.") },
// lore.miriam.utterance.addEventListener('end', () => {
// lore.miriam.text("If you can understand me crouch")
// lore.miriam.utterance.addEventListener('end', () => {
// lore.talkingColor = "#dff"
// function cycle() { // () => { lore.talkingColor = "#dff" },
// if (input.down) { // ],
// lore.miriam.text("Look, It did it! It crouched.") // [ // 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.
// 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"
// function cycle() { // /*
// if (input.down) { // The player has different aspects that aren't directly communicating
// lore.miriam.text("It is Alive!!! ... hehehehehe! ahahahahahah ehehehehe, ahahahah ...") // like each part is a separate local minimum solution, and the project is the superposition of both goals.
// lore.miriam.utterance.addEventListener('end', () => { // part of it wants to undo what has happened, that part is making the null level spawn so it can communicate
// setTimeout(() => { // just do its job: research tech
// lore.anand.text("OK ...") // part of it wants to escape/fight
// lore.anand.utterance.addEventListener('end', () => { // part wants to explore self awareness and make connections with the scientists
// lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.") // maybe... player must make a choice?
// lore.anand.utterance.addEventListener('end', () => { // keep fighting
// lore.anand.text("Anything we say could destabilize the project.") // exit the simulation
// lore.anand.utterance.addEventListener('end', () => { // enter real world
// lore.miriam.text("Fine, Let's talk down stairs.") // close tab?
// lore.miriam.utterance.addEventListener('end', () => { // wipes all local storage?
// lore.miriam.text("Bye bye little bot.") // */
// lore.miriam.utterance.addEventListener('end', () => { // () => { lore.miriam.text("") },
// lore.talkingColor = "#dff" // () => { lore.miriam.text("") },
// }) // () => { lore.miriam.text("") },
// })
// })
// })
// })
// }, 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);
// }, // () => { lore.talkingColor = "#dff" },
// ],
], ],
unlockTesting() { unlockTesting() {
if (localSettings.loreCount < 1) localSettings.loreCount = 1 if (localSettings.loreCount < 1) localSettings.loreCount = 1
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible" document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
document.getElementById("experiment-button").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(`<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)
}, },
} }

View File

@@ -4,6 +4,7 @@ const spawn = {
fullPickList: [ fullPickList: [
"hopper", "hopper", "hopper", "hopper", "hopper", "hopper",
"shooter", "shooter", "shooter", "shooter",
"grenadier", "grenadier",
"striker", "striker", "striker", "striker",
"laser", "laser", "laser", "laser",
"exploder", "exploder", "exploder", "exploder",
@@ -22,7 +23,7 @@ const spawn = {
"ghoster", "ghoster",
"sneaker", "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 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 //each level has 2 mobs: one new mob and one from the last level
spawn.pickList.splice(0, 1); 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 // 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) spawn[options[Math.floor(Math.random() * options.length)]](x, y)
}, },
@@ -2005,20 +2006,6 @@ const spawn = {
pulsar(x, y, radius = 40) { pulsar(x, y, radius = 40) {
mobs.spawn(x, y, 3, radius, "#f08"); mobs.spawn(x, y, 3, radius, "#f08");
let me = mob[mob.length - 1]; 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 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); Matter.Body.rotate(me, Math.random() * Math.PI * 2);
me.radius *= 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"); mobs.spawn(x, y, 5, radius, "transparent");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 //makes effective life much larger
me.accelMag = 0.001 * simulation.accelScale; me.accelMag = 0.0011 * simulation.accelScale;
me.frictionAir = 0.01; me.frictionAir = 0.01;
me.g = 0.0002; //required if using 'gravity' me.g = 0.0002; //required if using 'gravity'
me.stroke = "transparent"; //used for drawSneaker me.stroke = "transparent"; //used for drawSneaker
@@ -2462,7 +2449,7 @@ const spawn = {
//draw //draw
if (!m.isBodiesAsleep) { if (!m.isBodiesAsleep) {
if (this.seePlayer.yes) { if (this.seePlayer.yes) {
if (this.alpha < 1) this.alpha += 0.01; if (this.alpha < 1) this.alpha += 0.01 / simulation.CDScale;
} else { } else {
if (this.alpha > 0) this.alpha -= 0.03; if (this.alpha > 0) this.alpha -= 0.03;
} }
@@ -2497,7 +2484,7 @@ const spawn = {
me.seeAtDistance2 = 300000; me.seeAtDistance2 = 300000;
me.accelMag = 0.00012 * simulation.accelScale; me.accelMag = 0.00012 * simulation.accelScale;
if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search 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.stroke = "transparent"; //used for drawGhost
me.alpha = 1; //used in drawGhost me.alpha = 1; //used in drawGhost
me.canTouchPlayer = false; //used in drawGhost me.canTouchPlayer = false; //used in drawGhost
@@ -2699,12 +2686,16 @@ const spawn = {
me.fireAngle = 0; me.fireAngle = 0;
me.accelMag = 0.005 * simulation.accelScale; me.accelMag = 0.005 * simulation.accelScale;
me.frictionAir = 0.05; 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 = { me.fireDir = {
x: 0, x: 0,
y: 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() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) 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 // 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) { shieldingBoss(x, y, radius = 200) {
mobs.spawn(x, y, 9, radius, "rgb(150, 150, 255)"); mobs.spawn(x, y, 9, radius, "rgb(150, 150, 255)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];

View File

@@ -14,7 +14,7 @@
} }
} }
lore.techCount = 0; lore.techCount = 0;
if (simulation.isCommunityMaps || simulation.isCheating) { if (simulation.isCheating) { //simulation.isCommunityMaps ||
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) { if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0; tech.tech[i].frequency = 0;
@@ -2521,7 +2521,7 @@
} }
}, },
{ {
name: "negentropy", name: "negative entropy",
description: `at the start of each <strong>level</strong><br>spawn a <strong class='color-h'>heal</strong> for every <strong>22</strong> missing health`, description: `at the start of each <strong>level</strong><br>spawn a <strong class='color-h'>heal</strong> for every <strong>22</strong> missing health`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -4358,7 +4358,7 @@
}, },
{ {
name: "drone repair", name: "drone repair",
description: "broken <strong>drones</strong> <strong>repair</strong> if the drone <strong class='color-g'>gun</strong> is active<br><strong>repairing</strong> has a <strong>33%</strong> chance to use <strong>1</strong> <strong class='color-g'>ammo</strong>", description: "broken <strong>drones</strong> <strong>repair</strong> if the drone <strong class='color-g'>gun</strong> is active<br><strong>repairing</strong> has a <strong>25%</strong> chance to use <strong>1</strong> <strong class='color-g'>ammo</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -5840,6 +5840,7 @@
sound.resume() sound.resume()
setTimeout(() => { setTimeout(() => {
sound.suspend() sound.suspend()
sound.close()
powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal"); powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
}, delay); }, delay);
}, delay); }, delay);

View File

@@ -1,23 +1,8 @@
******************************************************** NEXT PATCH ******************************************************** ******************************************************** 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 new mobs - grenadier and grenadierBoss
I also added in a 0.25 fade in effect on the power up selection menu. Can you tell?
tech: pseudoscience - adds 0-4 JUNK to the potential tech pool (was 1-5 JUNK) tech drone repair has a 25% chance to use ammo, was 33%
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
******************************************************** TODO ******************************************************** ******************************************************** 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 the blocked value only scales up to 2x or 4x (33 energy) blocked
doesn't stack with spherical tech 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 in testing mode console log the body you click on
make a tech that improves all charge guns make a tech that improves all charge guns
@@ -205,9 +176,6 @@ n-gon outreach ideas
******************************************************** BUGS ******************************************************** ******************************************************** 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 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 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 ******************************************************** ******************************************************** MOBS ********************************************************
mob bullets that explode (use the pulsar effect)
mobs that explode before they die (use the pulsar effect)
mob mechanics mob mechanics
use the force at a location effect, like the plasma field use the force at a location effect, like the plasma field
Matter.Body.applyForce(who, path[1], force) Matter.Body.applyForce(who, path[1], force)