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

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,
}