From b0b8e093337ceb1fbdac914fdd033a092220636d Mon Sep 17 00:00:00 2001 From: landgreen Date: Tue, 6 Jul 2021 06:22:58 -0700 Subject: [PATCH] grenadier new mobs - grenadier and grenadierBoss tech drone repair has a 25% chance to use ammo, was 33% --- .DS_Store | Bin 6148 -> 6148 bytes js/bullet.js | 10 +- js/level.js | 10 +- js/lore.js | 499 +++++++++++++++++++-------------------------------- js/spawn.js | 312 +++++++++++++++++++++++++++++--- js/tech.js | 7 +- todo.txt | 39 +--- 7 files changed, 498 insertions(+), 379 deletions(-) diff --git a/.DS_Store b/.DS_Store index 6765adeefe4bfbff6aea29e221e2ca5a54100fe7..03292074950cc9fe63d01c35ba5f15f30a9e3297 100644 GIT binary patch delta 22 dcmZoMXffEJ#mrP!I$4L=mr3Hm=4$3n5dcxR2ND1P delta 22 dcmZoMXffEJ#mrRTGFgY&mr1f 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)