another combo

tech: collimator - add 1 laser beam and align your diverging beams to be parallel
  requires diffraction grating

added secret pilot wave combo to make blocks
rewrote combo test algorithm to be more forgiving with pattern matching
  also extended combos test to arrow keys, not just WASD

cache 17->15x ammo
metamaterial cloaking 0.3->0.4x damage reduction while cloaked
boson composite drains more energy when passing through mobs
  scales with difficulty
subway level has 6->4 (5 on hard difficulty) stations
subway gives 1/3->1/5 interest per station

bug fixes
  Higgs skin removal fixed
  diaphragm skin removal fixed
This commit is contained in:
landgreen
2025-01-26 09:09:15 -08:00
parent c9a5ab91b8
commit 77e484c3d2
9 changed files with 183 additions and 69 deletions

BIN
img/collimator.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -7370,6 +7370,8 @@ const b = {
};
}
} else if (tech.beamCollimator) {
this.fire = this.fireSplitCollimator
} else if (tech.beamSplitter) {
this.fire = this.fireSplit
} else if (tech.historyLaser) {
@@ -7395,6 +7397,7 @@ const b = {
}, tech.laserDamage / b.fireCDscale * this.lensDamage);
}
},
firePulse() { },
fireSplit() {
const drain = tech.laserDrain / b.fireCDscale
@@ -7418,6 +7421,29 @@ const b = {
}
}
},
fireSplitCollimator() {
const drain = tech.laserDrain / b.fireCDscale
if (m.energy < drain) {
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
} else {
m.fireCDcycle = m.cycle
m.energy -= drain
const freq = 0.037
const len = tech.beamSplitter + 1
const phase = 2 * Math.PI / len
for (let i = 0; i < len; i++) {
if (Math.sin(m.cycle * freq + phase * (i) + Math.PI / 2) > 0 || !(m.cycle % 3)) ctx.globalAlpha = 0.35
const whereSweep = m.angle + (m.crouch ? 0.4 : 1) * (Math.sin(m.cycle * freq + phase * (i)))
const where = { x: m.pos.x + 30 * Math.cos(whereSweep), y: m.pos.y + 30 * Math.sin(whereSweep) }
b.laser(where, {
x: where.x + 5000 * Math.cos(m.angle),
y: where.y + 5000 * Math.sin(m.angle)
}, tech.laserDamage / b.fireCDscale * this.lensDamage);
ctx.globalAlpha = 1
}
}
},
fireWideBeam() {
const drain = tech.laserDrain / b.fireCDscale
if (m.energy < drain) {

View File

@@ -1176,6 +1176,7 @@ function openExperimentMenu() {
document.body.style.overflowX = "hidden";
document.getElementById("info").style.display = 'none'
build.reset();
}
//record settings so they can be reproduced in the experimental menu

View File

@@ -33,7 +33,7 @@ const level = {
// tech.tech[297].frequency = 100
// tech.addJunkTechToPool(0.5)
// m.couplingChange(10)
// m.setField("wormhole") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// m.setField("pilot wave") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// m.energy = 0
// powerUps.research.count = 3
// tech.isHookWire = true
@@ -50,8 +50,8 @@ const level = {
// requestAnimationFrame(() => { tech.giveTech("non-renewables") });
// tech.giveTech("dark matter")
// tech.addJunkTechToPool(0.5)
// for (let i = 0; i < 1; ++i) tech.giveTech("demineralization")
// for (let i = 0; i < 1; ++i) tech.giveTech("remineralization")
// for (let i = 0; i < 1; ++i) tech.giveTech("paradigm shift")
// for (let i = 0; i < 1; ++i) tech.giveTech("Higgs mechanism")
// m.skin.egg();
// for (let i = 0; i < 1; ++i) tech.giveTech("many-worlds")
// requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("quasiparticles") });
@@ -67,7 +67,7 @@ const level = {
// for (let i = 0; i < 10; ++i) spawn.starter(1900, -500)
// for (let i = 0; i < 1; i++) spawn.mantisBoss(1900, -500)
// for (let i = 0; i < 1; i++) spawn.softBoss(1900, -500)
// for (let i = 0; i < 1; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "entanglement");
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "gun");
// for (let i = 0; i < 100; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo");
@@ -175,7 +175,8 @@ const level = {
let rate = tech.interestRate
if (level.onLevel < level.levels.length - 1) {//make sure it's not on the lore level which has an undefined name
const levelName = level.levels[level.onLevel]
if (levelName === "final" || levelName === "subway") rate *= 1 / 3
if (levelName === "final") rate *= 1 / 3
if (levelName === "subway") rate *= 1 / 5
}
let ammoSum = 0
@@ -2754,6 +2755,11 @@ const level = {
Composite.add(engine.world, cons[cons.length - 1]);
}
},
// softBody(x, y, angle = 0, isAttached = true, len = 15, radius = 20, stiffness = 1, damping = 1) {
// https://github.com/liabru/matter-js/blob/master/examples/softBody.js
// https://brm.io/matter-js/docs/classes/Composites.html
// https://codepen.io/Shokeen/pen/EmOLJO?editors=0010
// },
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
@@ -3534,7 +3540,7 @@ const level = {
const stationList = [] //use to randomize station order
for (let i = 1, totalNumberOfStations = 10; i < totalNumberOfStations; ++i) stationList.push(i) //!!!! update station number when you add a new station
stationList.sort(() => Math.random() - 0.5);
stationList.splice(0, 3); //remove some stations to keep it to 4 stations
stationList.splice(0, simulation.difficultyMode > 4 ? 4 : 5); //remove some stations to keep it to 4 stations
stationList.unshift(0) //add index zero to the front of the array
let isExitOpen = false

View File

@@ -1088,7 +1088,7 @@ const lore = {
() => {
setTimeout(() => {
lore.anand.text("How ever it thinks it can learn, and I think we showed it that nonviolence is an option,")
lore.anand.text("How ever it thinks, it can learn, and I think we showed it that violence isn't the only option,")
}, 1000);
},
() => {

View File

@@ -3647,6 +3647,7 @@ const m = {
m.fieldUpgrades[index].effect();
simulation.inGameConsole(`<div class="circle-grid field"></div> &nbsp; <span class='color-var'>m</span>.setField("<strong class='color-text'>${m.fieldUpgrades[m.fieldMode].name}</strong>")<br>input.key.field<span class='color-symbol'>:</span> ["<span class='color-text'>MouseRight</span>"]`);
if (m.fieldMode === 4) simulation.inGameConsole(`simulation<span class='color-symbol'>.</span>molecularMode <span class='color-symbol'>=</span> ${m.fieldUpgrades[4].modeText()} &nbsp; &nbsp; <em style="float: right;font-family: monospace;font-size: 1rem;color: #055;">↓↘→↓↙←↑↑↓</em>`);
if (m.fieldMode === 8) simulation.inGameConsole(`Composite<span class='color-symbol'>.</span>add<span class='color-symbol'>(</span>engine.world<span class='color-symbol'>,</span> block<span class='color-symbol'>)</span> &nbsp; &nbsp; <em style ="float: right; font-family: monospace;font-size:1rem;color:#055;">//↓↓→↘↓↙←↓↓</em>`);
},
fieldEvent: null,
fieldUpgrades: [
@@ -4209,43 +4210,23 @@ const m = {
setDescription() {
return `use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br>excess <strong class='color-f'>energy</strong> used to <strong class='color-print'>print</strong> ${simulation.molecularMode === 0 ? "<strong class='color-p' style='letter-spacing: 2px;'>spores" : simulation.molecularMode === 1 ? "<strong>missiles" : simulation.molecularMode === 2 ? "<strong class='color-s'>ice IX" : "<strong>drones"}</strong><br><strong>12</strong> <strong class='color-f'>energy</strong> per second <em style ="float: right; font-family: monospace;font-size:1rem;color:#fff;">↓↘→↓↙←↑↑↓</em>`
},
keyLog: [],
keyLog: [null, null, null, null, null, null, null],
effect: () => {
//store event function so it can be found and removed in m.setField()
m.fieldEvent = function (event) {
m.fieldUpgrades[4].keyLog.push(event.code)
// Helper function to compare arrays
function arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
const pattern = [input.key.down, input.key.right, input.key.down, input.key.left, input.key.up, input.key.up, input.key.down]
//check if the newest key press is correct
if (event.code !== pattern[m.fieldUpgrades[4].keyLog.length - 1]) {
m.fieldUpgrades[4].keyLog = [] //pattern is wrong, reset log
} else if (arraysEqual(m.fieldUpgrades[4].keyLog, pattern)) { //pattern is complete
m.fieldUpgrades[4].keyLog.shift() //remove first element
m.fieldUpgrades[4].keyLog.push(event.code) //add new key to end
const patternA = ["ArrowDown", "ArrowRight", "ArrowDown", "ArrowLeft", "ArrowUp", "ArrowUp", "ArrowDown"]
const patternB = [input.key.down, input.key.right, input.key.down, input.key.left, input.key.up, input.key.up, input.key.down]
const arraysEqual = (a, b) => a.length === b.length && a.every((val, i) => val === b[i]);
if (arraysEqual(m.fieldUpgrades[4].keyLog, patternA) || arraysEqual(m.fieldUpgrades[4].keyLog, patternB)) {
//cycle to next molecular mode
m.fieldUpgrades[4].keyLog = []
const energy = m.energy //save current energy
if (simulation.molecularMode < 3) {
simulation.molecularMode++
} else {
simulation.molecularMode = 0
}
// m.setField((m.fieldMode === m.fieldUpgrades.length - 1) ? 1 : m.fieldMode + 1) //cycle to next field, skip field emitter
simulation.molecularMode = simulation.molecularMode < 3 ? simulation.molecularMode + 1 : 0
m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription()
m.energy = energy //return to current energy
const name = `${simulation.molecularMode === 0 ? "<em class='color-p' style='letter-spacing: 2px;'>spores" : simulation.molecularMode === 1 ? "<em>missiles" : simulation.molecularMode === 2 ? "<em class='color-s'>ice IX" : "<em>drones"}</em>`
simulation.inGameConsole(`simulation<span class='color-symbol'>.</span>molecularMode <span class='color-symbol'>=</span> ${simulation.molecularMode} // ${name} &nbsp; <em style="float: right;font-family: monospace;font-size: 1rem;color: #055;">↓↘→↓↙←↑↑↓</em>`);
}
// console.log(m.fieldUpgrades[4].keyLog)
// console.log(event.code, m.fieldUpgrades[4].keyLog)
}
window.addEventListener("keydown", m.fieldEvent);
@@ -5019,7 +5000,7 @@ const m = {
},
{
name: "metamaterial cloaking",
description: `<strong>0.3x</strong> <strong class='color-defense'>damage taken</strong> while <strong class='color-cloaked'>cloaked</strong><br>after <strong class='color-cloaked'>decloaking</strong> <strong>4.5x</strong> <strong class='color-d'>damage</strong> for <strong>2</strong> s<br><strong>6</strong> <strong class='color-f'>energy</strong> per second`,
description: `<strong>0.4x</strong> <strong class='color-defense'>damage taken</strong> while <strong class='color-cloaked'>cloaked</strong><br>after <strong class='color-cloaked'>decloaking</strong> <strong>4.5x</strong> <strong class='color-d'>damage</strong> for <strong>2</strong> s<br><strong>6</strong> <strong class='color-f'>energy</strong> per second`,
effect: () => {
m.fieldFire = true;
m.fieldMeterColor = "#333";
@@ -5070,7 +5051,7 @@ const m = {
if (!m.isCloak) { //&& m.energy > drain + 0.03
// m.energy -= drain
m.isCloak = true //enter cloak
m.fieldHarmReduction = 0.3;
m.fieldHarmReduction = 0.4;
m.enterCloakCycle = m.cycle
if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy)
@@ -5151,8 +5132,8 @@ const m = {
if (inPlayer.length > 0) {
for (let i = 0; i < inPlayer.length; i++) {
if (m.energy > 0) {
if (!inPlayer[i].isUnblockable) m.energy -= 0.003;
if (inPlayer[i].shield) m.energy -= 0.011;
if (!inPlayer[i].isUnblockable) m.energy -= 0.004 + 0.0005 * simulation.difficultyMode;
if (inPlayer[i].shield) m.energy -= 0.015 + 0.001 * simulation.difficultyMode;
}
}
}
@@ -5180,8 +5161,65 @@ const m = {
},
{
name: "pilot wave",
description: `use <strong class='color-f'>energy</strong> to guide <strong class='color-block'>blocks</strong><br><div class="circle-grid tech"></div>, <div class="circle-grid gun"></div>, and <div class="circle-grid field"></div> have <strong>+3</strong> <strong class='color-choice'><span>ch</span><span>oi</span><span>ces</span></strong><br><strong>10</strong> <strong class='color-f'>energy</strong> per second`,
description: `use <strong class='color-f'>energy</strong> to guide <strong class='color-block'>blocks</strong><em style ="float: right; font-family: monospace;font-size:1rem;color:#fff;">↓↓→↘↓↙←↓↓</em><br><div class="circle-grid tech"></div>, <div class="circle-grid gun"></div>, and <div class="circle-grid field"></div> have <strong>+3</strong> <strong class='color-choice'><span>ch</span><span>oi</span><span>ces</span></strong><br><strong>10</strong> <strong class='color-f'>energy</strong> per second`,
keyLog: [null, null, null, null, null, null, null],
effect: () => {
//store event function so it can be found and removed in m.setField()
m.fieldEvent = function (event) {
m.fieldUpgrades[4].keyLog.shift() //remove first element
m.fieldUpgrades[4].keyLog.push(event.code) //add new key to end
const patternA = ["ArrowDown", "ArrowDown", "ArrowRight", "ArrowDown", "ArrowLeft", "ArrowDown", "ArrowDown"]
const patternB = [input.key.down, input.key.down, input.key.right, input.key.down, input.key.left, input.key.down, input.key.down]
const arraysEqual = (a, b) => a.length === b.length && a.every((val, i) => val === b[i]);
const where = {
x: m.pos.x,
y: m.pos.y - 75
}
if (
(arraysEqual(m.fieldUpgrades[4].keyLog, patternA) || arraysEqual(m.fieldUpgrades[4].keyLog, patternB))
&& !Matter.Query.point(map, where).length
) {
//remove old blocks
// for (let i = 0; i < body.length; i++) {
// if (body[i].isPilotWave) {
// Matter.Composite.remove(engine.world, body[i]);
// body.splice(i, 1);
// break
// }
// }
//spawn a block
const radius = 25 + Math.floor(15 * Math.random())
// body[body.length] = Matter.Bodies.polygon(simulation.mouseInGame.x, simulation.mouseInGame.y, 4, radius, {
body[body.length] = Matter.Bodies.polygon(where.x, where.y, 4 + Math.floor(4 * Math.random()), radius, {
friction: 0.05,
frictionAir: 0.001,
collisionFilter: {
category: cat.body,
mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
},
classType: "body",
isPilotWave: true,
});
const block = body[body.length - 1]
//mess with the block shape (this code is horrible)
Composite.add(engine.world, block); //add to world
const r1 = radius * (0.85 + 0.6 * Math.random())
const r2 = radius * (0.85 + 0.6 * Math.random())
let angle = Math.PI / 4
const vertices = []
for (let i = 0, len = block.vertices.length; i < len; i++) {
angle += 2 * Math.PI / len + 0.06 * Math.random()
vertices.push({ x: block.position.x + r1 * Math.cos(angle), y: block.position.y + r2 * Math.sin(angle) })
}
Matter.Body.setVertices(block, vertices)
/* <em style ="float: right; font-family: monospace;font-size:1rem;color:#fff;">↓↘→↓↙←↑↑↓</em> */
simulation.inGameConsole(`Composite<span class='color-symbol'>.</span>add<span class='color-symbol'>(</span>engine.world<span class='color-symbol'>,</span> block<span class='color-symbol'>)</span> &nbsp; &nbsp; <em style ="float: right; font-family: monospace;font-size:1rem;color:#fff;">//↓↓→↘↓↙←↓↓</em>`);
}
}
window.addEventListener("keydown", m.fieldEvent);
m.fieldMeterColor = "#333"
m.eyeFillColor = m.fieldMeterColor

View File

@@ -406,12 +406,13 @@ const tech = {
m.skin.strokeGap();
},
remove() {
tech.isFireMoveLock = false
if (tech.isFireMoveLock) {
tech.isFireMoveLock = false
b.setFireCD();
b.setFireMethod();
if (this.count) m.resetSkin();
m.resetSkin();
}
tech.isFireMoveLock = false
}
},
{
@@ -480,7 +481,10 @@ const tech = {
},
remove() {
tech.isDilate = false
if (this.count) m.resetSkin();
if (this.count) {
m.resetSkin();
if (tech.isDiaphragm) m.skin.dilate2()
}
}
},
{
@@ -490,7 +494,7 @@ const tech = {
count: 0,
frequency: 2,
frequencyDefault: 2,
isSkin: true,
// isSkin: true,
allowed() {
return tech.isDilate
},
@@ -502,7 +506,10 @@ const tech = {
},
remove() {
tech.isDiaphragm = false
if (this.count) m.resetSkin();
if (this.count) {
m.resetSkin();
if (tech.isDilate) m.skin.dilate()
}
}
},
{
@@ -1063,7 +1070,7 @@ const tech = {
{
name: "cache",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Cache_(computing)' class="link">cache</a>`,
description: `<strong>17x</strong> <strong class='color-ammo'>ammo</strong> per ${powerUps.orb.ammo()}, but<br>you can't <strong>store</strong> additional <strong class='color-ammo'>ammo</strong>`,
description: `<strong>15x</strong> <strong class='color-ammo'>ammo</strong> per ${powerUps.orb.ammo()}, but<br>you can't <strong>store</strong> additional <strong class='color-ammo'>ammo</strong>`,
maxCount: 1,
count: 0,
frequency: 1,
@@ -1073,7 +1080,7 @@ const tech = {
},
requires: "not non-renewables",
effect() {
tech.ammoCap = 17;
tech.ammoCap = 15;
powerUps.ammo.effect()
},
remove() {
@@ -7372,7 +7379,7 @@ const tech = {
requestAnimationFrame(() => {
let techGiven = 0
for (let j = 0; j < 3; j++) {
const names = ["quasiparticles", "lens", "compound lens", "arc length", "infrared diode", "free-electron laser", "dye laser", "relativistic momentum", "specular reflection", "diffraction grating", "diffuse beam", "output coupler", "slow light", "laser-bot", "laser-bot upgrade"]
const names = ["quasiparticles", "lens", "compound lens", "arc length", "infrared diode", "free-electron laser", "dye laser", "relativistic momentum", "specular reflection", "diffraction grating", "diffuse beam", "output coupler", "slow light", "laser-bot", "laser-bot upgrade", "collimator"]
//convert names into indexes
const options = []
for (let i = 0; i < names.length; i++) {
@@ -7514,7 +7521,7 @@ const tech = {
allowed() {
return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade || tech.isLaserField) && !tech.isWideLaser && !tech.isPulseLaser && !tech.historyLaser
},
requires: "laser, not diffuse beam, pulse, or slow light",
requires: "laser, not diffuse beam, pulse, slow light",
effect() {
tech.laserReflections += 2;
},
@@ -7533,7 +7540,7 @@ const tech = {
allowed() {
return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.historyLaser
},
requires: "laser gun, diffuse beam, or slow light",
requires: "laser gun, not diffuse beam, slow light",
effect() {
tech.beamSplitter++
b.guns[11].chooseFireMethod()
@@ -7545,6 +7552,29 @@ const tech = {
}
}
},
{
name: "collimator",
description: `<strong>+1</strong> <strong class='color-laser'>laser</strong> beam<br>align your diverging <strong class='color-laser'>laser</strong> beams to be <strong>parallel</strong>`,
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.historyLaser && tech.beamSplitter > 0 && !tech.isPulseLaser
},
requires: "laser gun, diffraction, not diffuse beam, slow light, pulse",
effect() {
tech.beamSplitter++
tech.beamCollimator = true
b.guns[11].chooseFireMethod()
},
remove() {
tech.beamCollimator = false
if (tech.beamSplitter > 0) tech.beamSplitter--
b.guns[11].chooseFireMethod()
}
},
{
name: "diffuse beam",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Diffuser_(optics)' class="link">diffuse beam</a>`,
@@ -7607,7 +7637,7 @@ const tech = {
allowed() {
return tech.haveGunCheck("laser") && !tech.beamSplitter && !tech.isWideLaser
},
requires: "laser gun, diffraction grating, diffuse beam",
requires: "laser gun, not diffraction grating, diffuse beam",
effect() {
tech.historyLaser++
b.guns[11].chooseFireMethod()
@@ -7657,8 +7687,8 @@ const tech = {
effect() {
tech.laserDrain *= 0.75
tech.laserDamage *= 1.25
tech.laserColor = "rgb(0, 11, 255)"
tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
tech.laserColor = "rgb(0, 40, 255)"
tech.laserColorAlpha = "rgba(0, 40, 255,0.5)"
},
remove() {
tech.laserDrain = 0.003;
@@ -7701,9 +7731,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDrain === 0.003 && !tech.isStuckOn
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDrain === 0.003 && !tech.isStuckOn && !tech.beamCollimator
},
requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier, collimator",
effect() {
tech.isPulseLaser = true;
b.guns[11].chooseFireMethod()
@@ -12319,4 +12349,5 @@ const tech = {
isDemineralize: null,
mineralDamage: null,
negativeMassCost: null,
beamCollimator: null,
}

View File

@@ -9,6 +9,7 @@ body {
margin: 0;
overflow: hidden;
cursor: auto;
background-color: #f00;
/* filter: grayscale(1); */
/* transition: background-color 0.2s ease-in-out; */
}

View File

@@ -1,17 +1,22 @@
******************************************************** NEXT PATCH **************************************************
mantisBoss flashes for a second before it drops invulnerability
removed parasitism - it's too similar to invulnerability tech
invariant no longer drains energy while wormhole time is paused
added 1 research cost
added secret combo to change molecular assembler mode
tech: collimator - add 1 laser beam and align your diverging beams to be parallel
requires diffraction grating
added secret pilot wave combo to make blocks
rewrote combo test algorithm to be more forgiving with pattern matching
also extended combos test to arrow keys, not just WASD
cache 17->15x ammo
metamaterial cloaking 0.3->0.4x damage reduction while cloaked
boson composite drains more energy when passing through mobs
scales with difficulty
subway level has 6->4 (5 on hard difficulty) stations
subway gives 1/3->1/5 interest per station
bug fixes
issue with constraint: "mob death heals mobs"
mob health was becoming NaN, this was infecting other values like player energy
entering a seed in settings wasn't giving the same results as a randomly generated seeds
also removed some random code that was using seeded shuffle, but didn't need to
converted it to non seeded random shuffle with .sort(() => Math.random() - 0.5);
Higgs skin removal fixed
diaphragm skin removal fixed
******************************************************** BUGS ********************************************************
@@ -19,9 +24,10 @@ player can become crouched while not touching the ground if they exit the ground
*********************************************************** TODO *****************************************************
soft body boss?
search softBody(x, y, angle = 0, isAttached = true, len = 15, radius = 20, stiffness = 1, damping = 1) {
use ←↑→↓↖↗↘↙ combos to allow fields to have special actions
!!should this be wasd, arrows, or both?
how to limit spam?
on cooldown
timer or once per level
@@ -40,8 +46,7 @@ use ←↑→↓↖↗↘↙ combos to allow fields to have special actions
plasma torch
time dilation
metamaterial cloaking
pilot wave
spawn blocks
pilot wave - done
wormhole
shoot out all the blocks that were sucked in this level (maybe cap at like 10?, cap with energy spent to fire)
are block sizes stored properly? because they shrink before they get eaten...
@@ -52,6 +57,12 @@ use ←↑→↓↖↗↘↙ combos to allow fields to have special actions
fire from player (and draw a wormhole looking graphic)
grappling hook
new level idea: large map sized blocks that can't be destroyed that the player walks on as a part of the level
eventually the blocks fall
after fall level progresses to a phase 2 to clean up the blocks or leave them
should bosses be killed by falling blocks??
how to avoid the large block vibrating/dancing on tiny block issue
new level idea: escort mission
player has to stay near something that moves slowly through the level
maybe only a zone around the escort is safe