historyBoss

blocking uses 33% less energy

tech: stimulated emission removed
tech: Bayesian statistics renamed stimulated emission
tech: futures exchange gives 4.5% per cancel (up from 4%)

new level boss: follows you like the dynamo-bot, but is not friend
  will not spawn if you have a dynamo-bot
  (probably will be rebalanced in next patch)
This commit is contained in:
landgreen
2021-02-05 05:38:08 -08:00
parent 6446685cf0
commit 6e5d951bf1
13 changed files with 358 additions and 252 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -114,14 +114,14 @@
<br> <br>
<label for="classic-select" title="play older versions of n-gon">classic n-gon:</label> <label for="classic-select" title="play older versions of n-gon">classic n-gon:</label>
<select name="classic-select" id="classic-select" onChange="window.location.href=this.value"> <select name="classic-select" id="classic-select" onChange="window.location.href=this.value">
<option value="https://scratch.mit.edu/projects/14005697/fullscreen/" selected>scratch: 2015</option> <option value="https://scratch.mit.edu/projects/14005697/fullscreen/" selected>scratch: 2014</option>
<option value="https://scratch.mit.edu/projects/22573757/fullscreen/" selected>scratch: 2015</option> <option value="https://scratch.mit.edu/projects/22573757/fullscreen/" selected>scratch: 2015</option>
<option value="https://codepen.io/lilgreenland/full/ozXNWZ" selected>codepen: 2016</option> <option value="https://codepen.io/lilgreenland/full/ozXNWZ" selected>codepen: 2016</option>
<option value="https://codepen.io/lilgreenland/full/wzARJY">codepen: 2016</option> <option value="https://codepen.io/lilgreenland/full/wzARJY">codepen: 2016</option>
<option value="classic/7-1-2017/">n-gon: 2017</option> <option value="classic/7-1-2017/">n-gon: 2017</option>
<option value="classic/1-4-2018/">n-gon: 2018</option> <option value="classic/1-4-2018/">n-gon: 2018</option>
<option value="classic/7-11-2019/">n-gon: 2019</option> <option value="classic/7-11-2019/">n-gon: summer-2019</option>
<option value="classic/9-8-2019/">n-gon: 2019</option> <option value="classic/9-8-2019/">n-gon: fall-2019</option>
</select> </select>
<br> <br>
<label for="fps-select" title="use this to slow the game down">limit frames per second:</label> <label for="fps-select" title="use this to slow the game down">limit frames per second:</label>

View File

@@ -315,11 +315,11 @@ const b = {
} }
if (tech.isExplodeRadio) { //radiation explosion if (tech.isExplodeRadio) { //radiation explosion
const alertRange = 100 + radius * 2; //alert range radius *= 1.25; //alert range
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: where.x, x: where.x,
y: where.y, y: where.y,
radius: alertRange, radius: radius,
color: "rgba(25,139,170,0.25)", color: "rgba(25,139,170,0.25)",
time: simulation.drawTime * 2 time: simulation.drawTime * 2
}); });
@@ -328,9 +328,13 @@ const b = {
sub = Vector.sub(where, player.position); sub = Vector.sub(where, player.position);
dist = Vector.magnitude(sub); dist = Vector.magnitude(sub);
if (dist < alertRange) { if (dist < radius) {
m.energy -= 0.23 * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1) const drain = (tech.isExplosionHarm ? 0.5 : 0.25) * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1)
if (m.energy < 0) m.energy = 0 m.energy -= drain
if (m.energy < 0) {
m.energy = 0
m.damage(0.03);
}
} }
//mob damage and knock back with alert //mob damage and knock back with alert
@@ -339,10 +343,10 @@ const b = {
if (mob[i].alive && !mob[i].isShielded) { if (mob[i].alive && !mob[i].isShielded) {
sub = Vector.sub(where, mob[i].position); sub = Vector.sub(where, mob[i].position);
dist = Vector.magnitude(sub) - mob[i].radius; dist = Vector.magnitude(sub) - mob[i].radius;
if (dist < alertRange) { if (dist < radius) {
if (mob[i].shield) dmg *= 2.5 //balancing explosion dmg to shields if (mob[i].shield) dmg *= 2.5 //balancing explosion dmg to shields
if (Matter.Query.ray(map, mob[i].position, where).length > 0) dmg *= 0.5 //reduce damage if a wall is in the way if (Matter.Query.ray(map, mob[i].position, where).length > 0) dmg *= 0.5 //reduce damage if a wall is in the way
mobs.statusDoT(mob[i], dmg * damageScale * 0.2, 240) //apply radiation damage status effect on direct hits mobs.statusDoT(mob[i], dmg * damageScale * 0.25, 240) //apply radiation damage status effect on direct hits
mob[i].locatePlayer(); mob[i].locatePlayer();
damageScale *= 0.87 //reduced damage for each additional explosion target damageScale *= 0.87 //reduced damage for each additional explosion target
} }
@@ -1077,7 +1081,7 @@ const b = {
didExtruderDrain: false, didExtruderDrain: false,
canExtruderFire: true, canExtruderFire: true,
extruder() { extruder() {
const DRAIN = 0.0007 + m.fieldRegen const DRAIN = 0.0006 + m.fieldRegen
if (m.energy > DRAIN && b.canExtruderFire) { if (m.energy > DRAIN && b.canExtruderFire) {
m.energy -= DRAIN m.energy -= DRAIN
if (m.energy < 0) { if (m.energy < 0) {
@@ -1096,7 +1100,7 @@ const b = {
frictionAir: 0, frictionAir: 0,
isInHole: true, //this keeps the bullet from entering wormholes isInHole: true, //this keeps the bullet from entering wormholes
minDmgSpeed: 0, minDmgSpeed: 0,
dmg: b.dmgScale * 1.25, //damage also changes when you divide by mob.mass on in .do() dmg: b.dmgScale * 1.35, //damage also changes when you divide by mob.mass on in .do()
classType: "bullet", classType: "bullet",
isBranch: false, isBranch: false,
restitution: 0, restitution: 0,
@@ -2545,7 +2549,7 @@ const b = {
dmg: 0, // 0.14 //damage done in addition to the damage from momentum dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 2, minDmgSpeed: 2,
lookFrequency: 40 + Math.floor(7 * Math.random()), lookFrequency: 40 + Math.floor(7 * Math.random()),
drainThreshold: tech.isEnergyHealth ? 0.5 : 0.33, drainThreshold: tech.isEnergyHealth ? 0.6 : 0.4,
acceleration: 0.0015 * (1 + 0.3 * Math.random()), acceleration: 0.0015 * (1 + 0.3 * Math.random()),
range: 700 * (1 + 0.1 * Math.random()) + 300 * tech.isLaserBotUpgrade, range: 700 * (1 + 0.1 * Math.random()) + 300 * tech.isLaserBotUpgrade,
playerRange: 150 + Math.floor(30 * Math.random()), playerRange: 150 + Math.floor(30 * Math.random()),
@@ -2711,7 +2715,7 @@ const b = {
cd: 0, cd: 0,
acceleration: 0.009, acceleration: 0.009,
endCycle: Infinity, endCycle: Infinity,
drainThreshold: tech.isEnergyHealth ? 0.4 : 0.2, drainThreshold: tech.isEnergyHealth ? 0.5 : 0.33,
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
category: cat.bullet, category: cat.bullet,

View File

@@ -196,6 +196,7 @@ const build = {
<br> <br>
<br>level: ${level.levels[level.onLevel]} (${level.difficultyText()}) &nbsp; ${m.cycle} cycles <br>level: ${level.levels[level.onLevel]} (${level.difficultyText()}) &nbsp; ${m.cycle} cycles
<br>${mob.length} mobs, &nbsp; ${body.length} blocks, &nbsp; ${bullet.length} bullets, &nbsp; ${powerUp.length} power ups <br>${mob.length} mobs, &nbsp; ${body.length} blocks, &nbsp; ${bullet.length} bullets, &nbsp; ${powerUp.length} power ups
<br>damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }% <br>damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }%
<br>harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}% <br>harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}%
<br>heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}% <br>heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}%

View File

@@ -7,7 +7,6 @@ const level = {
defaultZoom: 1400, defaultZoom: 1400,
onLevel: -1, onLevel: -1,
levelsCleared: 0, levelsCleared: 0,
bossKilled: false,
playableLevels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber"], playableLevels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber"],
levels: [], levels: [],
start() { start() {
@@ -111,26 +110,26 @@ const level = {
difficultyIncrease(num = 1) { difficultyIncrease(num = 1) {
for (let i = 0; i < num; i++) { for (let i = 0; i < num; i++) {
simulation.difficulty++ simulation.difficulty++
b.dmgScale *= 0.93; //damage done by player decreases each level b.dmgScale *= 0.94; //damage done by player decreases each level
if (simulation.accelScale < 5) simulation.accelScale *= 1.02 //mob acceleration increases each level if (simulation.accelScale < 5) simulation.accelScale *= 1.02 //mob acceleration increases each level
if (simulation.lookFreqScale > 0.2) simulation.lookFreqScale *= 0.98 //mob cycles between looks decreases each level if (simulation.lookFreqScale > 0.2) simulation.lookFreqScale *= 0.98 //mob cycles between looks decreases each level
if (simulation.CDScale > 0.2) simulation.CDScale *= 0.97 //mob CD time decreases each level if (simulation.CDScale > 0.2) simulation.CDScale *= 0.97 //mob CD time decreases each level
} }
simulation.dmgScale = 0.378 * simulation.difficulty //damage done by mobs increases each level simulation.dmgScale = 0.36 * simulation.difficulty //damage done by mobs increases each level
simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
}, },
difficultyDecrease(num = 1) { //used in easy mode for simulation.reset() difficultyDecrease(num = 1) { //used in easy mode for simulation.reset()
for (let i = 0; i < num; i++) { for (let i = 0; i < num; i++) {
simulation.difficulty-- simulation.difficulty--
b.dmgScale /= 0.93; //damage done by player decreases each level b.dmgScale /= 0.94; //damage done by player decreases each level
if (simulation.accelScale > 0.2) simulation.accelScale /= 1.02 //mob acceleration increases each level if (simulation.accelScale > 0.2) simulation.accelScale /= 1.02 //mob acceleration increases each level
if (simulation.lookFreqScale < 5) simulation.lookFreqScale /= 0.98 //mob cycles between looks decreases each level if (simulation.lookFreqScale < 5) simulation.lookFreqScale /= 0.98 //mob cycles between looks decreases each level
if (simulation.CDScale < 5) simulation.CDScale /= 0.97 //mob CD time decreases each level if (simulation.CDScale < 5) simulation.CDScale /= 0.97 //mob CD time decreases each level
} }
if (simulation.difficulty < 1) simulation.difficulty = 0; if (simulation.difficulty < 1) simulation.difficulty = 0;
simulation.dmgScale = 0.378 * simulation.difficulty //damage done by mobs increases each level simulation.dmgScale = 0.36 * simulation.difficulty //damage done by mobs increases each level
if (simulation.dmgScale < 0.1) simulation.dmgScale = 0.1; if (simulation.dmgScale < 0.1) simulation.dmgScale = 0.1;
simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) simulation.healScale = 1 / (1 + simulation.difficulty * 0.055)
}, },
difficultyText() { difficultyText() {
if (simulation.difficultyMode === 1) { if (simulation.difficultyMode === 1) {
@@ -1052,7 +1051,8 @@ const level = {
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.boost(1500, 0, 900); // spawn.boost(1500, 0, 900);
spawn.starter(1900, -500, 200) //big boy // spawn.starter(1900, -500, 200) //big boy
spawn.historyBoss(1900, -500)
// spawn.sneaker(2900, -500) // spawn.sneaker(2900, -500)
// spawn.launcherBoss(1200, -500) // spawn.launcherBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400) // spawn.laserTargetingBoss(1600, -400)
@@ -1066,7 +1066,7 @@ const level = {
// spawn.beamer(1200, -500) // spawn.beamer(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1); // spawn.shield(mob[mob.length - 1], 1800, -120, 1);
// spawn.nodeBoss(1200, -500, "launcher") // spawn.nodeGroup(1200, -500, "launcher")
// spawn.snakeBoss(1200, -500) // spawn.snakeBoss(1200, -500)
// spawn.powerUpBoss(2900, -500) // spawn.powerUpBoss(2900, -500)
// spawn.randomMob(1600, -500) // spawn.randomMob(1600, -500)
@@ -1105,13 +1105,12 @@ const level = {
// spawn.boost(4150, 0, 1300); // spawn.boost(4150, 0, 1300);
// spawn.randomSmallMob(1300, -70); // spawn.randomSmallMob(1300, -70);
// spawn.randomMob(2650, -975, 0.8); // spawn.randomMob(2650, -975, 0.8);
// spawn.randomBoss(1700, -900, 0.4); // spawn.randomGroup(1700, -900, 0.4);
// if (simulation.difficulty > 3) spawn.randomLevelBoss(2200, -1300); // if (simulation.difficulty > 3) spawn.randomLevelBoss(2200, -1300);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
// if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500); // if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
}, },
final() { final() {
level.bossKilled = false; // if a boss needs to be killed
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
}; };
@@ -1162,7 +1161,6 @@ const level = {
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
}, },
gauntlet() { gauntlet() {
level.bossKilled = true; //if there is no boss this needs to be true to increase levels
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
}; };
@@ -1199,12 +1197,12 @@ const level = {
spawn.blockDoor(2585, -210) spawn.blockDoor(2585, -210)
spawn.mapRect(2500, -200, 200, 300); //right wall spawn.mapRect(2500, -200, 200, 300); //right wall
spawn.nodeBoss(3500, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); spawn.nodeGroup(3500, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]);
spawn.mapRect(4500, -1200, 200, 750); //right wall spawn.mapRect(4500, -1200, 200, 750); //right wall
spawn.blockDoor(4585, -210) spawn.blockDoor(4585, -210)
spawn.mapRect(4500, -200, 200, 300); //right wall spawn.mapRect(4500, -200, 200, 300); //right wall
spawn.lineBoss(5000, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); spawn.lineGroup(5000, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]);
spawn.mapRect(6400, -1200, 400, 750); //right wall spawn.mapRect(6400, -1200, 400, 750); //right wall
spawn.mapRect(6400, -200, 400, 300); //right wall spawn.mapRect(6400, -200, 400, 300); //right wall
spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(6700, -1800, 800, 2600); //right wall
@@ -1212,20 +1210,19 @@ const level = {
for (let i = 0; i < 3; ++i) { for (let i = 0; i < 3; ++i) {
if (simulation.difficulty * Math.random() > 15 * i) { if (simulation.difficulty * Math.random() > 15 * i) {
spawn.randomBoss(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); spawn.randomGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
} }
if (simulation.difficulty * Math.random() > 10 * i) { if (simulation.difficulty * Math.random() > 10 * i) {
spawn.randomBoss(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); spawn.randomGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
} }
if (simulation.difficulty * Math.random() > 7 * i) { if (simulation.difficulty * Math.random() > 7 * i) {
spawn.randomBoss(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
} }
} }
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350);
}, },
intro() { intro() {
level.bossKilled = true; //if there is no boss this needs to be true to increase levels
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
}; };
@@ -1709,7 +1706,7 @@ const level = {
spawn.randomMob(1550, -2750, -0.5); spawn.randomMob(1550, -2750, -0.5);
spawn.randomMob(1350, -1150, -0.5); spawn.randomMob(1350, -1150, -0.5);
spawn.randomMob(-75, -1475, 0); spawn.randomMob(-75, -1475, 0);
spawn.randomBoss(600, -2600, 0); spawn.randomGroup(600, -2600, 0);
} }
if (simulation.difficulty < 25) { if (simulation.difficulty < 25) {
spawn.randomMob(700, -1650, 0); spawn.randomMob(700, -1650, 0);
@@ -1727,7 +1724,6 @@ const level = {
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1925, -1250); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1925, -1250);
}, },
sewers() { sewers() {
level.bossKilled = false; // if a boss needs to be killed
const rotor = level.rotor(5100, 2475, -0.001) const rotor = level.rotor(5100, 2475, -0.001)
const button = level.button(6600, 2675) const button = level.button(6600, 2675)
const hazard = level.hazard(4550, 2750, 4550, 150) const hazard = level.hazard(4550, 2750, 4550, 150)
@@ -1844,7 +1840,7 @@ const level = {
spawn.mapRect(9300, 2590, 650, 25); spawn.mapRect(9300, 2590, 650, 25);
spawn.mapRect(9700, 2580, 100, 50); spawn.mapRect(9700, 2580, 100, 50);
spawn.randomBoss(1300, 2100, 0.1); spawn.randomGroup(1300, 2100, 0.1);
spawn.randomMob(8300, 2100, 0.1); spawn.randomMob(8300, 2100, 0.1);
spawn.randomSmallMob(2575, -75, 0.1); //entrance spawn.randomSmallMob(2575, -75, 0.1); //entrance
spawn.randomMob(8125, 2450, 0.1); spawn.randomMob(8125, 2450, 0.1);
@@ -1855,7 +1851,7 @@ const level = {
spawn.randomSmallMob(1100, -300, 0.2); //entrance spawn.randomSmallMob(1100, -300, 0.2); //entrance
spawn.randomMob(4450, 2500, 0.2); spawn.randomMob(4450, 2500, 0.2);
spawn.randomMob(6350, 2525, 0.2); spawn.randomMob(6350, 2525, 0.2);
spawn.randomBoss(9200, 2400, 0.3); spawn.randomGroup(9200, 2400, 0.3);
spawn.randomSmallMob(1900, -250, 0.3); //entrance spawn.randomSmallMob(1900, -250, 0.3); //entrance
spawn.randomMob(1500, 2100, 0.4); spawn.randomMob(1500, 2100, 0.4);
spawn.randomSmallMob(1700, -150, 0.4); //entrance spawn.randomSmallMob(1700, -150, 0.4); //entrance
@@ -1868,12 +1864,11 @@ const level = {
spawn.randomMob(3600, 1725, 0.9); spawn.randomMob(3600, 1725, 0.9);
spawn.randomMob(4100, 1225, 0.9); spawn.randomMob(4100, 1225, 0.9);
spawn.randomMob(2825, 400, 0.9); spawn.randomMob(2825, 400, 0.9);
if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]); if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss"]);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275);
}, },
satellite() { satellite() {
level.bossKilled = false; // if a boss needs to be killed
const elevator = level.platform(4210, -1325, 380, 30, -10) const elevator = level.platform(4210, -1325, 380, 30, -10)
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
@@ -2058,13 +2053,13 @@ const level = {
spawn.randomMob(2000, -2800, 0.4); spawn.randomMob(2000, -2800, 0.4);
spawn.randomMob(2200, -500, 0.4); spawn.randomMob(2200, -500, 0.4);
spawn.randomMob(4475, -3550, 0.3); spawn.randomMob(4475, -3550, 0.3);
spawn.randomBoss(5000, -2150, 1); spawn.randomGroup(5000, -2150, 1);
spawn.randomBoss(3700, -4100, 0.3); spawn.randomGroup(3700, -4100, 0.3);
spawn.randomBoss(2700, -1600, 0.1); spawn.randomGroup(2700, -1600, 0.1);
spawn.randomBoss(1600, -100, 0); spawn.randomGroup(1600, -100, 0);
spawn.randomBoss(5000, -3900, -0.3); spawn.randomGroup(5000, -3900, -0.3);
if (simulation.difficulty > 3) { if (simulation.difficulty > 3) {
if (Math.random() < 0.1) { if (Math.random() < 0.2) {
spawn.randomLevelBoss(2800, -1400); spawn.randomLevelBoss(2800, -1400);
} else if (Math.random() < 0.25) { } else if (Math.random() < 0.25) {
spawn.laserBoss(2900 + 300 * Math.random(), -2950 + 150 * Math.random()); spawn.laserBoss(2900 + 300 * Math.random(), -2950 + 150 * Math.random());
@@ -2080,7 +2075,6 @@ const level = {
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3950, -850); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3950, -850);
}, },
rooftops() { rooftops() {
level.bossKilled = false; // if a boss needs to be killed
const elevator = level.platform(1450, -1000, 235, 30, -2) const elevator = level.platform(1450, -1000, 235, 30, -2)
level.custom = () => { level.custom = () => {
ctx.fillStyle = "#ccc" ctx.fillStyle = "#ccc"
@@ -2296,15 +2290,14 @@ const level = {
spawn.randomMob(5200, -100, 0.3); spawn.randomMob(5200, -100, 0.3);
spawn.randomMob(5275, -900, 0.2); spawn.randomMob(5275, -900, 0.2);
spawn.randomMob(900, -2125, 0.3); spawn.randomMob(900, -2125, 0.3);
spawn.randomBoss(600, -1575, 0); spawn.randomGroup(600, -1575, 0);
spawn.randomBoss(2225, -1325, 0.4); spawn.randomGroup(2225, -1325, 0.4);
spawn.randomBoss(4900, -1200, 0); spawn.randomGroup(4900, -1200, 0);
if (simulation.difficulty > 3) spawn.randomLevelBoss(3200, -2050); if (simulation.difficulty > 3) spawn.randomLevelBoss(3200, -2050);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(2175, -2425); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(2175, -2425);
}, },
aerie() { aerie() {
level.bossKilled = false; // if a boss needs to be killed
// const elevator = level.platform(4112, -2300, 280, 50) // const elevator = level.platform(4112, -2300, 280, 50)
// simulation.g = 0.0012 //0.0024 // simulation.g = 0.0012 //0.0024
level.custom = () => { level.custom = () => {
@@ -2446,7 +2439,7 @@ const level = {
spawn.mapRect(4250, -3700, 50, 300); spawn.mapRect(4250, -3700, 50, 300);
spawn.mapRect(3700, -3250, 1100, 100); spawn.mapRect(3700, -3250, 1100, 100);
spawn.randomBoss(350, -500, 1) spawn.randomGroup(350, -500, 1)
spawn.randomSmallMob(-225, 25); spawn.randomSmallMob(-225, 25);
spawn.randomSmallMob(1000, -1100); spawn.randomSmallMob(1000, -1100);
spawn.randomSmallMob(4000, -250); spawn.randomSmallMob(4000, -250);
@@ -2465,8 +2458,8 @@ const level = {
spawn.randomMob(1700, -50, 0.3) spawn.randomMob(1700, -50, 0.3)
spawn.randomMob(2350, -900, 0.3) spawn.randomMob(2350, -900, 0.3)
spawn.randomMob(4700, -150, 0.2); spawn.randomMob(4700, -150, 0.2);
spawn.randomBoss(4000, -350, 0.6); spawn.randomGroup(4000, -350, 0.6);
spawn.randomBoss(2750, -550, 0.1); spawn.randomGroup(2750, -550, 0.1);
spawn.randomMob(2175, -925, 0.5); spawn.randomMob(2175, -925, 0.5);
spawn.randomMob(2750, 100, 0.5); spawn.randomMob(2750, 100, 0.5);
spawn.randomMob(4250, -1725, 0.5); spawn.randomMob(4250, -1725, 0.5);
@@ -2486,8 +2479,8 @@ const level = {
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
if (simulation.difficulty > 4) spawn.nodeBoss(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss if (simulation.difficulty > 4) spawn.nodeGroup(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss
} else if (Math.random() < 0.15) { } else if (Math.random() < 0.2) {
spawn.randomLevelBoss(4250, -250); spawn.randomLevelBoss(4250, -250);
spawn.debris(-250, 50, 1650, 2); //16 debris per level spawn.debris(-250, 50, 1650, 2); //16 debris per level
spawn.debris(2475, 0, 750, 2); //16 debris per level spawn.debris(2475, 0, 750, 2); //16 debris per level
@@ -2514,7 +2507,6 @@ const level = {
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(5350, -325); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(5350, -325);
}, },
skyscrapers() { skyscrapers() {
level.bossKilled = false; // if a boss needs to be killed
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
}; };
@@ -2669,14 +2661,13 @@ const level = {
spawn.randomMob(2200, -600, 0.2); spawn.randomMob(2200, -600, 0.2);
spawn.randomMob(850, -1300, 0.25); spawn.randomMob(850, -1300, 0.25);
spawn.randomMob(-100, -900, -0.2); spawn.randomMob(-100, -900, -0.2);
spawn.randomBoss(3700, -1500, 0.4); spawn.randomGroup(3700, -1500, 0.4);
spawn.randomBoss(1700, -900, 0.4); spawn.randomGroup(1700, -900, 0.4);
if (simulation.difficulty > 3) spawn.randomLevelBoss(2600, -2300); if (simulation.difficulty > 3) spawn.randomLevelBoss(2600, -2300);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3075, -2050); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3075, -2050);
}, },
highrise() { highrise() {
level.bossKilled = false; // if a boss needs to be killed
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
}; };
@@ -2868,15 +2859,14 @@ const level = {
spawn.randomMob(-125, -1500, -0.1); spawn.randomMob(-125, -1500, -0.1);
spawn.randomMob(-325, -1900, -0.1); spawn.randomMob(-325, -1900, -0.1);
spawn.randomMob(-550, -100, -0.1); spawn.randomMob(-550, -100, -0.1);
spawn.randomBoss(-3250, -2700, 0.2); spawn.randomGroup(-3250, -2700, 0.2);
spawn.randomBoss(-2450, -1100, 0); spawn.randomGroup(-2450, -1100, 0);
if (simulation.difficulty > 3) spawn.randomLevelBoss(-2400, -3000); if (simulation.difficulty > 3) spawn.randomLevelBoss(-2400, -3000);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(-1825, -1975); if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(-1825, -1975);
}, },
warehouse() { warehouse() {
level.bossKilled = false; // if a boss needs to be killed
level.custom = () => { level.custom = () => {
level.playerExitCheck(); level.playerExitCheck();
}; };
@@ -3037,9 +3027,9 @@ const level = {
spawn.randomMob(475, 300, 0); spawn.randomMob(475, 300, 0);
spawn.randomMob(-75, -700, 0); spawn.randomMob(-75, -700, 0);
spawn.randomMob(900, -200, -0.1); spawn.randomMob(900, -200, -0.1);
spawn.randomBoss(-125, 275, -0.2); spawn.randomGroup(-125, 275, -0.2);
spawn.randomBoss(-825, 1000, 0.2); spawn.randomGroup(-825, 1000, 0.2);
spawn.randomBoss(-1300, -1100, -0.3); spawn.randomGroup(-1300, -1100, -0.3);
if (simulation.difficulty > 3) { if (simulation.difficulty > 3) {
if (Math.random() < 0.25) { if (Math.random() < 0.25) {
@@ -3069,7 +3059,7 @@ const level = {
color: "#dff" color: "#dff"
}); });
} else { //reverse direction, start in bottom right } else { //reverse direction, start in bottom right
button = level.button(4300, 0) button = level.button(3800, 0)
door = level.door(3012, -200, 25, 200, 195) door = level.door(3012, -200, 25, 200, 195)
level.setPosToSpawn(3250, -550); //normal spawn level.setPosToSpawn(3250, -550); //normal spawn
level.exit.x = 1375; level.exit.x = 1375;
@@ -3220,11 +3210,11 @@ const level = {
spawn.randomMob(450, -225, 0.15); spawn.randomMob(450, -225, 0.15);
spawn.randomMob(100, -1200, 1); spawn.randomMob(100, -1200, 1);
spawn.randomMob(950, -1150, -0.1); spawn.randomMob(950, -1150, -0.1);
spawn.randomBoss(1800, -800, -0.2); spawn.randomGroup(1800, -800, -0.2);
spawn.randomBoss(4150, -1000, 0.6); spawn.randomGroup(4150, -1000, 0.6);
if (simulation.difficulty > 3) { if (simulation.difficulty > 3) {
if (Math.random() < 0.65) { if (Math.random() < 0.5) {
// tether ball // tether ball
level.fillBG.push({ level.fillBG.push({
x: 2495, x: 2495,
@@ -3244,7 +3234,7 @@ const level = {
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
//chance to spawn a ring of exploding mobs around this boss //chance to spawn a ring of exploding mobs around this boss
if (simulation.difficulty > 6) spawn.nodeBoss(2850, -80, "spawns", 8, 20, 105); if (simulation.difficulty > 6) spawn.nodeGroup(2850, -80, "spawns", 8, 20, 105);
} else { } else {
spawn.randomLevelBoss(2200, -450) spawn.randomLevelBoss(2200, -450)
} }
@@ -3483,9 +3473,9 @@ const level = {
spawn.randomMob(3050, -1650, 0.8); spawn.randomMob(3050, -1650, 0.8);
spawn.randomMob(3350, -600, 0.8); spawn.randomMob(3350, -600, 0.8);
spawn.randomMob(4400, -50, 1); spawn.randomMob(4400, -50, 1);
spawn.randomBoss(1500, -1900, 0.5); spawn.randomGroup(1500, -1900, 0.5);
spawn.randomBoss(2350, -850, 1); spawn.randomGroup(2350, -850, 1);
spawn.randomBoss(100, -450, 0.9); spawn.randomGroup(100, -450, 0.9);
if (simulation.difficulty > 3) spawn.randomLevelBoss(1850, -1400); if (simulation.difficulty > 3) spawn.randomLevelBoss(1850, -1400);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
@@ -3719,7 +3709,7 @@ const level = {
stiffness: 0.00006 stiffness: 0.00006
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
if (simulation.difficulty > 4) spawn.nodeBoss(7000, -3300, "spawns", 8, 20, 105); if (simulation.difficulty > 4) spawn.nodeGroup(7000, -3300, "spawns", 8, 20, 105);
} else if (simulation.difficulty > 3) { } else if (simulation.difficulty > 3) {
spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss"]); spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss"]);
} }
@@ -3738,7 +3728,7 @@ const level = {
stiffness: 0.00036 stiffness: 0.00036
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
if (simulation.difficulty > 4) spawn.nodeBoss(2350, -1300, "spawns", 8, 20, 105); if (simulation.difficulty > 4) spawn.nodeGroup(2350, -1300, "spawns", 8, 20, 105);
} else if (simulation.difficulty > 3) { } else if (simulation.difficulty > 3) {
spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "snakeBoss"]); spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "snakeBoss"]);
} }
@@ -3765,10 +3755,10 @@ const level = {
spawn.randomMob(800, 1200, 0.3); spawn.randomMob(800, 1200, 0.3);
spawn.randomMob(7200, -4000, 0.3); spawn.randomMob(7200, -4000, 0.3);
spawn.randomMob(250, -1550, 0.3); spawn.randomMob(250, -1550, 0.3);
spawn.randomBoss(900, -1450, 0.3); spawn.randomGroup(900, -1450, 0.3);
spawn.randomBoss(2980, -400, 0.3); spawn.randomGroup(2980, -400, 0.3);
spawn.randomBoss(5750, -3860, 0.4); spawn.randomGroup(5750, -3860, 0.4);
spawn.randomBoss(1130, 1300, 0.1); spawn.randomGroup(1130, 1300, 0.1);
powerUps.addRerollToLevel() //needs to run after mobs are spawned powerUps.addRerollToLevel() //needs to run after mobs are spawned
powerUps.spawn(1900, -940, "heal"); powerUps.spawn(1900, -940, "heal");
powerUps.spawn(3000, -230, "heal"); powerUps.spawn(3000, -230, "heal");
@@ -3815,7 +3805,7 @@ const level = {
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
//chance to spawn a ring of exploding mobs around this boss //chance to spawn a ring of exploding mobs around this boss
if (simulation.difficulty > 4) spawn.nodeBoss(2330, 1850, "spawns", 8, 20, 105); if (simulation.difficulty > 4) spawn.nodeGroup(2330, 1850, "spawns", 8, 20, 105);
powerUps.chooseRandomPowerUp(3100, 1630); powerUps.chooseRandomPowerUp(3100, 1630);
}, },
detours() { detours() {
@@ -3958,7 +3948,7 @@ const level = {
spawn.randomSmallMob(2800, -1620, 0.7); spawn.randomSmallMob(2800, -1620, 0.7);
spawn.randomMob(2400, -1370, 0.5); spawn.randomMob(2400, -1370, 0.5);
spawn.randomMob(3725, -1320, 0.3); spawn.randomMob(3725, -1320, 0.3);
spawn.randomBoss(2115, -2020, 0.1) spawn.randomGroup(2115, -2020, 0.1)
powerUps.spawn(5000, -1275, "heal"); powerUps.spawn(5000, -1275, "heal");
@@ -4078,7 +4068,7 @@ const level = {
spawn.randomMob(1500, -270, 0.2); spawn.randomMob(1500, -270, 0.2);
spawn.randomMob(1250, 55, 0.2); spawn.randomMob(1250, 55, 0.2);
spawn.randomMob(8800, -45, 0.2); spawn.randomMob(8800, -45, 0.2);
spawn.randomBoss(8025, -845, 0.2); spawn.randomGroup(8025, -845, 0.2);
if (simulation.difficulty > 2) { if (simulation.difficulty > 2) {
if (Math.random() < 0.2) { if (Math.random() < 0.2) {
@@ -4099,7 +4089,7 @@ const level = {
stiffness: 0.00015 stiffness: 0.00015
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
if (simulation.difficulty > 4) spawn.nodeBoss(8000, 630, "spawns", 8, 20, 105); if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105);
} else { } else {
spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss"]); spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss"]);
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
@@ -4664,16 +4654,16 @@ const level = {
spawn.randomMob(3965, -1650, 0.6) spawn.randomMob(3965, -1650, 0.6)
spawn.randomMob(4650, -1750, 0.6); spawn.randomMob(4650, -1750, 0.6);
spawn.randomMob(830, -1170, 0.5); spawn.randomMob(830, -1170, 0.5);
spawn.randomBoss(3730, -1100, 0.5); spawn.randomGroup(3730, -1100, 0.5);
spawn.randomMob(2650, -2250, 0.3); spawn.randomMob(2650, -2250, 0.3);
spawn.randomMob(1615, -2270, 0.3); spawn.randomMob(1615, -2270, 0.3);
spawn.randomMob(1380, -1280, 0.25); spawn.randomMob(1380, -1280, 0.25);
spawn.randomMob(2280, -650, 0.2); spawn.randomMob(2280, -650, 0.2);
spawn.randomBoss(2450, -2650, 0.2); spawn.randomGroup(2450, -2650, 0.2);
spawn.randomMob(3800, -580, 0.2); spawn.randomMob(3800, -580, 0.2);
spawn.randomMob(4630, -425, 0.1); spawn.randomMob(4630, -425, 0.1);
spawn.randomBoss(630, -1300, -0.1); spawn.randomGroup(630, -1300, -0.1);
spawn.randomBoss(3450, -2880, -0.2) spawn.randomGroup(3450, -2880, -0.2)
if (simulation.difficulty > 3) { if (simulation.difficulty > 3) {
if (Math.random() < 0.16) { if (Math.random() < 0.16) {
@@ -4687,7 +4677,7 @@ const level = {
stiffness: 0.00018 + 0.000007 * level.levelsCleared stiffness: 0.00018 + 0.000007 * level.levelsCleared
}); });
World.add(engine.world, cons[cons.length - 1]); World.add(engine.world, cons[cons.length - 1]);
if (simulation.difficulty > 4) spawn.nodeBoss(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss if (simulation.difficulty > 4) spawn.nodeGroup(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss
} else { } else {
spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "snakeBoss", "laserBoss"]); spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "snakeBoss", "laserBoss"]);

View File

@@ -128,14 +128,12 @@ const lore = {
requestAnimationFrame(cycle); requestAnimationFrame(cycle);
}, delay); }, delay);
}, },
// () => { () => {
// let delay = 2000 let delay = 6000
// setTimeout(() => { lore.miriam.text("testing speech generation for lore level", true) }, delay); setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.", true) }, delay);
// delay += 2200 delay += 2700
// setTimeout(() => { lore.anand.text("well, I'm also testing speech synthesis. Do you think it sounds good?", true) }, delay);
// delay += 4600 },
// setTimeout(() => { lore.miriam.text("I guess it's fine.", true) }, delay);
// },
], ],
dialogue: [ dialogue: [
``, ``,

View File

@@ -410,7 +410,7 @@ const mobs = {
// } // }
// }, // },
laserBeam() { laserBeam() {
if (simulation.cycle % 7 && this.seePlayer.yes) { if (this.seePlayer.yes) {
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
// ctx.lineDashOffset = 6*(simulation.cycle % 215); // ctx.lineDashOffset = 6*(simulation.cycle % 215);
if (this.distanceToPlayer() < this.laserRange) { if (this.distanceToPlayer() < this.laserRange) {

View File

@@ -638,9 +638,7 @@ const m = {
tech.isDeathAvoidedThisLevel = true tech.isDeathAvoidedThisLevel = true
powerUps.research.changeRerolls(-1) powerUps.research.changeRerolls(-1)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span><span class='color-symbol'>--</span><br>${powerUps.research.count}`) simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span><span class='color-symbol'>--</span><br>${powerUps.research.count}`)
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x, m.pos.y, "heal", false);
powerUps.spawn(m.pos.x, m.pos.y, "heal", false);
}
m.energy = m.maxEnergy m.energy = m.maxEnergy
m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds
simulation.wipe = function() { //set wipe to have trails simulation.wipe = function() { //set wipe to have trails
@@ -1170,14 +1168,12 @@ const m = {
}, },
pushMass(who) { pushMass(who) {
const speed = Vector.magnitude(Vector.sub(who.velocity, player.velocity)) const speed = Vector.magnitude(Vector.sub(who.velocity, player.velocity))
const fieldBlockCost = (0.03 + Math.sqrt(who.mass) * speed * 0.003) * m.fieldShieldingScale; const fieldBlockCost = (0.025 + Math.sqrt(who.mass) * speed * 0.002) * m.fieldShieldingScale;
const unit = Vector.normalise(Vector.sub(player.position, who.position)) const unit = Vector.normalise(Vector.sub(player.position, who.position))
if (m.energy > fieldBlockCost * 0.2) { //shield needs at least some of the cost to block if (m.energy > fieldBlockCost * 0.2) { //shield needs at least some of the cost to block
m.energy -= fieldBlockCost m.energy -= fieldBlockCost
if (m.energy < 0) { if (m.energy < 0) m.energy = 0;
m.energy = 0;
}
// if (m.energy > m.maxEnergy) m.energy = m.maxEnergy; // if (m.energy > m.maxEnergy) m.energy = m.maxEnergy;
if (tech.blockDmg) { if (tech.blockDmg) {
@@ -1396,11 +1392,11 @@ const m = {
}, },
{ {
name: "standing wave harmonics", name: "standing wave harmonics",
description: "<strong>3</strong> oscillating <strong>shields</strong> are permanently active<br><strong>blocking</strong> drains <strong class='color-f'>energy</strong> with no <strong>cool down</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>15%</strong>", description: "<strong>3</strong> oscillating <strong>shields</strong> are permanently active<br><strong>blocking</strong> drains <strong class='color-f'>energy</strong> with no <strong>cool down</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>20%</strong>",
effect: () => { effect: () => {
// m.fieldHarmReduction = 0.80; // m.fieldHarmReduction = 0.80;
m.fieldBlockCD = 0; m.fieldBlockCD = 0;
m.fieldHarmReduction = 0.85; m.fieldHarmReduction = 0.8;
m.hold = function() { m.hold = function() {
if (m.isHolding) { if (m.isHolding) {
m.drawHold(m.holdingTarget); m.drawHold(m.holdingTarget);
@@ -1554,13 +1550,13 @@ const m = {
}, },
{ {
name: "negative mass field", name: "negative mass field",
description: "use <strong class='color-f'>energy</strong> to nullify &nbsp;<strong style='letter-spacing: 7px;'>gravity</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>45%</strong><br><strong>blocks</strong> held by the field have a lower <strong>mass</strong>", description: "use <strong class='color-f'>energy</strong> to nullify &nbsp;<strong style='letter-spacing: 7px;'>gravity</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>50%</strong><br><strong>blocks</strong> held by the field have a lower <strong>mass</strong>",
fieldDrawRadius: 0, fieldDrawRadius: 0,
effect: () => { effect: () => {
m.fieldFire = true; m.fieldFire = true;
m.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping m.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping
m.fieldMeterColor = "#000" m.fieldMeterColor = "#000"
m.fieldHarmReduction = 0.55; m.fieldHarmReduction = 0.5;
m.fieldDrawRadius = 0; m.fieldDrawRadius = 0;
m.hold = function() { m.hold = function() {

View File

@@ -38,13 +38,15 @@ const powerUps = {
if (isCanceled) { if (isCanceled) {
if (tech.isCancelDuplication) tech.cancelCount++ if (tech.isCancelDuplication) tech.cancelCount++
if (tech.isCancelRerolls) { if (tech.isCancelRerolls) {
for (let i = 0; i < 6; i++) {
let spawnType = (m.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo" let spawnType = (m.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo"
if (Math.random() < 0.33) { if (Math.random() < 0.33) {
spawnType = "heal" spawnType = "heal"
} else if (Math.random() < 0.5 && !tech.isSuperDeterminism) { } else if (Math.random() < 0.5 && !tech.isSuperDeterminism) {
spawnType = "research" spawnType = "research"
} }
for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false); powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false);
}
} }
if (tech.isBanish && type === 'tech') { // banish researched tech by adding them to the list of banished tech if (tech.isBanish && type === 'tech') { // banish researched tech by adding them to the list of banished tech
const banishLength = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 const banishLength = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2
@@ -469,7 +471,7 @@ const powerUps = {
if (tech.isTechDamage && who.name === "tech") m.damage(0.11) if (tech.isTechDamage && who.name === "tech") m.damage(0.11)
if (tech.isMassEnergy) m.energy += 2.5; if (tech.isMassEnergy) m.energy += 2.5;
if (tech.isMineDrop) { if (tech.isMineDrop) {
if (tech.isLaserMine) { //laser mine if (tech.isLaserMine) {
b.laserMine(who.position) b.laserMine(who.position)
} else { } else {
b.mine(who.position, { x: 0, y: 0 }, 0, tech.isMineAmmoBack) b.mine(who.position, { x: 0, y: 0 }, 0, tech.isMineAmmoBack)
@@ -498,7 +500,7 @@ const powerUps = {
powerUps.spawn(x, y, "gun"); powerUps.spawn(x, y, "gun");
return; return;
} }
if (Math.random() < 0.0027 * (25 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 15 if (Math.random() < 0.0027 * (25 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 25
powerUps.spawn(x, y, "tech"); powerUps.spawn(x, y, "tech");
return; return;
} }
@@ -559,10 +561,8 @@ const powerUps = {
if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech") if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech")
//bonus power ups for clearing runs in the last game //bonus power ups for clearing runs in the last game
if (level.levelsCleared === 0 && !simulation.isCheating) { if (level.levelsCleared === 0 && !simulation.isCheating && localSettings.levelsClearedLastGame > 1) {
for (let i = 0; i < localSettings.levelsClearedLastGame / 4 - 1; i++) { for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game
powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game
}
localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} }

View File

@@ -21,7 +21,7 @@ const spawn = {
"ghoster", "ghoster",
"sneaker", "sneaker",
], ],
allowedBossList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper"], allowedGroupList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper"],
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);
@@ -47,41 +47,41 @@ const spawn = {
} }
} }
}, },
randomBoss(x, y, chance = 1) { randomGroup(x, y, chance = 1) {
if (spawn.spawnChance(chance) && simulation.difficulty > 2 || chance == Infinity) { if (spawn.spawnChance(chance) && simulation.difficulty > 2 || chance == Infinity) {
//choose from the possible picklist //choose from the possible picklist
let pick = this.pickList[Math.floor(Math.random() * this.pickList.length)]; let pick = this.pickList[Math.floor(Math.random() * this.pickList.length)];
//is the pick able to be a boss? //is the pick able to be a group?
let canBeBoss = false; let canBeGroup = false;
for (let i = 0, len = this.allowedBossList.length; i < len; ++i) { for (let i = 0, len = this.allowedGroupList.length; i < len; ++i) {
if (this.allowedBossList[i] === pick) { if (this.allowedGroupList[i] === pick) {
canBeBoss = true; canBeGroup = true;
break; break;
} }
} }
if (canBeBoss) { if (canBeGroup) {
if (Math.random() < 0.55) { if (Math.random() < 0.55) {
this.nodeBoss(x, y, pick); this.nodeGroup(x, y, pick);
} else { } else {
this.lineBoss(x, y, pick); this.lineGroup(x, y, pick);
} }
} else { } else {
if (Math.random() < 0.07) { if (Math.random() < 0.07) {
this[pick](x, y, 90 + Math.random() * 40); //one extra large mob this[pick](x, y, 90 + Math.random() * 40); //one extra large mob
} else if (Math.random() < 0.35) { } else if (Math.random() < 0.35) {
this.groupBoss(x, y) //hidden grouping blocks this.blockGroup(x, y) //hidden grouping blocks
} else { } else {
pick = (Math.random() < 0.5) ? "randomList" : "random"; pick = (Math.random() < 0.5) ? "randomList" : "random";
if (Math.random() < 0.55) { if (Math.random() < 0.55) {
this.nodeBoss(x, y, pick); this.nodeGroup(x, y, pick);
} else { } else {
this.lineBoss(x, y, pick); this.lineGroup(x, y, pick);
} }
} }
} }
} }
}, },
randomLevelBoss(x, y, options = ["shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"]) { randomLevelBoss(x, y, options = ["historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"]) {
// other bosses: suckerBoss, laserBoss, tetherBoss, //all need a particular level to work so they are not included // other bosses: suckerBoss, laserBoss, tetherBoss, //all need a particular level to work so they are not included
spawn[options[Math.floor(Math.random() * options.length)]](x, y) spawn[options[Math.floor(Math.random() * options.length)]](x, y)
}, },
@@ -297,7 +297,7 @@ const spawn = {
//when player is inside event horizon //when player is inside event horizon
if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
if (m.energy > 0) m.energy -= 0.01 if (m.energy > 0) m.energy -= 0.01
if (m.energy < 0.15) { if (m.energy < 0.15 && m.immuneCycle < m.cycle) {
m.damage(0.0004 * simulation.dmgScale); m.damage(0.0004 * simulation.dmgScale);
} }
const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
@@ -443,7 +443,7 @@ const spawn = {
} }
} }
}, },
groupBoss(x, y, num = 3 + Math.random() * 8) { blockGroup(x, y, num = 3 + Math.random() * 8) {
for (let i = 0; i < num; i++) { for (let i = 0; i < num; i++) {
const radius = 25 + Math.floor(Math.random() * 20) const radius = 25 + Math.floor(Math.random() * 20)
spawn.grouper(x + Math.random() * radius, y + Math.random() * radius, radius); spawn.grouper(x + Math.random() * radius, y + Math.random() * radius, radius);
@@ -875,7 +875,7 @@ const spawn = {
//when player is inside event horizon //when player is inside event horizon
if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
if (m.energy > 0) m.energy -= 0.004 if (m.energy > 0) m.energy -= 0.004
if (m.energy < 0.1) { if (m.energy < 0.1 && m.immuneCycle < m.cycle) {
m.damage(0.00015 * simulation.dmgScale); m.damage(0.00015 * simulation.dmgScale);
} }
const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
@@ -981,7 +981,7 @@ const spawn = {
//when player is inside event horizon //when player is inside event horizon
if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) { if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
if (m.energy > 0) m.energy -= 0.006 if (m.energy > 0) m.energy -= 0.006
if (m.energy < 0.1) { if (m.energy < 0.1 && m.immuneCycle < m.cycle) {
m.damage(0.0002 * simulation.dmgScale); m.damage(0.0002 * simulation.dmgScale);
} }
const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
@@ -1065,7 +1065,7 @@ const spawn = {
const nodes = 6 const nodes = 6
const angle = 2 * Math.PI / nodes const angle = 2 * Math.PI / nodes
spawn.allowShields = false; //don't want shields on individual boss mobs spawn.allowShields = false; //don't want shields on individual mobs
for (let i = 0; i < nodes; ++i) { for (let i = 0; i < nodes; ++i) {
spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12); spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12);
@@ -1086,7 +1086,7 @@ const spawn = {
World.add(engine.world, consBB[consBB.length - 1]); World.add(engine.world, consBB[consBB.length - 1]);
} }
//spawn shield around all nodes //spawn shield around all nodes
spawn.bossShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25); spawn.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
spawn.allowShields = true; spawn.allowShields = true;
}, },
timeSkipBoss(x, y, radius = 55) { timeSkipBoss(x, y, radius = 55) {
@@ -1185,10 +1185,96 @@ const spawn = {
this.checkStatus(); this.checkStatus();
this.attraction(); this.attraction();
this.repulsion(); this.repulsion();
//laser beam
this.laserBeam(); this.laserBeam();
}; };
}, },
historyBoss(x, y, radius = 30) {
if (tech.dynamoBotCount > 0) {
spawn.randomLevelBoss(x, y, ["cellBossCulture", "bomberBoss", "powerUpBoss"])
return
}
mobs.spawn(x, y, 0, radius, "transparent");
let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.3); //extra dense //normal is 0.001
me.laserRange = 550;
me.seeAtDistance2 = 2000000;
me.showHealthBar = false; //drawn in this.awake
me.delayLimit = 60 + Math.floor(60 * Math.random());
me.followDelay = 600 - Math.floor(60 * Math.random())
me.stroke = "transparent"; //used for drawGhost
me.collisionFilter.mask = cat.bullet
me.memory = Infinity
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.awake = function() {
this.checkStatus();
//health bar needs to be here because the position is being set
const h = this.radius * 0.3;
const w = this.radius * 2;
const x = this.position.x - w / 2;
const y = this.position.y - w * 0.7;
ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
ctx.fillRect(x, y, w, h);
ctx.fillStyle = "rgba(150,0,255,0.7)";
ctx.fillRect(x, y, w * this.health, h);
//draw eye
const unit = Vector.normalise(Vector.sub(m.pos, this.position))
const eye = Vector.add(Vector.mult(unit, 15), this.position)
ctx.beginPath();
ctx.arc(eye.x, eye.y, 4, 0, 2 * Math.PI);
ctx.moveTo(this.position.x + 20 * unit.x, this.position.y + 20 * unit.y);
ctx.lineTo(this.position.x + 30 * unit.x, this.position.y + 30 * unit.y);
ctx.strokeStyle = this.stroke;
ctx.lineWidth = 2;
ctx.stroke();
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
// ctx.lineDashOffset = 6*(simulation.cycle % 215);
if (this.distanceToPlayer() < this.laserRange) {
if (m.energy > 0.003) m.energy -= 0.003
if (m.immuneCycle < m.cycle && m.energy < 0.1) m.damage(0.0003 * simulation.dmgScale);
ctx.beginPath();
ctx.moveTo(eye.x, eye.y);
ctx.lineTo(m.pos.x, m.pos.y);
ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(150,0,255)";
ctx.stroke();
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
ctx.fillStyle = "rgba(150,0,255,0.15)";
ctx.fill();
}
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.laserRange * 0.9, 0, 2 * Math.PI);
ctx.strokeStyle = "rgba(150,0,255,0.5)";
ctx.lineWidth = 1;
ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = "rgba(150,0,255,0.03)";
ctx.fill();
if (!m.isBodiesAsleep && !this.isStunned && !this.isSlowed) {
if (this.followDelay > this.delayLimit) this.followDelay -= 0.2;
let history = m.history[(m.cycle - Math.floor(this.followDelay)) % 600]
Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
}
}
me.do = function() {
if (this.seePlayer.recall || (!(simulation.cycle % this.seePlayerFreq) && this.distanceToPlayer2() < this.seeAtDistance2 && !m.isCloak)) {
setTimeout(() => {
this.do = this.awake
this.stroke = "rgba(205,0,255,0.5)"
this.fill = "rgba(205,0,255,0.1)"
this.seePlayer.yes = true
}, 2000);
}
this.checkStatus();
};
},
focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) { focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) {
radius = Math.ceil(radius * 0.7); radius = Math.ceil(radius * 0.7);
mobs.spawn(x, y, 4, radius, "rgb(0,0,255)"); mobs.spawn(x, y, 4, radius, "rgb(0,0,255)");
@@ -2403,8 +2489,8 @@ const spawn = {
//snake tail //snake tail
const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40) const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40)
spawn.lineBoss(x + 105, y, "snakeBody", nodes); spawn.lineGroup(x + 105, y, "snakeBody", nodes);
//constraint boss with first 3 mobs in lineboss //constraint with first 3 mobs in line
consBB[consBB.length] = Constraint.create({ consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes], bodyA: mob[mob.length - nodes],
bodyB: mob[mob.length - 1 - nodes], bodyB: mob[mob.length - 1 - nodes],
@@ -2520,7 +2606,7 @@ const spawn = {
}; };
} }
}, },
bossShield(targets, x, y, radius, stiffness = 0.4) { groupShield(targets, x, y, radius, stiffness = 0.4) {
const nodes = targets.length const nodes = targets.length
mobs.spawn(x, y, 9, radius, "rgba(220,220,255,0.9)"); mobs.spawn(x, y, 9, radius, "rgba(220,220,255,0.9)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
@@ -2532,7 +2618,7 @@ const spawn = {
me.collisionFilter.mask = cat.bullet; me.collisionFilter.mask = cat.bullet;
for (let i = 0; i < nodes; ++i) { for (let i = 0; i < nodes; ++i) {
mob[mob.length - i - 2].isShielded = true; mob[mob.length - i - 2].isShielded = true;
//constrain to all mob nodes in boss //constrain to all mob nodes in group
consBB[consBB.length] = Constraint.create({ consBB[consBB.length] = Constraint.create({
bodyA: me, bodyA: me,
bodyB: mob[mob.length - i - 2], bodyB: mob[mob.length - i - 2],
@@ -2567,7 +2653,7 @@ const spawn = {
//complex constrained mob templates********************************************************************** //complex constrained mob templates**********************************************************************
//******************************************************************************************************* //*******************************************************************************************************
allowShields: true, allowShields: true,
nodeBoss( nodeGroup(
x, x,
y, y,
spawn = "striker", spawn = "striker",
@@ -2577,7 +2663,7 @@ const spawn = {
sideLength = Math.ceil(Math.random() * 100) + 70, // distance between each node mob sideLength = Math.ceil(Math.random() * 100) + 70, // distance between each node mob
stiffness = Math.random() * 0.03 + 0.005 stiffness = Math.random() * 0.03 + 0.005
) { ) {
this.allowShields = false; //don't want shields on individual boss mobs this.allowShields = false; //don't want shields on individual group mobs
const angle = 2 * Math.PI / nodes const angle = 2 * Math.PI / nodes
let targets = [] let targets = []
for (let i = 0; i < nodes; ++i) { for (let i = 0; i < nodes; ++i) {
@@ -2588,20 +2674,20 @@ const spawn = {
whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)]; whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)];
} }
this[whoSpawn](x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius); this[whoSpawn](x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius);
targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields targets.push(mob[mob.length - 1].id) //track who is in the group, for shields
} }
if (Math.random() < 0.3) { if (Math.random() < 0.3) {
this.constrain2AdjacentMobs(nodes, stiffness * 2, true); this.constrain2AdjacentMobs(nodes, stiffness * 2, true);
} else { } else {
this.constrainAllMobCombos(nodes, stiffness); this.constrainAllMobCombos(nodes, stiffness);
} }
//spawn shield for entire boss //spawn shield for entire group
if (nodes > 2 && Math.random() < 0.998) { if (nodes > 2 && Math.random() < 0.998) {
this.bossShield(targets, x, y, sideLength + 2.5 * radius + nodes * 6 - 25); this.groupShield(targets, x, y, sideLength + 2.5 * radius + nodes * 6 - 25);
} }
this.allowShields = true; this.allowShields = true;
}, },
lineBoss( lineGroup(
x, x,
y, y,
spawn = "striker", spawn = "striker",
@@ -2611,7 +2697,7 @@ const spawn = {
l = Math.ceil(Math.random() * 80) + 30, l = Math.ceil(Math.random() * 80) + 30,
stiffness = Math.random() * 0.06 + 0.01 stiffness = Math.random() * 0.06 + 0.01
) { ) {
this.allowShields = false; //don't want shields on individual boss mobs this.allowShields = false; //don't want shields on individual group mobs
for (let i = 0; i < nodes; ++i) { for (let i = 0; i < nodes; ++i) {
let whoSpawn = spawn; let whoSpawn = spawn;
if (spawn === "random") { if (spawn === "random") {

View File

@@ -105,14 +105,14 @@ const tech = {
return dmg * tech.slowFire * tech.aimDamage return dmg * tech.slowFire * tech.aimDamage
}, },
duplicationChance() { duplicationChance() {
return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.04 + tech.duplicateChance + m.duplicateChance return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + m.duplicateChance
}, },
totalBots() { totalBots() {
return tech.dynamoBotCount + tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount return tech.dynamoBotCount + tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
}, },
tech: [{ tech: [{
name: "integrated armament", name: "integrated armament",
description: "increase <strong class='color-d'>damage</strong> by <strong>25%</strong><br>your inventory can only hold 1 <strong class='color-g'>gun</strong>", description: `increase <strong class='color-d'>damage</strong> by <strong>25%</strong><br>your inventory can only hold 1 <strong class='color-g'>gun</strong>`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -121,9 +121,17 @@ const tech = {
requires: "no more than 1 gun", requires: "no more than 1 gun",
effect() { effect() {
tech.isOneGun = true; tech.isOneGun = true;
//
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].name === "CPT gun") tech.tech[i].description = `adds the <strong>CPT</strong> <strong class='color-g'>gun</strong> to your inventory<br>it <strong>rewinds</strong> your <strong class='color-h'>health</strong>, <strong>velocity</strong>, and <strong>position</strong><br><div style = 'color: #f24'>replaces your current gun</div>`
}
}, },
remove() { remove() {
tech.isOneGun = false; tech.isOneGun = false;
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].name === "CPT gun") tech.tech[i].description = `adds the <strong>CPT</strong> <strong class='color-g'>gun</strong> to your inventory<br>it <strong>rewinds</strong> your <strong class='color-h'>health</strong>, <strong>velocity</strong>, and <strong>position</strong>`
}
} }
}, },
{ {
@@ -510,13 +518,13 @@ const tech = {
}, },
{ {
name: "iridium-192", name: "iridium-192",
description: "<strong class='color-e'>explosions</strong> release <strong class='color-p'>gamma radiation</strong><br><strong>60%</strong> more <strong class='color-d'>damage</strong> over 4 seconds", description: "<strong class='color-e'>explosions</strong> release <strong class='color-p'>gamma radiation</strong><br><strong>100%</strong> more <strong class='color-d'>damage</strong>, but over 4 seconds",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 return tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1)
}, },
requires: "an explosive damage source", requires: "an explosive damage source, not ammonium nitrate or nitroglycerin",
effect: () => { effect: () => {
tech.isExplodeRadio = true; tech.isExplodeRadio = true;
}, },
@@ -530,9 +538,9 @@ const tech = {
maxCount: 9, maxCount: 9,
count: 0, count: 0,
allowed() { allowed() {
return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1)
}, },
requires: "an explosive damage source", requires: "an explosive damage source, not iridium-192",
effect: () => { effect: () => {
tech.explosiveRadius += 0.2; tech.explosiveRadius += 0.2;
}, },
@@ -546,9 +554,9 @@ const tech = {
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1)
}, },
requires: "an explosive damage source", requires: "an explosive damage source, not iridium-192",
effect: () => { effect: () => {
tech.isSmallExplosion = true; tech.isSmallExplosion = true;
}, },
@@ -626,7 +634,7 @@ const tech = {
}, },
{ {
name: "impact shear", name: "impact shear",
description: "mobs release a <strong>nail</strong> when they <strong>die</strong><br>nails target nearby mobs", description: "mobs release a <strong>nail</strong> when they <strong>die</strong><br><em>nails target nearby mobs</em>",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
allowed() { allowed() {
@@ -1318,9 +1326,8 @@ const tech = {
document.getElementById("health").style.display = "inline" document.getElementById("health").style.display = "inline"
document.getElementById("health-bg").style.display = "inline" document.getElementById("health-bg").style.display = "inline"
document.getElementById("dmg").style.backgroundColor = "#f67"; document.getElementById("dmg").style.backgroundColor = "#f67";
m.health = Math.min(m.maxHealth, m.energy); m.health = Math.max(Math.min(m.maxHealth, m.energy), 0.1);
m.displayHealth(); m.displayHealth();
} }
}, },
{ {
@@ -1739,7 +1746,7 @@ const tech = {
} }
}, },
{ {
name: "Bayesian statistics", name: "stimulated emission",
description: "<strong>20%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>after a <strong>collision</strong>, eject <strong>1</strong> <strong class='color-m'>tech</strong>", description: "<strong>20%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>after a <strong>collision</strong>, eject <strong>1</strong> <strong class='color-m'>tech</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -1756,24 +1763,60 @@ const tech = {
if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal
} }
}, },
// {
// name: "stimulated emission",
// description: "<strong>6%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><em>duplication chance can't exceed 100%</em>",
// maxCount: 9,
// count: 0,
// allowed() {
// return tech.duplicationChance() < 1
// },
// requires: "below 100% duplication chance",
// effect() {
// tech.duplicateChance += 0.06
// simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw
// },
// remove() {
// tech.duplicateChance = 0
// if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal
// }
// },
{ {
name: "stimulated emission", name: "futures exchange",
description: "<strong>6%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><em>duplication chance can't exceed 100%</em>", description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>4.5%</strong> power up <strong class='color-dup'>duplication</strong> chance",
maxCount: 9, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return tech.duplicationChance() < 1 return tech.duplicationChance() < 1 && !tech.isDeterminism
}, },
requires: "below 100% duplication chance", requires: "below 100% duplication chance, not determinism",
effect() { effect() {
tech.duplicateChance += 0.06 tech.isCancelDuplication = true
tech.cancelCount = 0
simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw
}, },
remove() { remove() {
tech.duplicateChance = 0 tech.isCancelDuplication = false
// tech.cancelCount = 0
if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal
} }
}, },
{
name: "commodities exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns <strong>6</strong> <strong class='color-h'>heals</strong>, <strong class='color-g'>ammo</strong>, and <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
allowed() {
return tech.isCancelDuplication
},
requires: "futures exchange",
effect() {
tech.isCancelRerolls = true
},
remove() {
tech.isCancelRerolls = false
}
},
{ {
name: "correlated damage", name: "correlated damage",
description: "your chance to <strong class='color-dup'>duplicate</strong> power ups<br>increases your <strong class='color-d'>damage</strong> by the same percent", description: "your chance to <strong class='color-dup'>duplicate</strong> power ups<br>increases your <strong class='color-d'>damage</strong> by the same percent",
@@ -1796,7 +1839,7 @@ const tech = {
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return tech.duplicationChance() > 0.25 return tech.duplicationChance() > 0.2
}, },
requires: "some duplication chance", requires: "some duplication chance",
effect() { effect() {
@@ -1806,42 +1849,6 @@ const tech = {
tech.isDuplicateBoss = false; tech.isDuplicateBoss = false;
} }
}, },
{
name: "futures exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>4%</strong> power up <strong class='color-dup'>duplication</strong> chance",
maxCount: 1,
count: 0,
allowed() {
return tech.duplicationChance() < 1 && !tech.isDeterminism
},
requires: "below 100% duplication chance, not determinism",
effect() {
tech.isCancelDuplication = true
tech.cancelCount = 0
simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw
},
remove() {
tech.isCancelDuplication = false
// tech.cancelCount = 0
if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal
}
},
{
name: "commodities exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns <strong>6</strong> <strong class='color-h'>heals</strong>, <strong class='color-g'>ammo</strong>, or <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
allowed() {
return tech.duplicationChance() > 0 && !tech.isDeterminism
},
requires: "a chance to duplicate power ups, not determinism",
effect() {
tech.isCancelRerolls = true
},
remove() {
tech.isCancelRerolls = false
}
},
{ {
name: "exchange symmetry", name: "exchange symmetry",
description: "convert <strong>1</strong> a random <strong class='color-m'>tech</strong> into <strong>3</strong> new <strong class='color-g'>guns</strong><br><em>recursive tech lose all stacks</em>", description: "convert <strong>1</strong> a random <strong class='color-m'>tech</strong> into <strong>3</strong> new <strong class='color-g'>guns</strong><br><em>recursive tech lose all stacks</em>",
@@ -1974,7 +1981,7 @@ const tech = {
}, },
{ {
name: "dark patterns", name: "dark patterns",
description: "reduce combat <strong>difficulty</strong> by <strong>1 level</strong><br>add <strong>16</strong> junk <strong class='color-m'>tech</strong> to the potential pool", description: "reduce combat <strong>difficulty</strong> by <strong>1 level</strong><br>add <strong>several</strong> junk <strong class='color-m'>tech</strong> to the potential pool",
maxCount: 1, maxCount: 1,
isNonRefundable: true, isNonRefundable: true,
isCustomHide: true, isCustomHide: true,
@@ -2183,7 +2190,7 @@ const tech = {
//************************************************** //**************************************************
{ {
name: "CPT gun", name: "CPT gun",
description: "adds the <strong>CPT</strong> <strong class='color-g'>gun</strong> to your inventory<br>it <strong>rewinds</strong> your <strong class='color-h'>health</strong>, <strong>velocity</strong>, and <strong>position</strong>", description: `adds the <strong>CPT</strong> <strong class='color-g'>gun</strong> to your inventory<br>it <strong>rewinds</strong> your <strong class='color-h'>health</strong>, <strong>velocity</strong>, and <strong>position</strong>`,
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -3820,7 +3827,7 @@ const tech = {
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return m.fieldUpgrades[m.fieldMode].name === "plasma torch" return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
}, },
requires: "plasma torch", requires: "plasma torch",
effect() { effect() {
@@ -4123,6 +4130,7 @@ const tech = {
} }
], ],
addLoreTechToPool() { //adds lore tech to tech pool addLoreTechToPool() { //adds lore tech to tech pool
if (!simulation.isCheating) {
tech.tech.push({ tech.tech.push({
name: `undefined`, name: `undefined`,
description: `${lore.techCount+1}/10<br><em>add copies of <strong>this</strong> to the potential <strong class='color-m'>tech</strong> pool</em>`, description: `${lore.techCount+1}/10<br><em>add copies of <strong>this</strong> to the potential <strong class='color-m'>tech</strong> pool</em>`,
@@ -4150,6 +4158,7 @@ const tech = {
}, },
remove() {} remove() {}
}) })
}
}, },
junk: [ junk: [
// { // {
@@ -4474,7 +4483,7 @@ const tech = {
}, },
{ {
name: "quantum black hole", name: "quantum black hole",
description: "use all your <strong class='color-f'>energy</strong> to<br><strong>spawn</strong> inside the event horizon of a <strong>black hole boss</strong>", description: "use all your <strong class='color-f'>energy</strong> to <strong>spawn</strong> inside the event horizon of a huge <strong>black hole</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,

View File

@@ -636,8 +636,8 @@ summary {
} }
.junk { .junk {
background: hsl(255, 46%, 72%); background: hsl(254, 59%, 74%);
border-radius: 25%; border-radius: 35%;
/* animation: 3s linear infinite alternate pulse; */ /* animation: 3s linear infinite alternate pulse; */
} }

View File

@@ -1,12 +1,19 @@
******************************************************** NEXT PATCH ******************************************************** ******************************************************** NEXT PATCH ********************************************************
blocking uses 33% less energy
tech cloning requires > 25% dup chance, and is now only 2x (was 3x) your dup chance for a second boss tech: stimulated emission removed
playing with the 4 community levels now removes 4 random levels from the level list tech: Bayesian statistics renamed stimulated emission
tech: futures exchange gives 4.5% per cancel (up from 4%)
tech: dark patterns - reduce combat difficulty by 1 level and add 16 junk tech to the potential tech pool new level boss: follows you like the dynamo-bot, but is not friend
will not spawn if you have a dynamo-bot
(probably will be rebalanced in next patch)
******************************************************** BUGS ******************************************************** ******************************************************** BUGS ********************************************************
make mobs that spawn other mobs limit spawns to line of sight
orange mobs
(only once on my computer) once every 7 second check isn't running code (only once on my computer) once every 7 second check isn't running code
power ups don't teleport to exit power ups don't teleport to exit
complex spin statistics isn't activating complex spin statistics isn't activating
@@ -31,19 +38,29 @@ tech: dark patterns - reduce combat difficulty by 1 level and add 16 junk tech t
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************
reduce 3 difficulty, randomize all mods when you... tech: when you switch guns switch a random bot to a different bot. If the bot you had was upgraded the new one will be too.
take damage or switch all bots
switch guns
pick up a tech tech: buff block throwing
require +100% damage for blocks
works with pilot wave?
lore: a tutorial / lore intro
needs to be optional so it doesn't slow experienced players
put something on the intro map
maybe a button triggers something
tech: add an eject button for each power up in the pause menu
also list all bot types in pause menu
with option to eject?
add back in gamepad support add back in gamepad support
but does anyone care?
https://github.com/landgreen/landgreen.github.io/search?q=gamepadconnected https://github.com/landgreen/landgreen.github.io/search?q=gamepadconnected
mechanic: gain damage when there are fewer bullets mechanic: gain damage when there are fewer bullets
junk tech
switch input keys: left-right, up-down?
rename intro level to something lore related rename intro level to something lore related
give undefined tech different effects at different localSettings.loreCount values give undefined tech different effects at different localSettings.loreCount values
@@ -329,7 +346,7 @@ n-gon outreach ideas
******************************************************** LORE ******************************************************** ******************************************************** LORE ********************************************************
cool names for tech cool names for tech
strange loop, ansatz strange loop, ansatz, Bayesian statistics
voice singing with pitch? voice singing with pitch?
@@ -343,7 +360,12 @@ chapter 2: scientists verify that bot can really hear them
chapter 3: why is the bot attacking things? chapter 3: why is the bot attacking things?
player is the bot and also the mobs, and the levels. player is the entire simulation player is the bot and also the mobs, and the levels. player is the entire simulation
why is the player attacking itself? why is the player attacking itself?
learn console commands to manipulate the simulation learn console commands to manipulate the simulation?
unlock hard and why difficulty?
but what about easy?
maybe remove easy, and replace with a check box that makes the game easy, but in a different way
disable lore, but respawn on the level you die at?
chapter 4: why does the simulation exists? chapter 4: why does the simulation exists?
started to research new tech and test in a simulated world started to research new tech and test in a simulated world