@@ -1162,7 +1199,7 @@ const powerUps = {
}
for (let i = 0; i < localSettings.entanglement.techIndexes.length; i++) { //add tech
let choose = localSettings.entanglement.techIndexes[i]
- const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
+ const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
if (choose === null || tech.tech[choose].count + 1 > tech.tech[choose].maxCount || !tech.tech[choose].allowed()) {
// text += `
${tech.tech[choose].name} - incoherent
`
diff --git a/js/simulation.js b/js/simulation.js
index 5844627..6dc83ed 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -1137,31 +1137,16 @@ const simulation = {
// },
checks() {
if (!(m.cycle % 15)) { //4 times a second
- //update defense bar
- const defense = m.defense()
+ const defense = m.defense() //update defense bar
if (m.lastCalculatedDefense !== defense) {
document.getElementById("defense-bar").style.width = Math.floor(300 * m.maxHealth * (1 - defense)) + "px";
-
- // if (m.lastCalculatedDefense === 1) document.getElementById("defense-bar").style.display = "inline"
- // if (defense === 1) document.getElementById("defense-bar").style.display = "none"
- // Math.pow(m.defense(), 0.13)
m.lastCalculatedDefense = defense
- // console.log(defense)
}
-
- //update damage bar
- const damage = tech.damageFromTech()
+ const damage = tech.damageFromTech() //update damage bar
if (m.lastCalculatedDamage !== damage) {
- canvas.width
- // document.getElementById("damage-bar").style.width = Math.floor(Math.atan(damage - 1) / 6.28 * canvas.width) + "px";
- document.getElementById("damage-bar").style.height = Math.floor(Math.atan(damage - 1) / 3.14 * canvas.height) + "px";
-
+ document.getElementById("damage-bar").style.height = Math.floor(Math.atan(0.25 * damage - 0.25) / 1.65 * canvas.height) + "px";
m.lastCalculatedDamage = damage
- console.log(damage)
}
-
-
-
}
if (!(m.cycle % 60)) { //once a second
//energy overfill
@@ -1211,7 +1196,17 @@ const simulation = {
if (isNaN(player.position.x)) m.death();
if (m.lastKillCycle + 300 > m.cycle) { //effects active for 5 seconds after killing a mob
if (tech.isEnergyRecovery && m.immuneCycle < m.cycle) m.energy += m.maxEnergy * 0.05
- if (tech.isHealthRecovery) m.addHealth(0.005 * m.maxHealth)
+ if (tech.isHealthRecovery) {
+ const heal = 0.005 * m.maxHealth
+ m.addHealth(heal)
+ simulation.drawList.push({ //add dmg to draw queue
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: Math.sqrt(heal) * 150,
+ color: "rgba(0,255,200,0.6)",
+ time: 8
+ });
+ }
}
if (!(m.cycle % 420)) { //once every 7 seconds
diff --git a/js/spawn.js b/js/spawn.js
index 5bfe02e..53e713b 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -239,10 +239,10 @@ const spawn = {
me.chaseSpeed = 3.3
me.isMACHO = true;
me.frictionAir = 0.006
- me.onDeath = function() {
+ me.onDeath = function () {
tech.isHarmMACHO = false;
}
- me.do = function() {
+ me.do = function () {
if (!simulation.isTimeSkipping) {
const sine = Math.sin(simulation.cycle * 0.015)
this.radius = 370 * (1 + 0.1 * sine)
@@ -300,7 +300,7 @@ const spawn = {
me.collisionFilter.mask = 0; //cat.player //| cat.body
me.chaseSpeed = 1.2 + 2.3 * Math.random()
- me.awake = function() {
+ me.awake = function () {
//chase player
const sub = Vector.sub(player.position, this.position)
const where = Vector.add(this.position, Vector.mult(Vector.normalise(sub), this.chaseSpeed))
@@ -334,7 +334,7 @@ const spawn = {
ctx.fill();
this.radius = 100 * (1 + 0.25 * Math.sin(simulation.cycle * 0.03))
}
- me.do = function() { //wake up after the player moves
+ me.do = function () { //wake up after the player moves
if (player.speed > 1 && !m.isCloak) {
if (this.distanceToPlayer() < 500) {
const unit = Vector.rotate({ x: 1, y: 0 }, Math.random() * 6.28)
@@ -375,7 +375,7 @@ const spawn = {
me.isInvulnerable = false
me.totalModes = 0
me.lastDamageCycle = 0
- me.onDamage = function() {
+ me.onDamage = function () {
this.lastDamageCycle = this.cycle
if (this.health < this.nextHealthThreshold) {
if (this.health === 1) me.cycle = 1; //reset fight
@@ -386,7 +386,7 @@ const spawn = {
this.damageReduction = 0
}
};
- me.invulnerable = function() {
+ me.invulnerable = function () {
if (this.isInvulnerable) {
this.invulnerableCount--
if (this.invulnerableCount < 0) {
@@ -407,17 +407,17 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 15 + 6 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
- ctx.fillStyle = `rgba(255,255,255,${Math.min(1, 120/(this.invulnerableCount+60))})`;
+ ctx.fillStyle = `rgba(255,255,255,${Math.min(1, 120 / (this.invulnerableCount + 60))})`;
ctx.fill()
}
}
- me.damageReductionDecay = function() { //slowly make the boss take more damage over time //damageReduction resets with each invulnerability phase
+ me.damageReductionDecay = function () { //slowly make the boss take more damage over time //damageReduction resets with each invulnerability phase
if (!(me.cycle % 60) && this.lastDamageCycle + 240 > this.cycle) this.damageReduction *= 1.02 //only decay once a second //only decay if the player has done damage in the last 4 seconds
}
me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]
- me.spawnMobs = function(index = 0) {
+ me.spawnMobs = function (index = 0) {
const vertex = me.vertices[index]
const unit = Vector.normalise(Vector.sub(me.position, vertex))
const where = Vector.add(vertex, Vector.mult(unit, -30))
@@ -427,271 +427,271 @@ const spawn = {
}
me.maxMobs = 400
me.mode = [{
- name: "boulders",
- spawnRate: 170 - 6 * simulation.difficultyMode,
- do() {
- if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
- me.boulder(me.position.x, me.position.y + 250)
- }
- },
- enter() {},
- exit() {},
- }, {
- name: "mobs",
- // whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
- spawnRate: 280 - 20 * simulation.difficultyMode,
- do() {
- if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
- me.torque += 0.000015 * me.inertia; //spin
- const index = Math.floor((me.cycle % (this.spawnRate * 6)) / this.spawnRate) //int from 0 to 5
- if (index === 0) me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; //fire a bullet from each vertex
- me.spawnMobs(index)
- // const vertex = me.vertices[index]
- // const unit = Vector.normalise(Vector.sub(me.position, vertex))
- // const where = Vector.add(vertex, Vector.mult(unit, -30))
- // spawn[me.mobType](where.x + 50 * (Math.random() - 0.5), where.y + 50 * (Math.random() - 0.5));
- // const velocity = Vector.mult(Vector.perp(unit), -18) //give the mob a rotational velocity as if they were attached to a vertex
- // Matter.Body.setVelocity(mob[mob.length - 1], { x: me.velocity.x + velocity.x, y: me.velocity.y + velocity.y });
- }
- },
- enter() {},
- exit() {},
+ name: "boulders",
+ spawnRate: 170 - 6 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
+ me.boulder(me.position.x, me.position.y + 250)
+ }
},
- {
- name: "hoppers",
- spawnRate: 480 - 16 * simulation.difficultyMode,
- do() {
- if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
- me.torque += 0.00002 * me.inertia; //spin
- for (let i = 0; i < 6; i++) {
- const vertex = me.vertices[i]
- spawn.hopBullet(vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5), 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
- Matter.Body.setDensity(mob[mob.length - 1], 0.002); //normal is 0.001
- const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(me.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex
- Matter.Body.setVelocity(mob[mob.length - 1], {
- x: me.velocity.x + velocity.x,
- y: me.velocity.y + velocity.y
- });
- }
- let where = { x: 600 - Math.random() * 100, y: -225 }
- if (simulation.isHorizontalFlipped) where.x = -600 + Math.random() * 100
- spawn.hopBullet(where.x, where.y, 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
+ enter() { },
+ exit() { },
+ }, {
+ name: "mobs",
+ // whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
+ spawnRate: 280 - 20 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
+ me.torque += 0.000015 * me.inertia; //spin
+ const index = Math.floor((me.cycle % (this.spawnRate * 6)) / this.spawnRate) //int from 0 to 5
+ if (index === 0) me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; //fire a bullet from each vertex
+ me.spawnMobs(index)
+ // const vertex = me.vertices[index]
+ // const unit = Vector.normalise(Vector.sub(me.position, vertex))
+ // const where = Vector.add(vertex, Vector.mult(unit, -30))
+ // spawn[me.mobType](where.x + 50 * (Math.random() - 0.5), where.y + 50 * (Math.random() - 0.5));
+ // const velocity = Vector.mult(Vector.perp(unit), -18) //give the mob a rotational velocity as if they were attached to a vertex
+ // Matter.Body.setVelocity(mob[mob.length - 1], { x: me.velocity.x + velocity.x, y: me.velocity.y + velocity.y });
+ }
+ },
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "hoppers",
+ spawnRate: 480 - 16 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
+ me.torque += 0.00002 * me.inertia; //spin
+ for (let i = 0; i < 6; i++) {
+ const vertex = me.vertices[i]
+ spawn.hopBullet(vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5), 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
Matter.Body.setDensity(mob[mob.length - 1], 0.002); //normal is 0.001
+ const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(me.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: me.velocity.x + velocity.x,
+ y: me.velocity.y + velocity.y
+ });
}
- },
- enter() {},
- exit() {},
+ let where = { x: 600 - Math.random() * 100, y: -225 }
+ if (simulation.isHorizontalFlipped) where.x = -600 + Math.random() * 100
+ spawn.hopBullet(where.x, where.y, 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
+ Matter.Body.setDensity(mob[mob.length - 1], 0.002); //normal is 0.001
+ }
},
- {
- name: "seekers",
- spawnRate: 100 - 3 * simulation.difficultyMode,
- do() {
- if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
- const index = Math.floor((me.cycle % 360) / 60)
- spawn.seeker(me.vertices[index].x, me.vertices[index].y, 18 * (0.5 + Math.random())); //seeker(x, y, radius = 8, sides = 6)
- const who = mob[mob.length - 1]
- Matter.Body.setDensity(who, 0.00003); //normal is 0.001
- who.timeLeft = 720 + 30 * simulation.difficulty //* (0.8 + 0.4 * Math.random());
- who.accelMag = 0.0004 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
- who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
- }
- },
- enter() {},
- exit() {},
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "seekers",
+ spawnRate: 100 - 3 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
+ const index = Math.floor((me.cycle % 360) / 60)
+ spawn.seeker(me.vertices[index].x, me.vertices[index].y, 18 * (0.5 + Math.random())); //seeker(x, y, radius = 8, sides = 6)
+ const who = mob[mob.length - 1]
+ Matter.Body.setDensity(who, 0.00003); //normal is 0.001
+ who.timeLeft = 720 + 30 * simulation.difficulty //* (0.8 + 0.4 * Math.random());
+ who.accelMag = 0.0004 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ }
},
- {
- name: "mines",
- bombCycle: 0,
- bombInterval: 10 - simulation.difficultyMode,
- do() {
- const yOff = 120
- this.bombCycle++
- if (!(this.bombCycle % this.bombInterval) && (this.bombCycle % 660) > 330) { //mines above player
- if (simulation.isHorizontalFlipped) {
- const x = m.pos.x + 200 * (Math.random() - 0.5)
- if (x > -750) { //mines above player IN tunnel
- spawn.mine(Math.min(Math.max(-730, x), 100), -450 - yOff * Math.random()) //player in main room
- mob[mob.length - 1].fallHeight = -209
- } else { //mines above player NOT in tunnel
- spawn.mine(Math.min(Math.max(-5375, x), -765), -1500 - yOff * Math.random()) //player in tunnel
- mob[mob.length - 1].fallHeight = -9
- }
- if (Math.random() < 0.5) {
- spawn.mine(-5350 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines
- mob[mob.length - 1].fallHeight = -9
- }
- } else {
- const x = m.pos.x + 200 * (Math.random() - 0.5)
- if (x < 750) { //mines above player IN tunnel
- spawn.mine(Math.min(Math.max(-100, x), 735), -450 - yOff * Math.random()) //player in main room
- mob[mob.length - 1].fallHeight = -209
- } else { //mines above player NOT in tunnel
- spawn.mine(Math.min(Math.max(760, x), 5375), -1500 - yOff * Math.random()) //player in tunnel
- mob[mob.length - 1].fallHeight = -9
- }
- if (Math.random() < 0.5) { //random mines, but not in tunnel
- spawn.mine(800 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines
- mob[mob.length - 1].fallHeight = -9
- }
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "mines",
+ bombCycle: 0,
+ bombInterval: 10 - simulation.difficultyMode,
+ do() {
+ const yOff = 120
+ this.bombCycle++
+ if (!(this.bombCycle % this.bombInterval) && (this.bombCycle % 660) > 330) { //mines above player
+ if (simulation.isHorizontalFlipped) {
+ const x = m.pos.x + 200 * (Math.random() - 0.5)
+ if (x > -750) { //mines above player IN tunnel
+ spawn.mine(Math.min(Math.max(-730, x), 100), -450 - yOff * Math.random()) //player in main room
+ mob[mob.length - 1].fallHeight = -209
+ } else { //mines above player NOT in tunnel
+ spawn.mine(Math.min(Math.max(-5375, x), -765), -1500 - yOff * Math.random()) //player in tunnel
+ mob[mob.length - 1].fallHeight = -9
+ }
+ if (Math.random() < 0.5) {
+ spawn.mine(-5350 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines
+ mob[mob.length - 1].fallHeight = -9
+ }
+ } else {
+ const x = m.pos.x + 200 * (Math.random() - 0.5)
+ if (x < 750) { //mines above player IN tunnel
+ spawn.mine(Math.min(Math.max(-100, x), 735), -450 - yOff * Math.random()) //player in main room
+ mob[mob.length - 1].fallHeight = -209
+ } else { //mines above player NOT in tunnel
+ spawn.mine(Math.min(Math.max(760, x), 5375), -1500 - yOff * Math.random()) //player in tunnel
+ mob[mob.length - 1].fallHeight = -9
+ }
+ if (Math.random() < 0.5) { //random mines, but not in tunnel
+ spawn.mine(800 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines
+ mob[mob.length - 1].fallHeight = -9
}
}
- for (let i = 0; i < mob.length; i++) { //mines fall
- if (mob[i].isMine) {
- if (mob[i].position.y < mob[i].fallHeight) {
- mob[i].force.y += mob[i].mass * 0.03;
- } else if (!mob[i].isOnGround) {
- mob[i].isOnGround = true
- Matter.Body.setPosition(mob[i], {
- x: mob[i].position.x,
- y: mob[i].fallHeight
- })
- }
+ }
+ for (let i = 0; i < mob.length; i++) { //mines fall
+ if (mob[i].isMine) {
+ if (mob[i].position.y < mob[i].fallHeight) {
+ mob[i].force.y += mob[i].mass * 0.03;
+ } else if (!mob[i].isOnGround) {
+ mob[i].isOnGround = true
+ Matter.Body.setPosition(mob[i], {
+ x: mob[i].position.x,
+ y: mob[i].fallHeight
+ })
}
}
- },
- enter() {
- this.bombCycle = 0;
- },
- exit() {
- for (let i = 0; i < mob.length; i++) {
- if (mob[i].isMine) mob[i].isExploding = true //explode the mines at the start of new round
- }
- },
+ }
},
- {
- name: "orbiters",
- spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode),
- orbitersCycle: 0,
- do() {
- this.orbitersCycle++
- if (!(this.orbitersCycle % this.spawnRate) && (this.orbitersCycle % 660) > 600 && mob.length < me.maxMobs) {
- const speed = (0.01 + 0.0005 * simulation.difficultyMode) * ((Math.random() < 0.5) ? 0.85 : -1.15)
- const phase = 0 //Math.floor(2 * Math.random()) * Math.PI
- //find distance to play and set orbs at that range
- const dist = me.distanceToPlayer()
- //360 + 2150 * Math.random()
- me.orbitalNoVelocity(me, dist + 900 * (Math.random() - 0.5), 0.1 * Math.random() + phase, speed) // orbital(who, radius, phase, speed)
- }
- },
- enter() {},
- exit() {},
+ enter() {
+ this.bombCycle = 0;
},
- {
- name: "laser",
- spinForce: 0.00000008, // * (Math.random() < 0.5 ? -1 : 1),
- fadeCycle: 0, //fades in over 4 seconds
- do() {
- this.fadeCycle++
- if (this.fadeCycle > 0) {
- me.torque += this.spinForce * me.inertia; //spin //0.00000015
- if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
+ exit() {
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isMine) mob[i].isExploding = true //explode the mines at the start of new round
+ }
+ },
+ },
+ {
+ name: "orbiters",
+ spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode),
+ orbitersCycle: 0,
+ do() {
+ this.orbitersCycle++
+ if (!(this.orbitersCycle % this.spawnRate) && (this.orbitersCycle % 660) > 600 && mob.length < me.maxMobs) {
+ const speed = (0.01 + 0.0005 * simulation.difficultyMode) * ((Math.random() < 0.5) ? 0.85 : -1.15)
+ const phase = 0 //Math.floor(2 * Math.random()) * Math.PI
+ //find distance to play and set orbs at that range
+ const dist = me.distanceToPlayer()
+ //360 + 2150 * Math.random()
+ me.orbitalNoVelocity(me, dist + 900 * (Math.random() - 0.5), 0.1 * Math.random() + phase, speed) // orbital(who, radius, phase, speed)
+ }
+ },
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "laser",
+ spinForce: 0.00000008, // * (Math.random() < 0.5 ? -1 : 1),
+ fadeCycle: 0, //fades in over 4 seconds
+ do() {
+ this.fadeCycle++
+ if (this.fadeCycle > 0) {
+ me.torque += this.spinForce * me.inertia; //spin //0.00000015
+ if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
+ ctx.strokeStyle = "#50f";
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.lineWidth = 1.5;
+ ctx.beginPath();
+ if (this.fadeCycle < 120) { //damage scales up over 2 seconds to give player time to move as it fades in
+ const scale = this.fadeCycle / 120
+ const dmg = this.fadeCycle < 60 ? 0 : 0.13 * simulation.dmgScale * scale
+ me.lasers(me.vertices[0], me.angle + Math.PI / 6, dmg);
+ me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[3], me.angle + 7 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[4], me.angle + 9 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[5], me.angle + 11 * Math.PI / 6, dmg);
+ ctx.strokeStyle = `rgba(85, 0, 255,${scale})`;
+ ctx.stroke();
+ ctx.strokeStyle = `rgba(80, 0, 255,${0.07 * scale})`
+ } else if (this.fadeCycle > 0) {
+ me.lasers(me.vertices[0], me.angle + Math.PI / 6);
+ me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6);
+ me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6);
+ me.lasers(me.vertices[3], me.angle + 7 * Math.PI / 6);
+ me.lasers(me.vertices[4], me.angle + 9 * Math.PI / 6);
+ me.lasers(me.vertices[5], me.angle + 11 * Math.PI / 6);
ctx.strokeStyle = "#50f";
- ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
- ctx.lineWidth = 1.5;
- ctx.beginPath();
- if (this.fadeCycle < 120) { //damage scales up over 2 seconds to give player time to move as it fades in
- const scale = this.fadeCycle / 120
- const dmg = this.fadeCycle < 60 ? 0 : 0.13 * simulation.dmgScale * scale
- me.lasers(me.vertices[0], me.angle + Math.PI / 6, dmg);
- me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6, dmg);
- me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6, dmg);
- me.lasers(me.vertices[3], me.angle + 7 * Math.PI / 6, dmg);
- me.lasers(me.vertices[4], me.angle + 9 * Math.PI / 6, dmg);
- me.lasers(me.vertices[5], me.angle + 11 * Math.PI / 6, dmg);
- ctx.strokeStyle = `rgba(85, 0, 255,${scale})`;
- ctx.stroke();
- ctx.strokeStyle = `rgba(80, 0, 255,${0.07*scale})`
- } else if (this.fadeCycle > 0) {
- me.lasers(me.vertices[0], me.angle + Math.PI / 6);
- me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6);
- me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6);
- me.lasers(me.vertices[3], me.angle + 7 * Math.PI / 6);
- me.lasers(me.vertices[4], me.angle + 9 * Math.PI / 6);
- me.lasers(me.vertices[5], me.angle + 11 * Math.PI / 6);
- ctx.strokeStyle = "#50f";
- ctx.stroke();
- ctx.strokeStyle = "rgba(80,0,255,0.07)";
- }
- ctx.setLineDash([]);
- ctx.lineWidth = 20;
ctx.stroke();
+ ctx.strokeStyle = "rgba(80,0,255,0.07)";
}
- },
- enter() { this.fadeCycle = 0 },
- exit() {},
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.stroke();
+ }
},
- {
- name: "black hole",
- eventHorizon: 0,
- eventHorizonRadius: 1900,
- eventHorizonCycle: 0,
- do() {
- this.eventHorizonCycle++
- this.eventHorizon = Math.max(0, this.eventHorizonRadius * Math.sin(this.eventHorizonCycle * 0.007)) //eventHorizon waves in and out
- //draw darkness
- ctx.beginPath();
- ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.2, 0, 2 * Math.PI);
- ctx.fillStyle = "rgba(0,20,40,0.3)";
- ctx.fill();
- ctx.beginPath();
- ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.4, 0, 2 * Math.PI);
- ctx.fillStyle = "rgba(0,20,40,0.25)";
- ctx.fill();
- ctx.beginPath();
- ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.6, 0, 2 * Math.PI);
- ctx.fillStyle = "rgba(0,20,40,0.2)";
- ctx.fill();
- ctx.beginPath();
- ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.8, 0, 2 * Math.PI);
- ctx.fillStyle = "rgba(0,20,40,0.15)";
- ctx.fill();
- ctx.beginPath();
- ctx.arc(me.position.x, me.position.y, this.eventHorizon, 0, 2 * Math.PI);
- ctx.fillStyle = "rgba(0,0,0,0.1)";
- ctx.fill();
- //when player is inside event horizon
- if (Vector.magnitude(Vector.sub(me.position, player.position)) < this.eventHorizon) {
- if (m.immuneCycle < m.cycle) {
- if (m.energy > 0) m.energy -= 0.018
- if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0003 * simulation.dmgScale);
- }
- const angle = Math.atan2(player.position.y - me.position.y, player.position.x - me.position.x);
- player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
- player.force.y -= 0.0017 * Math.sin(angle) * player.mass;
- //draw line to player
- ctx.beginPath();
- ctx.moveTo(me.position.x, me.position.y);
- ctx.lineTo(m.pos.x, m.pos.y);
- ctx.lineWidth = Math.min(60, me.radius * 2);
- ctx.strokeStyle = "rgba(0,0,0,0.5)";
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
- ctx.fillStyle = "rgba(0,0,0,0.3)";
- ctx.fill();
+ enter() { this.fadeCycle = 0 },
+ exit() { },
+ },
+ {
+ name: "black hole",
+ eventHorizon: 0,
+ eventHorizonRadius: 1900,
+ eventHorizonCycle: 0,
+ do() {
+ this.eventHorizonCycle++
+ this.eventHorizon = Math.max(0, this.eventHorizonRadius * Math.sin(this.eventHorizonCycle * 0.007)) //eventHorizon waves in and out
+ //draw darkness
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.2, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.3)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.4, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.25)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.6, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.2)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.8, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.15)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.1)";
+ ctx.fill();
+ //when player is inside event horizon
+ if (Vector.magnitude(Vector.sub(me.position, player.position)) < this.eventHorizon) {
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.018
+ if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0003 * simulation.dmgScale);
}
- me.curl(this.eventHorizon);
- },
- enter() { this.eventHorizonCycle = 0 },
- exit() {},
+ const angle = Math.atan2(player.position.y - me.position.y, player.position.x - me.position.x);
+ player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
+ player.force.y -= 0.0017 * Math.sin(angle) * player.mass;
+ //draw line to player
+ ctx.beginPath();
+ ctx.moveTo(me.position.x, me.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineWidth = Math.min(60, me.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ ctx.fill();
+ }
+ me.curl(this.eventHorizon);
},
- {
- name: "oscillation",
- waveCycle: 0,
- whereX: simulation.isHorizontalFlipped ? -3000 : 3000,
- do() {
- this.waveCycle += !me.isStunned + !me.isSlowed
- // if (!me.isShielded && (!(this.waveCycle % 1800) || !(this.waveCycle % 1801))) spawn.shield(me, me.position.x, me.position.y, 1);
- me.constraint.pointA = {
- x: this.whereX + 600 * Math.sin(this.waveCycle * 0.005),
- y: me.constraint.pointA.y
- }
- },
- enter() {
- spawn.shield(me, me.position.x, me.position.y, 1);
- },
- exit() { this.waveCycle = 0 },
+ enter() { this.eventHorizonCycle = 0 },
+ exit() { },
+ },
+ {
+ name: "oscillation",
+ waveCycle: 0,
+ whereX: simulation.isHorizontalFlipped ? -3000 : 3000,
+ do() {
+ this.waveCycle += !me.isStunned + !me.isSlowed
+ // if (!me.isShielded && (!(this.waveCycle % 1800) || !(this.waveCycle % 1801))) spawn.shield(me, me.position.x, me.position.y, 1);
+ me.constraint.pointA = {
+ x: this.whereX + 600 * Math.sin(this.waveCycle * 0.005),
+ y: me.constraint.pointA.y
+ }
},
+ enter() {
+ spawn.shield(me, me.position.x, me.position.y, 1);
+ },
+ exit() { this.waveCycle = 0 },
+ },
// {
// name: "__",
// do() {},
@@ -700,7 +700,7 @@ const spawn = {
// },
]
shuffle(me.mode); //THIS SHOULDN'T BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- me.do = function() {
+ me.do = function () {
this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
if (this.health < 1) {
this.cycle++;
@@ -716,13 +716,13 @@ const spawn = {
// this.mode[7].do()
};
me.spawnRate = 5800 - 30 * simulation.difficultyMode * simulation.difficultyMode
- me.spawnBoss = function() { //if the fight lasts too long start spawning bosses
+ me.spawnBoss = function () { //if the fight lasts too long start spawning bosses
if (!(me.cycle % this.spawnRate) && this.health < 1) {
this.spawnRate = Math.max(300, this.spawnRate - 10 * simulation.difficultyMode * simulation.difficultyMode) //reduce the timer each time a boss spawns
spawn.randomLevelBoss(3000 * (simulation.isHorizontalFlipped ? -1 : 1) + 2000 * (Math.random() - 0.5), -1100 + 200 * (Math.random() - 0.5))
}
}
- me.pushAway = function(magX = 0.13, magY = 0.05) {
+ me.pushAway = function (magX = 0.13, magY = 0.05) {
for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1)
body[i].force.y -= magY * body[i].mass
@@ -738,16 +738,16 @@ const spawn = {
player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1)
player.force.y -= magY * player.mass
}
- me.boulder = function(x, y) {
+ me.boulder = function (x, y) {
mobs.spawn(x, y, 6, Math.floor(50 + 50 * Math.random()), this.fill);
let boss = this
let me = mob[mob.length - 1];
me.stroke = "transparent";
- me.onHit = function() {
+ me.onHit = function () {
this.timeLeft = 0
};
me.explodeRange = 500
- me.onDeath = function() { //explode
+ me.onDeath = function () { //explode
simulation.drawList.push({ //draw explosion
x: this.position.x,
y: this.position.y,
@@ -797,14 +797,14 @@ const spawn = {
me.spin = me.inertia * 0.000005 * (1 + Math.random()) * (m.pos.x > me.position.x ? 1 : -1)
Matter.Body.setAngularVelocity(me, 0.1 * (1 + 0.3 * Math.random()) * (m.pos.x > me.position.x ? 1 : -1));
Matter.Body.setVelocity(me, { x: 0, y: 10 });
- me.do = function() {
+ me.do = function () {
this.fill = boss.fill
this.torque += this.spin;
this.gravity();
this.timeLimit();
};
}
- me.orbitalNoVelocity = function(who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
+ me.orbitalNoVelocity = function (who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
let boss = this
mobs.spawn(who.position.x, who.position.y, 6, 20, "rgb(255,0,150)");
let me = mob[mob.length - 1];
@@ -818,7 +818,7 @@ const spawn = {
me.isOrbital = true;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
- me.do = function() {
+ me.do = function () {
this.fill = boss.fill
const time = simulation.cycle * speed + phase
const orbit = { x: Math.cos(time), y: Math.sin(time) }
@@ -838,8 +838,8 @@ const spawn = {
}
};
}
- me.lasers = function(where, angle, dmg = 0.1 * simulation.dmgScale) {
- const vertexCollision = function(v1, v1End, domain) {
+ me.lasers = function (where, angle, dmg = 0.1 * simulation.dmgScale) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -909,7 +909,7 @@ const spawn = {
ctx.moveTo(where.x, where.y);
ctx.lineTo(best.x, best.y);
}
- me.onDeath = function() {
+ me.onDeath = function () {
if (!this.hasRunDeathScript) {
this.hasRunDeathScript = true
//make a block body to replace this one
@@ -923,7 +923,7 @@ const spawn = {
body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
body[len].classType = "body";
Composite.add(engine.world, body[len]); //add to world
- const expand = function(that, massLimit) {
+ const expand = function (that, massLimit) {
const scale = 1.05;
Matter.Body.scale(that, scale, scale);
if (that.mass < massLimit) setTimeout(expand, 20, that, massLimit);
@@ -946,7 +946,7 @@ const spawn = {
//add lore level as next level if player took lore tech earlier in the game
if (lore.techCount > (lore.techGoal - 1) && !simulation.isCheating) {
simulation.makeTextLog(`
undefined = ${lore.techCount}/${lore.techGoal}`, 360);
- setTimeout(function() {
+ setTimeout(function () {
simulation.makeTextLog(`level.levels.push("
null")`, 720);
unlockExit()
level.levels.push("null")
@@ -981,7 +981,7 @@ const spawn = {
document.getElementById("text-log").style.display = "none"
document.getElementById("fade-out").style.opacity = 1; //slowly fades out
// build.shareURL(false)
- setTimeout(function() {
+ setTimeout(function () {
if (!simulation.onTitlePage) {
m.alive = false
simulation.paused = true;
@@ -998,7 +998,7 @@ const spawn = {
}
if (simulation.testing) {
unlockExit()
- setTimeout(function() {
+ setTimeout(function () {
simulation.makeTextLog(`level.levels.length
= Infinite`);
}, 1500);
} else {
@@ -1571,7 +1571,7 @@ const spawn = {
// for (let i = 0; i < amount; i++) b.spore(this.position)
// }
// }
- me.do = function() {
+ me.do = function () {
this.zombieHealthBar();
this.lookForMobTargets();
this.attack();
@@ -1579,7 +1579,7 @@ const spawn = {
};
me.mobSearchIndex = 0;
me.target = null
- me.lookForMobTargets = function() {
+ me.lookForMobTargets = function () {
if (this.target === null && mob.length > 1 && !(simulation.cycle % this.seePlayerFreq)) { //find mob targets
let closeDist = Infinity;
for (let i = 0, len = mob.length; i < len; ++i) {
@@ -1607,7 +1607,7 @@ const spawn = {
this.target = null //chance to forget target
}
}
- me.zombieHealthBar = function() {
+ me.zombieHealthBar = function () {
this.health -= 0.0004 //decay
if ((this.health < 0.01 || isNaN(this.health)) && this.alive) this.death();
const h = this.radius * 0.3;
@@ -1620,7 +1620,7 @@ const spawn = {
ctx.fillRect(x, y, w * this.health, h);
}
me.hitCD = 0
- me.attack = function() { //hit non zombie mobs
+ me.attack = function () { //hit non zombie mobs
if (this.hitCD < simulation.cycle) {
if (this.target) {
this.force = Vector.mult(Vector.normalise(Vector.sub(this.target.position, this.position)), this.accelMag * this.mass)
@@ -1676,7 +1676,7 @@ const spawn = {
// me.memory = 120;
me.seeAtDistance2 = 2000000 //1400 vision range
Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.attraction();
this.repulsion();
@@ -1701,7 +1701,7 @@ const spawn = {
me.isGrouper = true;
me.seeAtDistance2 = 600 * 600
me.seePlayerFreq = Math.floor(50 + 50 * Math.random())
- me.do = function() {
+ me.do = function () {
this.gravity();
this.checkStatus();
this.seePlayerCheck();
@@ -1741,7 +1741,7 @@ const spawn = {
me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); //extra reduction for a boss, because normal density
me.frictionAir = 0.01;
me.accelMag = 0.0002;
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y);
for (const who of mob) {
if (who.isNecroMob) { //blockMobs leave their body, and die
@@ -1751,7 +1751,7 @@ const spawn = {
}
}
me.target = player; // the target to lock on. Usually a block, but will be the player under certain conditions
- me.do = function() {
+ me.do = function () {
this.checkStatus();
this.seePlayerCheck();
if (this.target) { //(this.target === player && this.seePlayer.yes) || this.target !== player
@@ -1861,7 +1861,7 @@ const spawn = {
me.isDropPowerUp = false;
// me.showHealthBar = false;
me.cycle = 0
- me.do = function() { //grow phase only occurs for growCycles
+ me.do = function () { //grow phase only occurs for growCycles
this.checkStatus();
this.seePlayerCheck();
this.cycle++
@@ -1874,7 +1874,7 @@ const spawn = {
this.radius *= scale;
}
}
- me.normalDo = function() {
+ me.normalDo = function () {
this.gravity();
this.checkStatus();
this.seePlayerCheck();
@@ -1907,20 +1907,20 @@ const spawn = {
me.damageReduction = 0.17 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); //me.damageReductionGoal
const k = 642 //k=r^2/m
- me.split = function() {
+ me.split = function () {
Matter.Body.scale(this, 0.45, 0.45);
this.radius = Math.sqrt(this.mass * k / Math.PI)
spawn.cellBoss(this.position.x, this.position.y, this.radius, this.cellID);
mob[mob.length - 1].health = this.health
}
- me.onHit = function() { //run this function on hitting player
+ me.onHit = function () { //run this function on hitting player
this.health = 1;
this.split();
};
- me.onDamage = function(dmg) {
+ me.onDamage = function (dmg) {
if (Math.random() < 0.34 * dmg * Math.sqrt(this.mass) && this.health > dmg) this.split();
}
- me.do = function() {
+ me.do = function () {
this.seePlayerByDistOrLOS();
this.checkStatus();
this.attraction();
@@ -1946,7 +1946,7 @@ const spawn = {
}
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.isCell = false;
let count = 0 //count other cells by id
// console.log(this.cellID)
@@ -1985,11 +1985,11 @@ const spawn = {
Matter.Body.setAngularVelocity(me, 0.12 * (Math.random() - 0.5))
// spawn.shield(me, x, y, 1);
- me.onHit = function() { //run this function on hitting player
+ me.onHit = function () { //run this function on hitting player
this.explode();
};
me.damageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
- me.doAwake = function() {
+ me.doAwake = function () {
this.alwaysSeePlayer();
this.checkStatus();
this.attraction();
@@ -2010,7 +2010,7 @@ const spawn = {
}
}
}
- me.do = function() {
+ me.do = function () {
this.checkStatus();
if (this.seePlayer.recall) {
this.do = this.doAwake
@@ -2020,7 +2020,7 @@ const spawn = {
}
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.isSpawnBoss = false;
let count = 0 //count other cells by id
// console.log(this.spawnID)
@@ -2073,7 +2073,7 @@ const spawn = {
me.buffCount = 0
me.accelMag = 0.00005 //* simulation.accelScale;
- me.setBuffed = function() {
+ me.setBuffed = function () {
this.buffCount++
this.accelMag += 0.000024 //* Math.sqrt(simulation.accelScale)
this.fill = `hsl(144, ${5 + 10 * this.buffCount}%, 50%)`
@@ -2086,7 +2086,7 @@ const spawn = {
// this.damageReduction = 0
// this.invulnerabilityCountDown = simulation.difficulty
}
- me.onDeath = function() {
+ me.onDeath = function () {
this.isBuffBoss = false;
let count = 0 //count other cells by id
for (let i = 0, len = mob.length; i < len; i++) {
@@ -2107,7 +2107,7 @@ const spawn = {
//required setup for invulnerable
// me.isInvulnerable = false
me.invulnerabilityCountDown = 0
- me.do = function() {
+ me.do = function () {
// if (this.isInvulnerable) {
// if (this.invulnerabilityCountDown > 0) {
// this.invulnerabilityCountDown--
@@ -2169,7 +2169,7 @@ const spawn = {
me.startingDamageReduction = me.damageReduction
me.damageReduction = 0
me.invulnerabilityCountDown = 40 + simulation.difficulty
- me.onHit = function() { //run this function on hitting player
+ me.onHit = function () { //run this function on hitting player
if (powerUps.ejectTech()) {
powerUps.ejectGraphic("150, 138, 255");
// powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
@@ -2178,7 +2178,7 @@ const spawn = {
Matter.Body.setDensity(this, this.density * 1.4); //normal is 0.001
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.leaveBody = false;
if (vertices > 3) {
this.isDropPowerUp = false;
@@ -2190,7 +2190,7 @@ const spawn = {
}
for (let i = 0; i < powerUp.length; i++) powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
};
- me.do = function() {
+ me.do = function () {
if (this.isInvulnerable) {
if (this.invulnerabilityCountDown > 0) {
this.invulnerabilityCountDown--
@@ -2200,7 +2200,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
} else {
this.isInvulnerable = false
@@ -2253,7 +2253,7 @@ const spawn = {
// me.damageReduction = 0
// me.invulnerabilityCountDown = 60 + simulation.difficulty * 2
- me.onHit = function() { //run this function on hitting player
+ me.onHit = function () { //run this function on hitting player
if (powerUps.ejectTech()) {
powerUps.ejectGraphic("150, 138, 255");
// powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
@@ -2262,7 +2262,7 @@ const spawn = {
Matter.Body.setDensity(this, this.density * 1.4); //normal is 0.001
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.leaveBody = false;
if (vertices > 3) {
this.isDropPowerUp = false;
@@ -2314,7 +2314,7 @@ const spawn = {
// for (let i = 0; i < this.powerUpList.length; i++) {}
// }
// me.constrainPowerUps()
- me.do = function() {
+ me.do = function () {
this.stroke = `hsl(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%)`
// if (this.isInvulnerable) {
// if (this.invulnerabilityCountDown > 0) {
@@ -2379,7 +2379,7 @@ const spawn = {
// me.onDeath = function () { //helps collisions functions work better after vertex have been changed
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
// }
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
this.attraction();
@@ -2427,14 +2427,14 @@ const spawn = {
Composite.add(engine.world, cons[cons.length - 1]);
cons[len2].length = 100 + 1.5 * radius;
me.cons2 = cons[len2];
- me.do = function() {
+ me.do = function () {
this.gravity();
this.searchSpring();
this.checkStatus();
this.springAttack();
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.removeCons();
};
spawn.shield(me, x, y);
@@ -2453,7 +2453,7 @@ const spawn = {
me.randomHopCD = simulation.cycle + me.randomHopFrequency;
Matter.Body.rotate(me, Math.random() * Math.PI);
spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
@@ -2501,10 +2501,10 @@ const spawn = {
// Matter.Body.rotate(me, Math.random() * Math.PI);
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass);
};
- me.do = function() {
+ me.do = function () {
this.gravity();
this.checkStatus();
if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
@@ -2533,11 +2533,11 @@ const spawn = {
me.delay = 120 + 40 * simulation.CDScale;
Matter.Body.rotate(me, Math.random() * Math.PI);
spawn.shield(me, x, y, 1);
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// for (let i = 0, len = 3 + 0.1 * simulation.difficulty; i < len; ++i) spawn.hopBullet(this.position.x + 100 * (Math.random() - 0.5), this.position.y + 100 * (Math.random() - 0.5))
};
- me.do = function() {
+ me.do = function () {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
@@ -2653,7 +2653,7 @@ const spawn = {
me.lookTorque = 0.0000014;
me.restitution = 0;
spawn.shield(me, x, y);
- me.look = function() {
+ me.look = function () {
this.seePlayerByLookingAt();
this.checkStatus();
if (this.seePlayer.recall && this.cd < simulation.cycle) {
@@ -2663,7 +2663,7 @@ const spawn = {
}
}
me.do = me.look
- me.spin = function() {
+ me.spin = function () {
this.checkStatus();
this.torque += 0.000035 * this.inertia;
//draw attack vector
@@ -2697,7 +2697,7 @@ const spawn = {
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
me.memory = Infinity;
Matter.Body.setDensity(me, 0.015); //extra dense //normal is 0.001 //makes effective life much larger
- me.do = function() {
+ me.do = function () {
//keep it slow, to stop issues from explosion knock backs
if (this.speed > 5) {
Matter.Body.setVelocity(this, {
@@ -2828,7 +2828,7 @@ const spawn = {
// me.frictionAir = 0.005;
me.memory = 1600;
Matter.Body.setDensity(me, 0.06); //extra dense //normal is 0.001 //makes effective life much larger
- me.onDeath = function() {
+ me.onDeath = function () {
//applying forces to player doesn't seem to work inside this method, not sure why
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
if (simulation.difficulty > 5) {
@@ -2850,7 +2850,7 @@ const spawn = {
}
};
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
- me.do = function() {
+ me.do = function () {
//keep it slow, to stop issues from explosion knock backs
if (this.speed > 1) {
Matter.Body.setVelocity(this, {
@@ -2984,7 +2984,7 @@ const spawn = {
Composite.add(engine.world, cons[cons.length - 1]);
cons[len2].length = 100 + 1.5 * radius;
me.cons2 = cons[len2];
- me.do = function() {
+ me.do = function () {
// this.armor();
this.gravity();
this.searchSpring();
@@ -2992,7 +2992,7 @@ const spawn = {
this.springAttack();
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.removeCons();
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
@@ -3070,7 +3070,7 @@ const spawn = {
me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false
me.invulnerabilityCountDown = 0
- me.do = function() {
+ me.do = function () {
this.checkStatus();
this.gravity();
//draw the two dots on the end of the springs
@@ -3097,7 +3097,7 @@ const spawn = {
}
}
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
if (this.invulnerabilityCountDown < 0) {
this.invulnerabilityCountDown = 110
@@ -3140,7 +3140,7 @@ const spawn = {
} else {
this.torque = this.lookTorque * this.inertia;
//spring to random place on map
- const vertexCollision = function(v1, v1End, domain) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -3205,7 +3205,7 @@ const spawn = {
}
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
this.removeCons();
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < this.babyList.length; i++) {
@@ -3232,7 +3232,7 @@ const spawn = {
babyMob.collisionFilter.mask = cat.bullet | cat.player //can't touch other mobs //cat.map | cat.body |
babyMob.delay = 60 + 55 * simulation.CDScale + Math.floor(Math.random() * 20);
babyMob.strikeRange = 400
- babyMob.onHit = function() {
+ babyMob.onHit = function () {
this.cd = simulation.cycle + this.delay;
//dislodge ammo
if (b.inventory.length) {
@@ -3376,7 +3376,7 @@ const spawn = {
me.frictionStatic = 0;
me.friction = 0;
spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
this.attraction();
@@ -3403,7 +3403,7 @@ const spawn = {
me.stroke = "transparent"; //used for drawGhost
me.collisionFilter.mask = cat.bullet | cat.body
me.memory = Infinity
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
requestAnimationFrame(() => {
requestAnimationFrame(() => {
@@ -3413,7 +3413,7 @@ const spawn = {
})
};
me.warpIntensity = 0
- me.awake = function() {
+ me.awake = function () {
this.checkStatus();
//health bar needs to be here because the position is being set
const h = this.radius * 0.3;
@@ -3487,7 +3487,7 @@ const spawn = {
Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
}
}
- me.do = function() {
+ me.do = function () {
if (this.seePlayer.recall || (!(simulation.cycle % this.seePlayerFreq) && this.distanceToPlayer2() < this.seeAtDistance2 && !m.isCloak)) {
setTimeout(() => {
this.do = this.awake
@@ -3510,11 +3510,11 @@ const spawn = {
me.accelMag = 0.00009 * simulation.accelScale;
me.frictionStatic = 0;
me.friction = 0;
- me.onDamage = function() {
+ me.onDamage = function () {
this.laserPos = this.position;
};
spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
this.attraction();
@@ -3584,7 +3584,7 @@ const spawn = {
// me.onDeath = function() {};
me.flapRate = 0.3 + Math.floor(3 * Math.random()) / 10 + 100 * me.accelMag
me.flapRadius = 75 + radius * 3
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory()
this.checkStatus();
if (this.seePlayer.recall) {
@@ -3616,7 +3616,7 @@ const spawn = {
}
const flapArc = 0.7 //don't go past 1.57 for normal flaps
- ctx.fillStyle = `hsla(${160+40*Math.random()}, 100%, ${25 + 25*Math.random()*Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
}
@@ -3676,7 +3676,7 @@ const spawn = {
// me.isAlreadyHadBabies = true
// }
- me.pushAway = function(magX = 0.13, magY = 0.05) {
+ me.pushAway = function (magX = 0.13, magY = 0.05) {
for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
if (Vector.magnitudeSquared(Vector.sub(body[i].position, this.position)) < 4000000) { //2000
body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1)
@@ -3701,7 +3701,7 @@ const spawn = {
}
}
- me.babies = function(len) {
+ me.babies = function (len) {
const delay = Math.max(3, Math.floor(15 - len / 2))
let i = 0
let spawnFlutters = () => {
@@ -3730,11 +3730,11 @@ const spawn = {
}
// me.babies(0.05 * simulation.difficulty + 1)
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
me.babies(0.05 * simulation.difficulty + 1)
};
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.health < this.nextHealthThreshold && this.alive) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4
@@ -3748,7 +3748,7 @@ const spawn = {
this.accelMag *= 1.4
}
};
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory(50)
this.checkStatus();
if (this.isInvulnerable) {
@@ -3768,7 +3768,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
} else if (this.seePlayer.recall) {
// const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass)
@@ -3804,7 +3804,7 @@ const spawn = {
}
const flapArc = 0.7 //don't go past 1.57 for normal flaps
this.wingSize = 0.97 * this.wingSize + 0.03 * this.wingGoal
- ctx.fillStyle = this.fill = `hsla(${160+40*Math.random()}, 100%, ${25 + 25*Math.random()*Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ ctx.fillStyle = this.fill = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0012)
this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0012)
} else {
@@ -3836,11 +3836,11 @@ const spawn = {
for (let i = 0, len = 2 + 0.3 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1);
// me.onHit = function() { };
// spawn.shield(me, x, y, 1); //not working, not sure why
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.laserInterval = 100
- me.do = function() {
+ me.do = function () {
// this.armor();
this.seePlayerByLookingAt();
this.checkStatus();
@@ -3860,7 +3860,7 @@ const spawn = {
this.torque -= 0.000004 * this.inertia;
}
if (simulation.cycle % this.laserInterval > this.laserInterval / 2) {
- const vertexCollision = function(v1, v1End, domain) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -3974,13 +3974,13 @@ const spawn = {
Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 200 + 300 * Math.random())
- me.onHit = function() {};
- me.onDeath = function() {
+ me.onHit = function () { };
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.targetingCount = 0;
me.targetingTime = 60 - Math.min(58, 3 * simulation.difficulty)
- me.do = function() {
+ me.do = function () {
// //wings
// const wing = (simulation.cycle % 9) > 4 ? this.vertices[0] : this.vertices[2] //Vector.add(this.position, { x: 100, y: 0 })
@@ -4018,7 +4018,7 @@ const spawn = {
} else if (c < -threshold) {
this.torque -= 0.000004 * this.inertia;
}
- const vertexCollision = function(v1, v1End, domain) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -4145,10 +4145,10 @@ const spawn = {
me.delay = 55 + 35 * simulation.CDScale;
me.nextBlinkCycle = me.delay;
spawn.shield(me, x, y, 1);
- me.onDamage = function() {
+ me.onDamage = function () {
// this.cd = simulation.cycle + this.delay;
};
- me.onDeath = function() {
+ me.onDeath = function () {
const offAngle = Math.PI * Math.random()
for (let i = 0, len = 3; i < len; i++) {
spawn.grenade(this.position.x, this.position.y, this.grenadeDelay);
@@ -4162,7 +4162,7 @@ const spawn = {
}
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
}
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory(40)
if (this.nextBlinkCycle < simulation.cycle && this.seePlayer.yes) { //teleport towards the player
this.nextBlinkCycle = simulation.cycle + this.delay;
@@ -4219,15 +4219,15 @@ const spawn = {
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 200 + 300 * Math.random(), 1)
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
- me.onHit = function() {};
- me.do = function() {
+ me.onHit = function () { };
+ me.do = function () {
if (player.speed > 5) this.do = this.fire //don't attack until player moves
}
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
- me.fire = function() {
+ me.fire = function () {
// this.armor();
this.checkStatus();
if (!m.isCloak && !this.isStunned) {
@@ -4327,8 +4327,8 @@ const spawn = {
me.pulseRadius = Math.min(400, 170 + simulation.difficulty * 3)
me.fireDelay = Math.max(75, 140 - simulation.difficulty * 0.5)
me.isFiring = false
- me.onHit = function() {};
- me.canSeeTarget = function() {
+ me.onHit = function () { };
+ me.canSeeTarget = function () {
const angle = this.angle + Math.PI / 2;
const dot = Vector.dot({
x: Math.cos(angle),
@@ -4347,7 +4347,7 @@ const spawn = {
return true
}
}
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
if (this.seePlayer.recall) {
@@ -4443,11 +4443,11 @@ const spawn = {
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
me.accelMag = 0.0001 * simulation.accelScale;
me.laserInterval = 100
- me.onHit = function() {
+ me.onHit = function () {
//run this function on hitting player
this.explode();
};
- me.do = function() {
+ me.do = function () {
this.torque = this.lookTorque * this.inertia * 0.5;
this.seePlayerByLookingAt();
this.checkStatus();
@@ -4457,7 +4457,7 @@ const spawn = {
if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
if (simulation.cycle % this.laserInterval > this.laserInterval / 2) {
- const vertexCollision = function(v1, v1End, domain) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -4572,11 +4572,11 @@ const spawn = {
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.isBoss = true;
// spawn.shield(me, x, y, 1); //not working, not sure why
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.rotateVelocity = Math.min(0.0045, 0.0015 * simulation.accelScale * simulation.accelScale) * (level.levelsCleared > 8 ? 1 : -1) * (simulation.isHorizontalFlipped ? -1 : 1)
- me.do = function() {
+ me.do = function () {
this.fill = '#' + Math.random().toString(16).substr(-6); //flash colors
this.checkStatus();
@@ -4617,8 +4617,8 @@ const spawn = {
// Matter.Body.setPosition(this, this.startingPosition);
};
- me.lasers = function(where, angle) {
- const vertexCollision = function(v1, v1End, domain) {
+ me.lasers = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -4709,7 +4709,7 @@ const spawn = {
// me.onDamage = function () {};
// me.onHit = function() { //run this function on hitting player
// };
- me.onDeath = function() {
+ me.onDeath = function () {
if (this.spikeLength > 4) {
this.spikeLength = 4
const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), this.radius * this.spikeLength)
@@ -4718,7 +4718,7 @@ const spawn = {
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
}
};
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
this.attraction();
@@ -4786,10 +4786,10 @@ const spawn = {
me.strikeRange = 300
Matter.Body.rotate(me, Math.PI * 0.1);
spawn.shield(me, x, y);
- me.onDamage = function() {
+ me.onDamage = function () {
this.cd = simulation.cycle + this.delay;
};
- me.do = function() {
+ me.do = function () {
this.gravity();
if (!(simulation.cycle % this.seePlayerFreq)) { // this.seePlayerCheck(); from mobs
if (
@@ -4846,8 +4846,8 @@ const spawn = {
Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger
me.damageReduction = 0.12 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.isBoss = true;
- me.onDamage = function() {};
- me.onDeath = function() {
+ me.onDamage = function () { };
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
@@ -4856,7 +4856,7 @@ const spawn = {
me.isInvulnerable = false
me.isNextInvulnerability = 0.75
me.invulnerabilityCountDown = 0
- me.invulnerable = function() {
+ me.invulnerable = function () {
if (this.health < this.isNextInvulnerability) {
this.isNextInvulnerability = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
this.isInvulnerable = true
@@ -4874,7 +4874,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
} else {
this.isInvulnerable = false
@@ -4882,7 +4882,7 @@ const spawn = {
}
}
}
- me.do = function() {
+ me.do = function () {
this.invulnerable();
this.checkStatus();
this.seePlayerByHistory(60);
@@ -4896,8 +4896,8 @@ const spawn = {
if (long > 0) this.laserSword(this.vertices[i], bend + this.angle + (i + 0.5) / sides * 2 * Math.PI, Math.abs(long));
}
};
- me.laserSword = function(where, angle, length) {
- const vertexCollision = function(v1, v1End, domain) {
+ me.laserSword = function (where, angle, length) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
@@ -4968,10 +4968,10 @@ const spawn = {
me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false
me.nextHealthThreshold = 0.75
- me.onDeath = function() {
+ me.onDeath = function () {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
@@ -4985,7 +4985,7 @@ const spawn = {
};
//draw radial lines from verticies showing future bullet paths?
- me.radialLines = function() {
+ me.radialLines = function () {
ctx.beginPath();
for (let i = 0, len = this.vertices.length; i < len; i++) {
ctx.moveTo(this.vertices[i].x, this.vertices[i].y)
@@ -4998,7 +4998,7 @@ const spawn = {
}
me.phaseCycle = 0
- me.normalDoStuff = function() {
+ me.normalDoStuff = function () {
this.checkStatus();
me.seePlayer.recall = 1
//maintain speed //faster in the vertical to help avoid repeating patterns
@@ -5009,7 +5009,7 @@ const spawn = {
if (Math.abs(this.velocity.x) < 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y });
}
}
- me.burstFire = function() {
+ me.burstFire = function () {
this.normalDoStuff();
this.radialLines()
//draw invulnerable
@@ -5019,7 +5019,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
if (!(simulation.cycle % this.burstFireFreq)) {
@@ -5076,7 +5076,7 @@ const spawn = {
Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
me.seePlayer.recall = 1;
// spawn.shield(me, x, y, 1);
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4
@@ -5104,14 +5104,14 @@ const spawn = {
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0, len = mob.length; i < len; ++i) { //trigger nearby mines
if (mob[i].isMine && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.explodeRange) mob[i].isExploding = true
}
};
// console.log(me.mass) //100
- me.do = function() {
+ me.do = function () {
me.seePlayer.recall = 1
//maintain speed //faster in the vertical to help avoid repeating patterns
if (this.speed < 0.01) {
@@ -5141,7 +5141,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
}
this.checkStatus();
@@ -5178,7 +5178,7 @@ const spawn = {
// this.health = 1
// this.isExploding = true
// };
- me.do = function() {
+ me.do = function () {
this.checkStatus();
if (Matter.Query.collides(this, [player]).length > 0) {
@@ -5230,7 +5230,7 @@ const spawn = {
Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
me.seePlayer.recall = 1;
// spawn.shield(me, x, y, 1);
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
@@ -5239,12 +5239,12 @@ const spawn = {
this.damageReduction = 0
}
};
- if (isSpawnBossPowerUp) me.onDeath = function() { powerUps.spawnBossPowerUp(this.position.x, this.position.y) };
+ if (isSpawnBossPowerUp) me.onDeath = function () { powerUps.spawnBossPowerUp(this.position.x, this.position.y) };
me.cycle = 0
me.nextHealthThreshold = 0.75
me.fireCount = 0
// console.log(me.mass) //100
- me.do = function() {
+ me.do = function () {
me.seePlayer.recall = 1
//maintain speed //faster in the vertical to help avoid repeating patterns
if (this.speed < 0.01) {
@@ -5278,7 +5278,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
} else if (this.mass < 100) {
Matter.Body.scale(this, 1.01, 1.01); //grow back to normal size
@@ -5315,7 +5315,7 @@ const spawn = {
me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
@@ -5325,7 +5325,7 @@ const spawn = {
// requestAnimationFrame(() => { simulation.timePlayerSkip(300) }); //wrapping in animation frame prevents errors, probably
}
};
- me.onDeath = function() {
+ me.onDeath = function () {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
requestAnimationFrame(() => { simulation.timePlayerSkip(60) }); //wrapping in animation frame prevents errors, probably
};
@@ -5334,9 +5334,9 @@ const spawn = {
me.nextHealthThreshold = 0.75
me.invulnerableCount = 0
// console.log(me.mass) //100
- me.do = function() {
+ me.do = function () {
this.cycle++
- this.fill = `hsl(${this.cycle*0.5}, 100%, 80%)`;
+ this.fill = `hsl(${this.cycle * 0.5}, 100%, 80%)`;
// this.fill = `hsl(${270 + 50*Math.sin(this.cycle*0.02)}, 100%, 60%)`;
this.seePlayer.recall = 1
//maintain speed //faster in the vertical to help avoid repeating patterns
@@ -5371,7 +5371,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 15 + 6 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
}
}
@@ -5406,10 +5406,10 @@ const spawn = {
me.isBadTarget = true;
me.isMobBullet = true;
me.showHealthBar = false;
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass * 12);
};
- me.do = function() {
+ me.do = function () {
this.timeLimit();
};
Matter.Body.setVelocity(me, velocity);
@@ -5443,11 +5443,11 @@ const spawn = {
me.laserAngle = 3 * Math.PI / 5
const seeDistance2 = 200000
spawn.shield(me, x, y);
- me.onDamage = function() {};
- me.onDeath = function() {
+ me.onDamage = function () { };
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory(40);
this.attraction();
this.checkStatus();
@@ -5458,7 +5458,7 @@ const spawn = {
// ctx.fillStyle = "#444";
// ctx.fill();
};
- me.swordWaiting = function() {
+ me.swordWaiting = function () {
if (
this.seePlayer.recall &&
this.cd < simulation.cycle &&
@@ -5487,7 +5487,7 @@ const spawn = {
}
}
me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
- me.swordGrow = function() {
+ me.swordGrow = function () {
this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
this.swordRadius += this.swordRadiusGrowRate
if (this.swordRadius > this.swordRadiusMax) {
@@ -5501,10 +5501,10 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
}
- me.swordSlash = function() {
+ me.swordSlash = function () {
this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
this.torque += this.torqueMagnitude;
this.spinCount++
@@ -5523,11 +5523,11 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
}
- me.laserSword = function(where, angle) {
- const vertexCollision = function(v1, v1End, domain) {
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let v = domain[i].vertices;
const len = v.length - 1;
@@ -5599,14 +5599,14 @@ const spawn = {
me.laserAngle = 3 * Math.PI / 5
const seeDistance2 = 200000
spawn.shield(me, x, y);
- me.onDamage = function() {};
- me.do = function() {
+ me.onDamage = function () { };
+ me.do = function () {
this.checkStatus();
this.seePlayerByHistory(15);
this.attraction();
this.sword() //does various things depending on what stage of the sword swing
};
- me.swordWaiting = function() {
+ me.swordWaiting = function () {
if (
this.seePlayer.recall &&
this.cd < simulation.cycle &&
@@ -5631,7 +5631,7 @@ const spawn = {
}
}
me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
- me.swordGrow = function() {
+ me.swordGrow = function () {
this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
this.swordRadius += this.swordRadiusGrowRate
if (this.swordRadius > this.swordRadiusMax || this.isStunned) {
@@ -5639,7 +5639,7 @@ const spawn = {
this.spinCount = 0
}
}
- me.swordSlash = function() {
+ me.swordSlash = function () {
this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
this.torque += this.torqueMagnitude;
this.spinCount++
@@ -5650,8 +5650,8 @@ const spawn = {
this.cd = simulation.cycle + this.delay;
}
}
- me.laserSword = function(where, angle) {
- const vertexCollision = function(v1, v1End, domain) {
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let v = domain[i].vertices;
const len = v.length - 1;
@@ -5721,10 +5721,10 @@ const spawn = {
me.showHealthBar = false;
me.memory = 30;
me.vanishesLeft = Math.ceil(1 + simulation.difficultyMode * 0.5)
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.vanishesLeft > 0 && this.health < 0.1) { //if health is below 10% teleport to a random spot on player history, heal, and cloak
this.vanishesLeft--
@@ -5733,7 +5733,7 @@ const spawn = {
x: this.position.x,
y: this.position.y,
radius: 3000,
- color: `rgba(0, 0, 0,${1-0.1*i})`,
+ color: `rgba(0, 0, 0,${1 - 0.1 * i})`,
time: (i + 2) * 4
});
}
@@ -5749,7 +5749,7 @@ const spawn = {
this.health = 1;
}
};
- me.cloak = function() {
+ me.cloak = function () {
if (!this.isCloaked) { //stealth
this.alpha = 0;
this.isCloaked = true;
@@ -5758,7 +5758,7 @@ const spawn = {
this.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
}
}
- me.deCloak = function() {
+ me.deCloak = function () {
if (this.isCloaked) {
this.damageReduction = 0.4 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
this.isCloaked = false;
@@ -5766,7 +5766,7 @@ const spawn = {
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
}
}
- me.do = function() {
+ me.do = function () {
if (this.damageReduction === 0) {
this.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
let i = this.status.length //clear bad status effects
@@ -5818,7 +5818,7 @@ const spawn = {
me.showHealthBar = false;
me.memory = 240;
me.isVanished = false;
- me.onDamage = function() {
+ me.onDamage = function () {
if (!this.isVanished && this.health < 0.1 && !this.isStunned && !this.isSlowed) { //if health is below 10% teleport to a random spot on player history, heal, and cloak
this.health = 1;
this.isVanished = true
@@ -5829,7 +5829,7 @@ const spawn = {
this.damageReduction = 0 //immune to harm for the rest of this game cycle
}
};
- me.cloak = function() {
+ me.cloak = function () {
if (this.isNotCloaked) { //stealth
this.alpha = 0;
this.isNotCloaked = false;
@@ -5837,7 +5837,7 @@ const spawn = {
this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
}
}
- me.do = function() {
+ me.do = function () {
if (this.damageReduction === 0) {
this.damageReduction = 1 //stop being immune to harm immediately
let i = this.status.length //clear bad status effects
@@ -5895,7 +5895,7 @@ const spawn = {
me.collisionFilter.mask = cat.bullet //| cat.body
me.showHealthBar = false;
me.memory = 480;
- me.do = function() {
+ me.do = function () {
//cap max speed
if (this.speed > 7) {
Matter.Body.setVelocity(this, {
@@ -6014,11 +6014,11 @@ const spawn = {
radiusOrbitals = radius + 125 + 350 * Math.random()
for (let i = 0; i < len; i++) spawn.orbital(me, radiusOrbitals, i / len * 2 * Math.PI, -speed)
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
- me.do = function() {
+ me.do = function () {
// this.armor();
this.seePlayerCheckByDistance();
this.checkStatus();
@@ -6050,11 +6050,11 @@ const spawn = {
x: 0,
y: 0
};
- me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
}
// spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
this.fire();
@@ -6093,11 +6093,11 @@ const spawn = {
setTimeout(() => {
for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1);
}, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
- me.onDeath = function() {
+ me.onDeath = function () {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
};
- me.do = function() {
+ me.do = function () {
// this.armor();
this.seePlayerByLookingAt();
this.checkStatus();
@@ -6152,7 +6152,7 @@ const spawn = {
mobs.spawn(x, y, sides, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass * 15);
};
Matter.Body.setDensity(me, 0.00004); //normal is 0.001
@@ -6167,7 +6167,7 @@ const spawn = {
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
- me.do = function() {
+ me.do = function () {
this.gravity();
this.timeLimit();
};
@@ -6176,10 +6176,10 @@ const spawn = {
mobs.spawn(x, y, sides, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass * 120);
};
- me.onDeath = function() {
+ me.onDeath = function () {
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
@@ -6219,7 +6219,7 @@ const spawn = {
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
- me.do = function() {
+ me.do = function () {
this.gravity();
this.timeLimit();
};
@@ -6250,11 +6250,11 @@ const spawn = {
x: 0,
y: 0
};
- me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
}
// spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
// this.seePlayerByLookingAt();
this.seePlayerCheck();
this.checkStatus();
@@ -6344,7 +6344,7 @@ const spawn = {
mobs.spawn(x, y, sides, radius, "rgb(255,0,155)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass * 20);
};
Matter.Body.setDensity(me, 0.00005); //normal is 0.001
@@ -6359,7 +6359,7 @@ const spawn = {
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
- me.onDeath = function() {
+ me.onDeath = function () {
if (simulation.difficulty > 11) { //explode AoE
const radius = 100 + 0.5 * simulation.difficulty + 50 * Math.random()
if (m.immuneCycle < m.cycle && Vector.magnitude(Vector.sub(this.position, player.position)) < radius) m.damage(0.0003 * radius * simulation.dmgScale);
@@ -6372,7 +6372,7 @@ const spawn = {
});
}
};
- me.do = function() {
+ me.do = function () {
// this.gravity();
this.timeLimit();
if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0 && this.speed < 10) {
@@ -6390,8 +6390,8 @@ const spawn = {
me.friction = 0;
me.frictionAir = 0.015;
spawn.shield(me, x, y);
- me.onDamage = function() {};
- me.do = function() {
+ me.onDamage = function () { };
+ me.do = function () {
this.seePlayerCheck();
this.checkStatus();
this.attraction();
@@ -6420,8 +6420,8 @@ const spawn = {
me.friction = 0;
me.frictionAir = 0.02;
spawn.shield(me, x, y);
- me.onDamage = function() {};
- me.do = function() {
+ me.onDamage = function () { };
+ me.do = function () {
this.seePlayerCheck();
this.checkStatus();
this.attraction();
@@ -6457,12 +6457,12 @@ const spawn = {
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
- me.onDeath = function() {
+ me.onDeath = function () {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
};
- me.onDamage = function() {};
- me.do = function() {
+ me.onDamage = function () { };
+ me.do = function () {
// this.armor();
this.seePlayerCheck();
this.checkStatus();
@@ -6657,7 +6657,7 @@ const spawn = {
spawn.spawnOrbitals(me, radius + 125, 1);
spawn.spawnOrbitals(me, radius + 200, 1);
Matter.Body.setDensity(me, 0.004 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
- me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
setTimeout(() => { //fix mob in place, but allow rotation
for (let i = 0, len = 6; i < len; i++) {
const speed = 2.25 * simulation.accelScale;
@@ -6673,7 +6673,7 @@ const spawn = {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
}
me.grenadeLimiter = 0
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.grenadeLimiter < 240 && this.health > 0) {
this.grenadeLimiter += 60
spawn.grenade(this.position.x, this.position.y, 80 + Math.floor(60 * Math.random()));
@@ -6686,7 +6686,7 @@ const spawn = {
}
};
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
- me.do = function() {
+ me.do = function () {
// this.armor();
if (this.grenadeLimiter > 1) this.grenadeLimiter--
this.seePlayerCheck();
@@ -6714,13 +6714,13 @@ const spawn = {
x: 0,
y: 0
};
- me.onDeath = function() { //helps collisions functions work better after vertex have been changed
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
spawn.grenade(this.position.x, this.position.y, 200 * simulation.CDScale);
// mob[mob.length - 1].collisionFilter.category = 0
mob[mob.length - 1].collisionFilter.mask = cat.player | cat.map;
}
// spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
this.seePlayerCheck();
this.checkStatus();
@@ -6774,7 +6774,7 @@ const spawn = {
mobs.spawn(x, y, 4, size, "rgb(215,0,190)"); //rgb(215,80,190)
let me = mob[mob.length - 1];
me.stroke = "transparent";
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass);
};
Matter.Body.setDensity(me, 0.00004); //normal is 0.001
@@ -6788,7 +6788,7 @@ const spawn = {
me.isDropPowerUp = false;
me.isBadTarget = true;
me.isMobBullet = true;
- me.onDeath = function() {
+ me.onDeath = function () {
//damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.position)) < pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
@@ -6806,7 +6806,7 @@ const spawn = {
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.map | cat.body | cat.player
// me.collisionFilter.mask = 0
- me.do = function() {
+ me.do = function () {
this.timeLimit();
ctx.beginPath(); //draw explosion outline
ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
@@ -6843,15 +6843,15 @@ const spawn = {
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
Matter.Body.setDensity(me, 0.0045); //extra dense //normal is 0.001 //makes effective life much larger
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
};
- me.onDamage = function() {
+ me.onDamage = function () {
this.cycle = 0
};
me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
- me.do = function() {
+ me.do = function () {
Matter.Body.rotate(this, 0.003) //gently spin around
this.checkStatus();
ctx.beginPath(); //draw cycle timer
@@ -6901,17 +6901,17 @@ const spawn = {
me.damageReduction = 0.07 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// requestAnimationFrame(() => { simulation.timePlayerSkip(120) }); //wrapping in animation frame prevents errors, probably
};
- me.onDamage = function() {
+ me.onDamage = function () {
//find side of mob closest to player
//causes lag for foam,laser too many seekers //maybe scale chance with dmg
// const where = Vector.add(this.position, Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.radius + 10))
// spawn.seeker(where.x, where.y); //give the bullet a rotational velocity as if they were attached to a vertex
};
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory(60);
this.attraction();
this.checkStatus();
@@ -6982,13 +6982,13 @@ const spawn = {
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
};
- me.onDamage = function() {};
+ me.onDamage = function () { };
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
- me.do = function() {
+ me.do = function () {
// this.armor();
this.seePlayerCheck();
this.checkStatus();
@@ -7048,7 +7048,7 @@ const spawn = {
mobs.spawn(x, y, sides, radius, "rgb(255,0,255)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
- me.onHit = function() {
+ me.onHit = function () {
this.explode(this.mass * 20);
};
Matter.Body.setDensity(me, 0.000015); //normal is 0.001
@@ -7063,7 +7063,7 @@ const spawn = {
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
- me.do = function() {
+ me.do = function () {
// this.seePlayer.yes = false;
this.alwaysSeePlayer()
this.attraction();
@@ -7076,7 +7076,7 @@ const spawn = {
me.g = 0.0004; //required if using this.gravity
me.leaveBody = false;
// me.isDropPowerUp = false;
- me.onDeath = function() { //run this function on death
+ me.onDeath = function () { //run this function on death
for (let i = 0; i < Math.ceil(this.mass * 0.15 + Math.random() * 2.5); ++i) {
spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
Matter.Body.setVelocity(mob[mob.length - 1], {
@@ -7086,7 +7086,7 @@ const spawn = {
}
};
spawn.shield(me, x, y);
- me.do = function() {
+ me.do = function () {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
@@ -7096,7 +7096,7 @@ const spawn = {
spawns(x, y, radius = 15) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
- me.onHit = function() { //run this function on hitting player
+ me.onHit = function () { //run this function on hitting player
this.explode();
};
// me.stroke = "transparent"
@@ -7110,7 +7110,7 @@ const spawn = {
me.leaveBody = false;
me.seePlayerFreq = Math.floor((80 + 50 * Math.random()));
me.frictionAir = 0.004;
- me.do = function() {
+ me.do = function () {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
@@ -7167,12 +7167,12 @@ const spawn = {
exploder(x, y, radius = 40 + Math.ceil(Math.random() * 50)) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
- me.onHit = function() {
+ me.onHit = function () {
//run this function on hitting player
this.explode();
};
me.g = 0.0004; //required if using this.gravity
- me.do = function() {
+ me.do = function () {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
@@ -7196,9 +7196,9 @@ const spawn = {
me.damageReduction = 0
me.isInvulnerable = true
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0, len = mob.length; i < len; i++) {
if (this.id === mob[i].snakeHeadID && mob[i].alive) mob[i].death()
@@ -7208,7 +7208,7 @@ const spawn = {
me.canFire = false;
me.closestVertex1 = 0;
me.cycle = 0
- me.do = function() {
+ me.do = function () {
// this.armor();
this.seePlayerByHistory(40)
this.checkStatus();
@@ -7334,13 +7334,13 @@ const spawn = {
me.ellipticity = 0.3
me.angleOff = 0.4
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0, len = mob.length; i < len; i++) {
if (this.id === mob[i].snakeHeadID && mob[i].alive) mob[i].death()
}
};
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory(40)
this.checkStatus();
this.attraction();
@@ -7361,7 +7361,7 @@ const spawn = {
a = Math.atan2(this.velocity.y, this.velocity.x)
}
- ctx.fillStyle = `hsla(${160+40*Math.random()}, 100%, ${25 + 25*Math.random()*Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
this.wing(a + Math.PI / 2 + this.angleOff + this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
this.wing(a - Math.PI / 2 - this.angleOff - this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
this.wing(a - Math.PI / 2 + this.angleOff + this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
@@ -7375,7 +7375,7 @@ const spawn = {
angle -= 0.1
spawn.snakeBody(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), i === 0 ? 25 : 20);
const who = mob[mob.length - 1]
- who.fill = `hsl(${160+40*Math.random()}, 100%, ${5 + 25*Math.random()*Math.random()}%)`
+ who.fill = `hsl(${160 + 40 * Math.random()}, 100%, ${5 + 25 * Math.random() * Math.random()}%)`
if (i < 4) who.snakeHeadID = me.id
if (i === 0) me.snakeBody1 = who //track this segment, so the difference in position between this segment and the head can be used to angle the wings
who.previousTailID = previousTailID
@@ -7421,7 +7421,7 @@ const spawn = {
me.frictionAir = 0;
me.isSnakeTail = true;
me.stroke = "transparent"
- me.onDeath = function() {
+ me.onDeath = function () {
setTimeout(() => {
for (let i = 0, len = mob.length; i < len; i++) {
if (this.id === mob[i].previousTailID && mob[i].alive) mob[i].death()
@@ -7432,7 +7432,7 @@ const spawn = {
}
}, 500);
};
- me.do = function() {
+ me.do = function () {
this.checkStatus();
};
// me.doActive = function() {
@@ -7467,12 +7467,12 @@ const spawn = {
spawn.shield(me, x, y, 1);
setTimeout(() => { spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
this.removeCons(); //remove constraint
me.babies(0.05 * simulation.difficulty + 1)
};
- me.babies = function(len) {
+ me.babies = function (len) {
const delay = Math.max(3, Math.floor(15 - len / 2))
let i = 0
let spawnFlutters = () => {
@@ -7499,7 +7499,7 @@ const spawn = {
}
requestAnimationFrame(spawnFlutters);
}
- me.onDamage = function() {
+ me.onDamage = function () {
if (this.health < this.nextHealthThreshold && this.alive) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4
@@ -7508,7 +7508,7 @@ const spawn = {
this.damageReduction = 0
}
};
- me.do = function() {
+ me.do = function () {
this.gravity();
if (this.isInvulnerable) {
this.repulsion();
@@ -7531,7 +7531,7 @@ const spawn = {
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 13 + 5 * Math.random();
- ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
} else {
this.seePlayerCheck();
@@ -7560,7 +7560,7 @@ const spawn = {
});
Composite.add(engine.world, consBB[consBB.length - 1]);
- me.onDamage = function() {
+ me.onDamage = function () {
//make sure the mob that owns the shield can tell when damage is done
this.alertNearByMobs();
this.fill = `rgba(220,220,255,${0.3 + 0.6 * this.health})`
@@ -7572,13 +7572,13 @@ const spawn = {
me.shieldTargetID = target.id
target.isShielded = true;
target.shieldID = me.id
- me.onDeath = function() {
+ me.onDeath = function () {
//clear isShielded status from target
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].id === this.shieldTargetID) mob[i].isShielded = false;
}
};
- me.do = function() {
+ me.do = function () {
this.checkStatus();
};
@@ -7611,11 +7611,11 @@ const spawn = {
});
Composite.add(engine.world, consBB[consBB.length - 1]);
}
- me.onDamage = function() {
+ me.onDamage = function () {
this.alertNearByMobs(); //makes sure the mob that owns the shield can tell when damage is done
this.fill = `rgba(220,220,255,${0.3 + 0.6 * this.health})`
};
- me.onDeath = function() {
+ me.onDeath = function () {
//clear isShielded status from target
for (let j = 0; j < targets.length; j++) {
for (let i = 0, len = mob.length; i < len; i++) {
@@ -7628,7 +7628,7 @@ const spawn = {
me.showHealthBar = false;
mob[mob.length - 1] = mob[mob.length - 1 - nodes];
mob[mob.length - 1 - nodes] = me;
- me.do = function() {
+ me.do = function () {
this.checkStatus();
};
},
@@ -7656,7 +7656,7 @@ const spawn = {
// me.isShielded = true
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
- me.do = function() {
+ me.do = function () {
//if host is gone
if (!who || !who.alive) {
this.death();
@@ -7717,10 +7717,10 @@ const spawn = {
}
for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1);
- me.onDeath = function() {
+ me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
- me.do = function() {
+ me.do = function () {
this.seePlayerByHistory();
this.checkStatus();
this.attraction();
@@ -7889,7 +7889,7 @@ const spawn = {
me.isBadTarget = true;
me.isUnblockable = true;
- me.do = function() {
+ me.do = function () {
let wireX = -50;
let wireY = -1000;
if (this.freeOfWires) {
@@ -7958,7 +7958,7 @@ const spawn = {
me.isBadTarget = true;
me.isUnblockable = true;
- me.do = function() {
+ me.do = function () {
let wireX = -50 - 20;
let wireY = -1000;
@@ -8010,7 +8010,7 @@ const spawn = {
me.isBadTarget = true;
me.isUnblockable = true;
- me.do = function() {
+ me.do = function () {
let wireX = -50 - 35;
let wireY = -1000;
@@ -8061,7 +8061,7 @@ const spawn = {
me.isBadTarget = true;
me.isUnblockable = true;
- me.do = function() {
+ me.do = function () {
let wireX = -50 + 16;
let wireY = -1000;
@@ -8112,7 +8112,7 @@ const spawn = {
me.isBadTarget = true;
me.isUnblockable = true;
- me.do = function() {
+ me.do = function () {
let wireX = -50 + 26;
let wireY = -1000;
diff --git a/js/tech.js b/js/tech.js
index fa1be3b..98f4a27 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -242,7 +242,7 @@ const tech = {
if (tech.isDamageForGuns) dmg *= 1 + 0.22 * Math.max(0, b.inventory.length - 1)
if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25
if (tech.isAcidDmg && m.health > 1) dmg *= 1.35;
- if (tech.isRerollDamage) dmg *= 1 + 0.03 * powerUps.research.count
+ if (tech.isRerollDamage) dmg *= 1 + Math.max(0, 0.03 * powerUps.research.count)
if (tech.isBotDamage) dmg *= 1 + 0.06 * b.totalBots()
if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage
if (tech.isLowEnergyDamage) dmg *= 1 + 0.7 * Math.max(0, 1 - m.energy)
@@ -308,9161 +308,9160 @@ const tech = {
}
},
tech: [{
- name: "tungsten carbide",
- description: "
+200 maximum
healthlose health after hard
landings",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isSkin: true,
- allowed() {
- return !m.isAltSkin
- },
- requires: "not skin",
- effect() {
- tech.hardLanding = 70
- tech.isFallingDamage = true;
- m.setMaxHealth();
- m.addHealth(1 / simulation.healScale)
- m.skin.tungsten()
- },
- remove() {
- tech.hardLanding = 130
- tech.isFallingDamage = false;
- m.setMaxHealth();
- if (this.count) m.resetSkin();
- }
+ name: "tungsten carbide",
+ description: "
+200 maximum
healthlose health after hard
landings",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin
},
- {
- name: "elasticity",
- description: "
+33% movement and
jumping+30% defense",
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isSkin: true,
- allowed() {
- return !m.isAltSkin
- },
- requires: "not skinned",
- effect() {
- m.skin.mech();
- tech.hardLanding = 110
- tech.squirrelFx += 0.4;
- tech.squirrelJump += 0.16;
- m.setMovement()
- },
- remove() {
- tech.hardLanding = 130
- tech.squirrelFx = 1;
- tech.squirrelJump = 1;
- m.setMovement()
- if (this.count) m.resetSkin();
- }
+ requires: "not skin",
+ effect() {
+ tech.hardLanding = 70
+ tech.isFallingDamage = true;
+ m.setMaxHealth();
+ m.addHealth(1 / simulation.healScale)
+ m.skin.tungsten()
},
- {
- name: "aperture",
- description: "every
6 seconds your
damage cycles
between
-50% and
+150% damage",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isSkin: true,
- allowed() {
- return !m.isAltSkin
- },
- requires: "not skinned",
- effect() {
- tech.isDilate = true
- m.skin.dilate()
- },
- remove() {
- tech.isDilate = false
- if (this.count) m.resetSkin();
- }
+ remove() {
+ tech.hardLanding = 130
+ tech.isFallingDamage = false;
+ m.setMaxHealth();
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "elasticity",
+ description: "
+33% movement and
jumping+30% defense",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin
},
- {
- name: "diaphragm",
- description: "every
6 seconds your
defense cycles
between
+100% and
-33% defense",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isSkin: true,
- allowed() {
- return tech.isDilate
- },
- requires: "aperture",
- effect() {
- tech.isDiaphragm = true
- m.resetSkin();
- m.skin.dilate2()
- },
- remove() {
- tech.isDiaphragm = false
- if (this.count) m.resetSkin();
- }
+ requires: "not skinned",
+ effect() {
+ m.skin.mech();
+ tech.hardLanding = 110
+ tech.squirrelFx += 0.4;
+ tech.squirrelJump += 0.16;
+ m.setMovement()
},
- {
- name: "mass-energy equivalence",
- // description: "
energy protects you instead of
health√ of
defense reduction reduces max
energy",
- description: "
energy protects you instead of
healthexponentially
reduced defense (~ x^0.13)",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isSkin: true,
- allowed() {
- return !m.isAltSkin && !tech.isPiezo && !tech.isRewindAvoidDeath && !tech.isAnnihilation //&& !tech.isAmmoFromHealth && !tech.isRewindGun
- },
- requires: "not piezoelectricity, CPT, annihilation",
- effect() {
- m.health = 0
- document.getElementById("health").style.display = "none"
- document.getElementById("health-bg").style.display = "none"
- document.getElementById("dmg").style.backgroundColor = "#0cf";
- tech.isEnergyHealth = true;
- simulation.mobDmgColor = "rgba(0, 255, 255,0.6)" //"#0cf"
+ remove() {
+ tech.hardLanding = 130
+ tech.squirrelFx = 1;
+ tech.squirrelJump = 1;
+ m.setMovement()
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "aperture",
+ description: "every
6 seconds your
damage cycles
between
-50% and
+150% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin
+ },
+ requires: "not skinned",
+ effect() {
+ tech.isDilate = true
+ m.skin.dilate()
+ },
+ remove() {
+ tech.isDilate = false
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "diaphragm",
+ description: "every
6 seconds your
defense cycles
between
+100% and
-33% defense",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isSkin: true,
+ allowed() {
+ return tech.isDilate
+ },
+ requires: "aperture",
+ effect() {
+ tech.isDiaphragm = true
+ m.resetSkin();
+ m.skin.dilate2()
+ },
+ remove() {
+ tech.isDiaphragm = false
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "mass-energy equivalence",
+ // description: "
energy protects you instead of
health√ of
defense reduction reduces max
energy",
+ description: "
energy protects you instead of
healthexponentially
reduced defense (~ x^0.13)",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin && !tech.isPiezo && !tech.isRewindAvoidDeath && !tech.isAnnihilation //&& !tech.isAmmoFromHealth && !tech.isRewindGun
+ },
+ requires: "not piezoelectricity, CPT, annihilation",
+ effect() {
+ m.health = 0
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("dmg").style.backgroundColor = "#0cf";
+ tech.isEnergyHealth = true;
+ simulation.mobDmgColor = "rgba(0, 255, 255,0.6)" //"#0cf"
+ m.displayHealth();
+ m.lastCalculatedDefense = 0 //this triggers a redraw of the defense bar
+ m.skin.energy();
+ },
+ remove() {
+ if (tech.isEnergyHealth) {
+ tech.isEnergyHealth = false;
+ document.getElementById("health").style.display = "inline"
+ document.getElementById("health-bg").style.display = "inline"
+ document.getElementById("dmg").style.backgroundColor = "#f67";
+ m.health = Math.max(Math.min(m.maxHealth, m.energy), 0.1);
+ simulation.mobDmgColor = "rgba(255,0,0,0.7)"
m.displayHealth();
m.lastCalculatedDefense = 0 //this triggers a redraw of the defense bar
- m.skin.energy();
- },
- remove() {
- if (tech.isEnergyHealth) {
- tech.isEnergyHealth = false;
- document.getElementById("health").style.display = "inline"
- document.getElementById("health-bg").style.display = "inline"
- document.getElementById("dmg").style.backgroundColor = "#f67";
- m.health = Math.max(Math.min(m.maxHealth, m.energy), 0.1);
- simulation.mobDmgColor = "rgba(255,0,0,0.7)"
- m.displayHealth();
- m.lastCalculatedDefense = 0 //this triggers a redraw of the defense bar
- m.resetSkin();
- }
- tech.isEnergyHealth = false;
+ m.resetSkin();
+ }
+ tech.isEnergyHealth = false;
+ }
+ },
+ {
+ name: "1st ionization energy",
+ link: `
1st ionization energy`,
+ // description: `after you collect ${powerUps.orb.heal()}
+${0.1 * tech.largerHeals} maximum
energy`,
+ // descriptionFunction: `convert current and future ${powerUps.orb.heal()} into
give
+${10 * tech.largerHeals} maximum
energy`,
+ descriptionFunction() {
+ return `convert current and future
into
give
+${8 * tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)} maximum
energy`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isEnergyHealth
+ },
+ requires: "mass-energy equivalence",
+ effect() {
+ powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
+ powerUps.heal.color = "#ff0" //"#0ae"
+ for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
+ if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
}
},
- {
- name: "1st ionization energy",
- link: `
1st ionization energy`,
- // description: `after you collect ${powerUps.orb.heal()}
+${0.1 * tech.largerHeals} maximum
energy`,
- // descriptionFunction: `convert current and future ${powerUps.orb.heal()} into
give
+${10 * tech.largerHeals} maximum
energy`,
- descriptionFunction() {
- return `convert current and future
into
give
+${8 * tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)} maximum
energy`
- },
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isEnergyHealth
- },
- requires: "mass-energy equivalence",
- effect() {
- powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
- powerUps.heal.color = "#ff0" //"#0ae"
- for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
- if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
- }
- },
- remove() {
- powerUps.healGiveMaxEnergy = false;
- // tech.healMaxEnergyBonus = 0
- powerUps.heal.color = "#0eb"
- for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
- if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
+ remove() {
+ powerUps.healGiveMaxEnergy = false;
+ // tech.healMaxEnergyBonus = 0
+ powerUps.heal.color = "#0eb"
+ for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
+ if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
+ }
+ }
+ },
+ {
+ name: "CPT symmetry",
+ // description: "
charge,
parity, and
time invert to undo
defenserewind (1.5—5) seconds for
(66—220) energy",
+ // description: "after losing
health, if you have
full energyrewind time for
44 energy per second",
+ descriptionFunction() {
+ return `after losing
health, if you have
${(100 * Math.min(100, m.maxEnergy)).toFixed(0)} energyrewind time for
40 energy per second`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin && m.fieldUpgrades[m.fieldMode].name !== "standing wave" && !tech.isRewindField && !tech.isEnergyHealth
+ },
+ requires: "not skinned, standing wave, max energy reduction, retrocausality, mass-energy",
+ effect() {
+ tech.isRewindAvoidDeath = true;
+ m.skin.CPT()
+ },
+ remove() {
+ tech.isRewindAvoidDeath = false;
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "causality bots",
+ link: `
causality bots`,
+ description: "when you
rewind build scrap
botsthat protect you for about
9 seconds",
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return tech.isRewindAvoidDeath || tech.isRewindField
+ },
+ requires: "CPT, retrocausality",
+ effect() {
+ tech.isRewindBot++;
+ },
+ remove() {
+ tech.isRewindBot = 0;
+ }
+ },
+ {
+ name: "causality bombs",
+ link: `
causality bombs`,
+ description: "when you
rewind drop several
grenadesbecome
invulnerable until they
explode",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isRewindAvoidDeath || tech.isRewindField
+ },
+ requires: "CPT, retrocausality",
+ effect() {
+ tech.isRewindGrenade = true;
+ },
+ remove() {
+ tech.isRewindGrenade = false;
+ }
+ },
+ {
+ name: "ternary", //"divisor",
+ descriptionFunction() {
+ return `
+40% damage while one of your
gunshas
ammo divisible by
3`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ // divisible: 3, // + Math.floor(6 * Math.random()),
+ effect() {
+ tech.isDivisor = true;
+ },
+ remove() {
+ tech.isDivisor = false;
+ }
+ },
+ {
+ name: "ordnance",
+ description: "
double the
frequency of finding
guntechspawn a
gun and
+7% JUNK to
tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2
+ }
+ this.refundAmount += tech.addJunkTechToPool(0.07)
+ },
+ refundAmount: 0,
+ remove() {
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "ad hoc",
+ descriptionFunction() {
+ return `spawn a ${powerUps.orb.heal()}, ${powerUps.orb.research(1)}, ${powerUps.orb.ammo(1)},
field,
gun, or
techfor each of your
guns`
+ },
+ maxCount: 1, //random power up
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ allowed() {
+ return b.inventory.length > 1
+ },
+ requires: "at least 2 guns",
+ effect() {
+ for (let i = 0; i < b.inventory.length; i++) {
+ if (Math.random() < 1 / 6) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
+ } else if (Math.random() < 1 / 5) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "tech");
+ } else if (Math.random() < 1 / 4) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
+ } else if (Math.random() < 1 / 3) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "heal");
+ } else if (Math.random() < 1 / 2) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "ammo");
+ } else {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "research");
}
}
},
- {
- name: "CPT symmetry",
- // description: "
charge,
parity, and
time invert to undo
defenserewind (1.5—5) seconds for
(66—220) energy",
- // description: "after losing
health, if you have
full energyrewind time for
44 energy per second",
- descriptionFunction() {
- return `after losing
health, if you have
${(100*Math.min(100,m.maxEnergy)).toFixed(0)} energyrewind time for
40 energy per second`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isSkin: true,
- allowed() {
- return !m.isAltSkin && m.fieldUpgrades[m.fieldMode].name !== "standing wave" && !tech.isRewindField && !tech.isEnergyHealth
- },
- requires: "not skinned, standing wave, max energy reduction, retrocausality, mass-energy",
- effect() {
- tech.isRewindAvoidDeath = true;
- m.skin.CPT()
- },
- remove() {
- tech.isRewindAvoidDeath = false;
- if (this.count) m.resetSkin();
- }
+ remove() { }
+ },
+ {
+ name: "applied science",
+ description: `get a random
guntechfor each of your
guns`, //spawn ${powerUps.orb.research(1)} and
+ maxCount: 9,
+ count: 0,
+ isNonRefundable: true,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return b.inventory.length > 1
},
- {
- name: "causality bots",
- link: `
causality bots`,
- description: "when you
rewind build scrap
botsthat protect you for about
9 seconds",
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBotTech: true,
- allowed() {
- return tech.isRewindAvoidDeath || tech.isRewindField
- },
- requires: "CPT, retrocausality",
- effect() {
- tech.isRewindBot++;
- },
- remove() {
- tech.isRewindBot = 0;
- }
- },
- {
- name: "causality bombs",
- link: `
causality bombs`,
- description: "when you
rewind drop several
grenadesbecome
invulnerable until they
explode",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isRewindAvoidDeath || tech.isRewindField
- },
- requires: "CPT, retrocausality",
- effect() {
- tech.isRewindGrenade = true;
- },
- remove() {
- tech.isRewindGrenade = false;
- }
- },
- {
- name: "ternary", //"divisor",
- descriptionFunction() {
- return `
+40% damage while one of your
gunshas
ammo divisible by
3`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- // divisible: 3, // + Math.floor(6 * Math.random()),
- effect() {
- tech.isDivisor = true;
- },
- remove() {
- tech.isDivisor = false;
- }
- },
- {
- name: "ordnance",
- description: "
double the
frequency of finding
guntechspawn a
gun and
+7% JUNK to
tech pool",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed: () => true,
- requires: "",
- effect() {
- powerUps.spawn(m.pos.x, m.pos.y, "gun");
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2
- }
- this.refundAmount += tech.addJunkTechToPool(0.07)
- },
- refundAmount: 0,
- remove() {
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
- }
- }
- },
- {
- name: "ad hoc",
- descriptionFunction() {
- return `spawn a ${powerUps.orb.heal()}, ${powerUps.orb.research(1)}, ${powerUps.orb.ammo(1)},
field,
gun, or
techfor each of your
guns`
- },
- maxCount: 1, //random power up
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- allowed() {
- return b.inventory.length > 1
- },
- requires: "at least 2 guns",
- effect() {
- for (let i = 0; i < b.inventory.length; i++) {
- if (Math.random() < 1 / 6) {
- powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
- } else if (Math.random() < 1 / 5) {
- powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "tech");
- } else if (Math.random() < 1 / 4) {
- powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
- } else if (Math.random() < 1 / 3) {
- powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "heal");
- } else if (Math.random() < 1 / 2) {
- powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "ammo");
- } else {
- powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "research");
+ requires: "at least 2 guns",
+ effect() {
+ for (let i = b.inventory.length - 1; i > -1; i--) { //backwards because some tech can remove or add guns
+ const gunTechPool = [] //find gun tech for this gun
+ for (let j = 0, len = tech.tech.length; j < len; j++) {
+ // console.log(j, tech.tech[j].isGunTech, tech.tech[j].allowed(), !tech.tech[j].isJunk, !tech.tech[j].isBadRandomOption, tech.tech[j].count < tech.tech[j].maxCount)
+ const originalActiveGunIndex = b.activeGun //set current gun to active so allowed works
+ b.activeGun = b.inventory[i] //to make the .allowed work for guns that aren't active
+ if (tech.tech[j].isGunTech && tech.tech[j].allowed() && !tech.tech[j].isJunk && !tech.tech[j].isBadRandomOption && tech.tech[j].count < tech.tech[j].maxCount) {
+ const regex = tech.tech[j].requires.search(b.guns[b.inventory[i]].name) //get string index of gun name
+ const not = tech.tech[j].requires.search(' not ') //get string index of ' not '
+ if (regex !== -1 && (not === -1 || not > regex)) gunTechPool.push(j) //look for the gun name in the requirements, but the gun name needs to show up before the word ' not '
}
- }
- },
- remove() {}
- },
- {
- name: "applied science",
- description: `get a random
guntechfor each of your
guns`, //spawn ${powerUps.orb.research(1)} and
- maxCount: 9,
- count: 0,
- isNonRefundable: true,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return b.inventory.length > 1
- },
- requires: "at least 2 guns",
- effect() {
- for (let i = b.inventory.length - 1; i > -1; i--) { //backwards because some tech can remove or add guns
- const gunTechPool = [] //find gun tech for this gun
- for (let j = 0, len = tech.tech.length; j < len; j++) {
- // console.log(j, tech.tech[j].isGunTech, tech.tech[j].allowed(), !tech.tech[j].isJunk, !tech.tech[j].isBadRandomOption, tech.tech[j].count < tech.tech[j].maxCount)
- const originalActiveGunIndex = b.activeGun //set current gun to active so allowed works
- b.activeGun = b.inventory[i] //to make the .allowed work for guns that aren't active
- if (tech.tech[j].isGunTech && tech.tech[j].allowed() && !tech.tech[j].isJunk && !tech.tech[j].isBadRandomOption && tech.tech[j].count < tech.tech[j].maxCount) {
- const regex = tech.tech[j].requires.search(b.guns[b.inventory[i]].name) //get string index of gun name
- const not = tech.tech[j].requires.search(' not ') //get string index of ' not '
- if (regex !== -1 && (not === -1 || not > regex)) gunTechPool.push(j) //look for the gun name in the requirements, but the gun name needs to show up before the word ' not '
+ b.activeGun = originalActiveGunIndex
+ if (!b.guns[b.activeGun].have) {
+ if (b.inventory.length === 0) {
+ b.activeGun = null
+ } else {
+ b.activeGun = b.inventory[0]
}
- b.activeGun = originalActiveGunIndex
- if (!b.guns[b.activeGun].have) {
- if (b.inventory.length === 0) {
- b.activeGun = null
- } else {
- b.activeGun = b.inventory[0]
- }
- b.inventoryGun = 0;
- }
- }
- if (gunTechPool.length) {
- const index = Math.floor(Math.random() * gunTechPool.length)
- tech.giveTech(gunTechPool[index]) // choose from the gun pool
- tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under paradigm shift
- simulation.makeTextLog(`
tech.giveTech("
${tech.tech[gunTechPool[index]].name}")`, 360)
+ b.inventoryGun = 0;
}
}
- simulation.boldActiveGunHUD();
- },
- remove() {}
- },
- {
- name: "arsenal",
- descriptionFunction() {
- return `
+22% damage per unequipped
gun (${(22 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => b.inventory.length > 1,
- requires: "at least 2 guns",
- effect() {
- tech.isDamageForGuns = true;
- },
- remove() {
- tech.isDamageForGuns = false;
- }
- },
- {
- name: "active cooling",
- descriptionFunction() {
- return `
+28% fire rate per unequipped
gun (${(28 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)`
- }, //
but not including your equipped
gun` },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => b.inventory.length > 1,
- requires: "at least 2 guns",
- effect() {
- tech.isFireRateForGuns = true;
- b.setFireCD();
- },
- remove() {
- tech.isFireRateForGuns = false;
- b.setFireCD();
- }
- },
- {
- name: "pigeonhole principle",
- descriptionFunction() {
- let info = ""
- if (this.count > 0 && Number.isInteger(tech.buffedGun) && b.inventory.length) {
- let gun = b.guns[b.inventory[tech.buffedGun]].name
- info = `
this level:
+${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for
${gun}`
+ if (gunTechPool.length) {
+ const index = Math.floor(Math.random() * gunTechPool.length)
+ tech.giveTech(gunTechPool[index]) // choose from the gun pool
+ tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under paradigm shift
+ simulation.makeTextLog(`
tech.giveTech("
${tech.tech[gunTechPool[index]].name}")`, 360)
}
- return `
+ }
+ simulation.boldActiveGunHUD();
+ },
+ remove() { }
+ },
+ {
+ name: "arsenal",
+ descriptionFunction() {
+ return `
+22% damage per unequipped
gun (${(22 * Math.max(0, b.inventory.length - 1)).toFixed(0)}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => b.inventory.length > 1,
+ requires: "at least 2 guns",
+ effect() {
+ tech.isDamageForGuns = true;
+ },
+ remove() {
+ tech.isDamageForGuns = false;
+ }
+ },
+ {
+ name: "active cooling",
+ descriptionFunction() {
+ return `
+28% fire rate per unequipped
gun (${(28 * Math.max(0, b.inventory.length - 1)).toFixed(0)}%)`
+ }, //
but not including your equipped
gun` },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => b.inventory.length > 1,
+ requires: "at least 2 guns",
+ effect() {
+ tech.isFireRateForGuns = true;
+ b.setFireCD();
+ },
+ remove() {
+ tech.isFireRateForGuns = false;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "pigeonhole principle",
+ descriptionFunction() {
+ let info = ""
+ if (this.count > 0 && Number.isInteger(tech.buffedGun) && b.inventory.length) {
+ let gun = b.guns[b.inventory[tech.buffedGun]].name
+ info = `
this level:
+${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for
${gun}`
+ }
+ return `
a new
gun is
chosen to be improved each
level
+31% damage per
gun for the
chosen gun${info}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return b.inventory.length > 1
- },
- requires: "at least 2 guns",
- effect() {
- tech.isGunChoice = true
- //switches gun on new level
- //generalist uses the same chosen gun so they match
- },
- remove() {
- tech.isGunChoice = false;
- }
},
- {
- name: "generalist",
- description: "spawn
7 guns, but you can't
switch gunsyour equipped
gun cycles after each level",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return b.inventory.length < b.guns.length - 5 && b.inventory.length > 1
- },
- requires: "at least 2 guns, at least 5 unclaimed guns",
- effect() {
- tech.isGunCycle = true;
- for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
- },
- remove() {
- if (!this.count) tech.isGunCycle = false; // only set to false if you don't have this tech
- // if (tech.isGunCycle) {
- // for (let i = 0; i < 8; i++) {
- // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
- // }
- // tech.isGunCycle = false;
- // }
- }
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return b.inventory.length > 1
},
- {
- name: "integrated armament",
- link: `
integrated armament`,
- description: `
+25% damage, but new guns
replace your current gun and convert guntech`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return b.inventory.length === 1
- },
- requires: "only 1 gun",
- effect() {
- tech.isOneGun = true;
- },
- remove() {
- tech.isOneGun = false;
- }
+ requires: "at least 2 guns",
+ effect() {
+ tech.isGunChoice = true
+ //switches gun on new level
+ //generalist uses the same chosen gun so they match
},
- {
- name: "supply chain",
- descriptionFunction() {
- return `double your current
ammo+4% JUNK to
tech pool`
- },
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
+ remove() {
+ tech.isGunChoice = false;
+ }
+ },
+ {
+ name: "generalist",
+ description: "spawn
7 guns, but you can't
switch gunsyour equipped
gun cycles after each level",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return b.inventory.length < b.guns.length - 5 && b.inventory.length > 1
+ },
+ requires: "at least 2 guns, at least 5 unclaimed guns",
+ effect() {
+ tech.isGunCycle = true;
+ for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
+ },
+ remove() {
+ if (!this.count) tech.isGunCycle = false; // only set to false if you don't have this tech
+ // if (tech.isGunCycle) {
+ // for (let i = 0; i < 8; i++) {
+ // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
+ // }
+ // tech.isGunCycle = false;
+ // }
+ }
+ },
+ {
+ name: "integrated armament",
+ link: `
integrated armament`,
+ description: `
+25% damage, but new guns
replace your current gun and convert guntech`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return b.inventory.length === 1
+ },
+ requires: "only 1 gun",
+ effect() {
+ tech.isOneGun = true;
+ },
+ remove() {
+ tech.isOneGun = false;
+ }
+ },
+ {
+ name: "supply chain",
+ descriptionFunction() {
+ return `double your current
ammo+4% JUNK to
tech pool`
+ },
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < b.guns.length; i++) {
+ if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo)
+ }
+ simulation.makeGunHUD();
+ this.refundAmount += tech.addJunkTechToPool(0.04)
+ },
+ refundAmount: 0,
+ remove() {
+ for (let j = 0; j < this.count; j++) {
for (let i = 0; i < b.guns.length; i++) {
- if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo)
- }
- simulation.makeGunHUD();
- this.refundAmount += tech.addJunkTechToPool(0.04)
- },
- refundAmount: 0,
- remove() {
- for (let j = 0; j < this.count; j++) {
- for (let i = 0; i < b.guns.length; i++) {
- if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo)
- }
- }
- simulation.makeGunHUD();
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
+ if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo)
}
}
- },
- {
- name: "logistics",
- description: `${powerUps.orb.ammo()} give
80% more
ammo, but
it's only added to your current
gun`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isEnergyNoAmmo
- },
- requires: "not non-renewables",
- effect() {
- tech.isAmmoForGun = true;
- },
- remove() {
- tech.isAmmoForGun = false;
+ simulation.makeGunHUD();
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
}
+ }
+ },
+ {
+ name: "logistics",
+ description: `${powerUps.orb.ammo()} give
80% more
ammo, but
it's only added to your current
gun`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
},
- {
- name: "cache",
- link: `
cache`,
- description: `${powerUps.orb.ammo()} give
1500% more
ammo, but
you can't
store any more
ammo than that`,
- // ammo powerups always max out your gun,
- // but the maximum ammo ti limited
- // description: `${powerUps.orb.ammo()} give
13x more
ammo, but
you can't
store any more
ammo than that`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isEnergyNoAmmo
- },
- requires: "not non-renewables",
- effect() {
- tech.ammoCap = 15;
- powerUps.ammo.effect()
- },
- remove() {
- tech.ammoCap = 0;
- }
+ requires: "not non-renewables",
+ effect() {
+ tech.isAmmoForGun = true;
},
- {
- name: "catabolism",
- descriptionFunction() {
- return `if you fire while
out of
ammospawn ${powerUps.orb.ammo(4)} and ${tech.isEnergyHealth ? "
–4 maximum
energy" : "
–2 maximum
health"}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isEnergyNoAmmo
- },
- requires: "not non-renewables",
- effect() {
- tech.isAmmoFromHealth = true;
- },
- remove() {
- tech.isAmmoFromHealth = false;
- }
+ remove() {
+ tech.isAmmoForGun = false;
+ }
+ },
+ {
+ name: "cache",
+ link: `
cache`,
+ description: `${powerUps.orb.ammo()} give
1500% more
ammo, but
you can't
store any more
ammo than that`,
+ // ammo powerups always max out your gun,
+ // but the maximum ammo ti limited
+ // description: `${powerUps.orb.ammo()} give
13x more
ammo, but
you can't
store any more
ammo than that`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
},
- {
- name: "non-renewables",
- description: `
+67% damage${powerUps.orb.ammo()} can't
spawn`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isAmmoFromHealth && !tech.isBoostReplaceAmmo
- },
- requires: "not catabolism, quasiparticles",
- damage: 1.67,
- effect() {
- tech.damage *= this.damage
- tech.isEnergyNoAmmo = true;
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isEnergyNoAmmo = false;
- }
+ requires: "not non-renewables",
+ effect() {
+ tech.ammoCap = 15;
+ powerUps.ammo.effect()
},
- {
- name: "desublimated ammunition",
- link: `
desublimated ammunition`,
- description: `if
crouchingalternating shots use no
ammo`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.crouchAmmoCount = true
- },
- remove() {
- tech.crouchAmmoCount = false;
- }
+ remove() {
+ tech.ammoCap = 0;
+ }
+ },
+ {
+ name: "catabolism",
+ descriptionFunction() {
+ return `if you fire while
out of
ammospawn ${powerUps.orb.ammo(4)} and ${tech.isEnergyHealth ? "
–4 maximum
energy" : "
–2 maximum
health"}`
},
- {
- name: "gun turret",
- description: "if
crouching+66% defense ",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isTurret = true
- },
- remove() {
- tech.isTurret = false;
- }
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
},
- {
- name: "dead reckoning",
- description: "if your
speed is 0
+50% damage",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.restDamage += 0.5
- },
- remove() {
- tech.restDamage = 1;
- }
+ requires: "not non-renewables",
+ effect() {
+ tech.isAmmoFromHealth = true;
},
- {
- name: "kinetic bombardment",
- description: "far away mobs take more
damageup to
+33% damage at
3000 displacement",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isFarAwayDmg = true; //used in mob.damage()
- },
- remove() {
- tech.isFarAwayDmg = false;
- }
+ remove() {
+ tech.isAmmoFromHealth = false;
+ }
+ },
+ {
+ name: "non-renewables",
+ description: `
+67% damage${powerUps.orb.ammo()} can't
spawn`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isAmmoFromHealth && !tech.isBoostReplaceAmmo
},
- {
- name: "Higgs mechanism",
- description: "
+45% fire ratewhile
firing your
position is fixed",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple
- },
- requires: "not ship mode, automatic, grappling hook",
- effect() {
- tech.isFireMoveLock = true;
+ requires: "not catabolism, quasiparticles",
+ damage: 1.67,
+ effect() {
+ tech.damage *= this.damage
+ tech.isEnergyNoAmmo = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isEnergyNoAmmo = false;
+ }
+ },
+ {
+ name: "desublimated ammunition",
+ link: `
desublimated ammunition`,
+ description: `if
crouchingalternating shots use no
ammo`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.crouchAmmoCount = true
+ },
+ remove() {
+ tech.crouchAmmoCount = false;
+ }
+ },
+ {
+ name: "gun turret",
+ description: "if
crouching+66% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isTurret = true
+ },
+ remove() {
+ tech.isTurret = false;
+ }
+ },
+ {
+ name: "dead reckoning",
+ description: "if your
speed is 0
+50% damage",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.restDamage += 0.5
+ },
+ remove() {
+ tech.restDamage = 1;
+ }
+ },
+ {
+ name: "kinetic bombardment",
+ description: "far away mobs take more
damageup to
+33% damage at
3000 displacement",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isFarAwayDmg = true; //used in mob.damage()
+ },
+ remove() {
+ tech.isFarAwayDmg = false;
+ }
+ },
+ {
+ name: "Higgs mechanism",
+ description: "
+45% fire ratewhile
firing your
position is fixed",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple
+ },
+ requires: "not ship mode, automatic, grappling hook",
+ effect() {
+ tech.isFireMoveLock = true;
+ b.setFireCD();
+ b.setFireMethod();
+ },
+ remove() {
+ if (tech.isFireMoveLock) {
+ tech.isFireMoveLock = false
b.setFireCD();
b.setFireMethod();
- },
- remove() {
- if (tech.isFireMoveLock) {
- tech.isFireMoveLock = false
- b.setFireCD();
- b.setFireMethod();
- }
}
- },
+ }
+ },
- // {
- // name: "coyote",
- // description: "",
- // maxCount: 1,
- // count: 0,
- // frequency: 1,
- // frequencyDefault: 1,
- // allowed() { return true },
- // requires: "",
- // effect() { // good with melee builds, content skipping builds
- // tech.coyoteTime = 120
- // // simulation.gravity = function() {
- // // function addGravity(bodies, magnitude) {
- // // for (var i = 0; i < bodies.length; i++) {
- // // bodies[i].force.y += bodies[i].mass * magnitude;
- // // }
- // // }
- // // if (!m.isBodiesAsleep) {
- // // addGravity(powerUp, simulation.g);
- // // addGravity(body, simulation.g);
- // // }
- // // player.force.y += player.mass * simulation.g
- // // }
- // },
- // remove() {
- // tech.coyoteTime = 5
- // }
- // },
- {
- name: "Newtons 1st law",
- description: "
defense is proportional to your
speedup to
+66% defense at
40 speed",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isSpeedHarm = true //max at speed = 40
- },
- remove() {
- tech.isSpeedHarm = false
+ // {
+ // name: "coyote",
+ // description: "",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // allowed() { return true },
+ // requires: "",
+ // effect() { // good with melee builds, content skipping builds
+ // tech.coyoteTime = 120
+ // // simulation.gravity = function() {
+ // // function addGravity(bodies, magnitude) {
+ // // for (var i = 0; i < bodies.length; i++) {
+ // // bodies[i].force.y += bodies[i].mass * magnitude;
+ // // }
+ // // }
+ // // if (!m.isBodiesAsleep) {
+ // // addGravity(powerUp, simulation.g);
+ // // addGravity(body, simulation.g);
+ // // }
+ // // player.force.y += player.mass * simulation.g
+ // // }
+ // },
+ // remove() {
+ // tech.coyoteTime = 5
+ // }
+ // },
+ {
+ name: "Newtons 1st law",
+ description: "
defense is proportional to your
speedup to
+66% defense at
40 speed",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isSpeedHarm = true //max at speed = 40
+ },
+ remove() {
+ tech.isSpeedHarm = false
+ }
+ },
+ {
+ name: "Newtons 2nd law",
+ description: "
damage is proportional to your
speedup to
+66% damage at
40 speed",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isSpeedDamage = true //max at speed = 40
+ },
+ remove() {
+ tech.isSpeedDamage = false
+ }
+ },
+ {
+ name: "microstates",
+ link: `
microstates`,
+ description: "for each active
bullet / bot+0.7% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isDamageFromBulletCount = true
+ },
+ remove() {
+ tech.isDamageFromBulletCount = false
+ }
+ },
+ {
+ name: "regression",
+ description: "bullet
collisions increase
vulnerability to
damage by
+5% for mobs
(+0.25% for bosses)",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isLessDamageReduction = true
+ },
+ remove() {
+ tech.isLessDamageReduction = false
+ }
+ },
+ {
+ name: "simulated annealing",
+ description: "
+20% damage–20% fire rate",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ damage: 1.2,
+ effect() {
+ tech.damage *= this.damage
+ tech.slowFire = 1.2
+ b.setFireCD();
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.slowFire = 1;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "heuristics",
+ description: "
+25% fire ratespawn a
gun",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.fireRate *= 0.75
+ b.setFireCD();
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ },
+ remove() {
+ tech.fireRate = 1;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "anti-shear topology",
+ link: `
anti-shear topology`,
+ description: "
+30% projectile
duration", //
drone spore worm flea missile foam wave neutron ice",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isBulletsLastLonger += 0.3
+ },
+ remove() {
+ tech.isBulletsLastLonger = 1;
+ }
+ },
+ {
+ name: "fracture analysis",
+ description: "if a mob is
stunned it takes
+400% damage from bullet impacts",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.isOrbitBotUpgrade || tech.isStun
+ },
+ requires: "a stun effect",
+ effect() {
+ tech.isCrit = true;
+ },
+ remove() {
+ tech.isCrit = false;
+ }
+ },
+ {
+ name: "shear stress",
+ description: "after mobs
diethey release a
nail that targets nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.nailsDeathMob++
+ },
+ remove() {
+ tech.nailsDeathMob = 0;
+ }
+ },
+ {
+ name: "thermal runaway",
+ description: "after mobs
diethey
explode",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.isExplodeMob = true;
+ },
+ remove() {
+ tech.isExplodeMob = false;
+ }
+ },
+ {
+ name: "zoospore vector",
+ link: `
zoospore vector`,
+ descriptionFunction() {
+ return `after mobs
die there is a
+10% chance
they grow ${b.guns[6].nameString('s')}`
+ },
+ // description: "after mobs
diethey have a
+10% chance to grow
spores",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.nailsDeathMob && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.sporesOnDeath += 0.1;
+ // if (tech.isSporeWorm) {
+ // for (let i = 0; i < 4; i++) b.worm(m.pos)
+ // } else {
+ // for (let i = 0; i < 8; i++) b.spore(m.pos)
+ // }
+ },
+ remove() {
+ tech.sporesOnDeath = 0;
+ }
+ },
+ {
+ name: "propagator",
+ description: "after mobs
die advance time
0.5 seconds
+60% damage",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.deathSkipTime++
+ },
+ remove() {
+ tech.deathSkipTime = 0
+ }
+ },
+ {
+ name: "collider",
+ descriptionFunction() {
+ return `after mobs
die there is a
+33% chance
to smash
power ups into a different
flavor`
+ },
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.collidePowerUps += 0.33333
+ },
+ remove() {
+ tech.collidePowerUps = 0
+ }
+ },
+ {
+ name: "bubble fusion",
+ descriptionFunction() {
+ return `after destroying a mob's natural
shieldspawn
1-2 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isShieldAmmo = true;
+ },
+ remove() {
+ tech.isShieldAmmo = false;
+ }
+ },
+ {
+ name: "reaction inhibitor",
+ description: "
-12% maximum mob
health", //
health
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath
+ },
+ requires: "", //"any mob death tech",
+ effect() {
+ tech.mobSpawnWithHealth++
+ mobs.setMobSpawnHealth()
+ //set all mobs at full health to 0.85
+ for (let i = 0; i < mob.length; i++) {
+ if (mob.health > mobs.mobSpawnWithHealth) mob.health = mobs.mobSpawnWithHealth
}
},
- {
- name: "Newtons 2nd law",
- description: "
damage is proportional to your
speedup to
+66% damage at
40 speed",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isSpeedDamage = true //max at speed = 40
- },
- remove() {
- tech.isSpeedDamage = false
- }
+ remove() {
+ tech.mobSpawnWithHealth = 0
+ mobs.setMobSpawnHealth()
+ }
+ },
+ {
+ name: "scrap bots",
+ link: `
scrap bots`,
+ description: "after mobs
die you have a
+33% chance
to build scrap
bots that operate for
13 seconds",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ allowed() {
+ return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.isExplodeMob && !tech.isMobBlockFling && !tech.iceIXOnDeath
},
- {
- name: "microstates",
- link: `
microstates`,
- description: "for each active
bullet / bot+0.7% damage",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isDamageFromBulletCount = true
- },
- remove() {
- tech.isDamageFromBulletCount = false
- }
+ requires: "no other mob death tech",
+ effect() {
+ tech.botSpawner += 0.33;
},
- {
- name: "regression",
- description: "bullet
collisions increase
vulnerability to
damage by
+5% for mobs
(+0.25% for bosses)",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isLessDamageReduction = true
- },
- remove() {
- tech.isLessDamageReduction = false
- }
+ remove() {
+ tech.botSpawner = 0;
+ }
+ },
+ {
+ name: "scrap refit",
+ link: `
scrap refit`,
+ description: "after mobs
diereset scrap
bots to
13 seconds of operation",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.botSpawner
},
- {
- name: "simulated annealing",
- description: "
+20% damage–20% fire rate",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- damage: 1.2,
- effect() {
- tech.damage *= this.damage
- tech.slowFire = 1.2
- b.setFireCD();
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.slowFire = 1;
- b.setFireCD();
- }
+ requires: "scrap bots",
+ effect() {
+ tech.isBotSpawnerReset = true;
},
- {
- name: "heuristics",
- description: "
+25% fire ratespawn a
gun",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.fireRate *= 0.75
- b.setFireCD();
- powerUps.spawn(m.pos.x, m.pos.y, "gun");
- },
- remove() {
- tech.fireRate = 1;
- b.setFireCD();
- }
+ remove() {
+ tech.isBotSpawnerReset = false;
+ }
+ },
+ {
+ name: "nail-bot",
+ link: `
nail-bot`,
+ description: "a
bot fires
nails at mobs in line of sight",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
},
- {
- name: "anti-shear topology",
- link: `
anti-shear topology`,
- description: "
+30% projectile
duration", //
drone spore worm flea missile foam wave neutron ice",
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.isBulletsLastLonger += 0.3
- },
- remove() {
- tech.isBulletsLastLonger = 1;
- }
+ requires: "",
+ effect() {
+ tech.nailBotCount++;
+ b.nailBot();
},
- {
- name: "fracture analysis",
- description: "if a mob is
stunned it takes
+400% damage from bullet impacts",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.isOrbitBotUpgrade || tech.isStun
- },
- requires: "a stun effect",
- effect() {
- tech.isCrit = true;
- },
- remove() {
- tech.isCrit = false;
+ remove() {
+ if (this.count) {
+ tech.nailBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
}
+ }
+ },
+ {
+ name: "nail-bot upgrade",
+ link: `
nail-bot upgrade`,
+ description: "
convert your bots to
nail-bots+500% fire rate and
+40% nail
velocity",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.nailBotCount > 1 && !b.hasBotUpgrade()
},
- {
- name: "shear stress",
- description: "after mobs
diethey release a
nail that targets nearby mobs",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
- },
- requires: "no other mob death tech",
- effect() {
- tech.nailsDeathMob++
- },
- remove() {
- tech.nailsDeathMob = 0;
+ requires: "2 or more nail bots and no other bot upgrade",
+ effect() {
+ tech.isNailBotUpgrade = true
+ b.convertBotsTo("nail-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'nail') bullet[i].isUpgraded = true
}
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("nail-bot", 5)
},
- {
- name: "thermal runaway",
- description: "after mobs
diethey
explode",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
- },
- requires: "no other mob death tech",
- effect() {
- tech.isExplodeMob = true;
- },
- remove() {
- tech.isExplodeMob = false;
- }
- },
- {
- name: "zoospore vector",
- link: `
zoospore vector`,
- descriptionFunction() {
- return `after mobs
die there is a
+10% chance
they grow ${b.guns[6].nameString('s')}`
- },
- // description: "after mobs
diethey have a
+10% chance to grow
spores",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.nailsDeathMob && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
- },
- requires: "no other mob death tech",
- effect() {
- tech.sporesOnDeath += 0.1;
- // if (tech.isSporeWorm) {
- // for (let i = 0; i < 4; i++) b.worm(m.pos)
- // } else {
- // for (let i = 0; i < 8; i++) b.spore(m.pos)
- // }
- },
- remove() {
- tech.sporesOnDeath = 0;
- }
- },
- {
- name: "propagator",
- description: "after mobs
die advance time
0.5 seconds
+60% damage",
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.deathSkipTime++
- },
- remove() {
- tech.deathSkipTime = 0
- }
- },
- {
- name: "collider",
- descriptionFunction() {
- return `after mobs
die there is a
+33% chance
to smash
power ups into a different
flavor`
- },
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.collidePowerUps += 0.33333
- },
- remove() {
- tech.collidePowerUps = 0
- }
- },
- {
- name: "bubble fusion",
- descriptionFunction() {
- return `after destroying a mob's natural
shieldspawn
1-2 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isShieldAmmo = true;
- },
- remove() {
- tech.isShieldAmmo = false;
- }
- },
- {
- name: "reaction inhibitor",
- description: "
-12% maximum mob
health", //
health
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath
- },
- requires: "", //"any mob death tech",
- effect() {
- tech.mobSpawnWithHealth++
- mobs.setMobSpawnHealth()
- //set all mobs at full health to 0.85
- for (let i = 0; i < mob.length; i++) {
- if (mob.health > mobs.mobSpawnWithHealth) mob.health = mobs.mobSpawnWithHealth
- }
- },
- remove() {
- tech.mobSpawnWithHealth = 0
- mobs.setMobSpawnHealth()
- }
- },
- {
- name: "scrap bots",
- link: `
scrap bots`,
- description: "after mobs
die you have a
+33% chance
to build scrap
bots that operate for
13 seconds",
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBotTech: true,
- allowed() {
- return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.isExplodeMob && !tech.isMobBlockFling && !tech.iceIXOnDeath
- },
- requires: "no other mob death tech",
- effect() {
- tech.botSpawner += 0.33;
- },
- remove() {
- tech.botSpawner = 0;
- }
- },
- {
- name: "scrap refit",
- link: `
scrap refit`,
- description: "after mobs
diereset scrap
bots to
13 seconds of operation",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.botSpawner
- },
- requires: "scrap bots",
- effect() {
- tech.isBotSpawnerReset = true;
- },
- remove() {
- tech.isBotSpawnerReset = false;
- }
- },
- {
- name: "nail-bot",
- link: `
nail-bot`,
- description: "a
bot fires
nails at mobs in line of sight",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.nailBotCount++;
- b.nailBot();
- },
- remove() {
- if (this.count) {
- tech.nailBotCount -= this.count;
- b.clearPermanentBots();
- b.respawnBots();
- }
- }
- },
- {
- name: "nail-bot upgrade",
- link: `
nail-bot upgrade`,
- description: "
convert your bots to
nail-bots+500% fire rate and
+40% nail
velocity",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.nailBotCount > 1 && !b.hasBotUpgrade()
- },
- requires: "2 or more nail bots and no other bot upgrade",
- effect() {
- tech.isNailBotUpgrade = true
- b.convertBotsTo("nail-bot")
+ remove() {
+ if (this.count) {
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'nail') bullet[i].isUpgraded = true
+ if (bullet[i].botType === 'nail') bullet[i].isUpgraded = false
}
- tech.setBotTechFrequency()
- tech.setTechFrequency("nail-bot", 5)
- },
- remove() {
- if (this.count) {
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'nail') bullet[i].isUpgraded = false
- }
- tech.setBotTechFrequency(1)
- }
- tech.isNailBotUpgrade = false
+ tech.setBotTechFrequency(1)
}
+ tech.isNailBotUpgrade = false
+ }
+ },
+ {
+ name: "foam-bot",
+ link: `
foam-bot`,
+ description: "a
bot fires
foam at nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
},
- {
- name: "foam-bot",
- link: `
foam-bot`,
- description: "a
bot fires
foam at nearby mobs",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.foamBotCount++;
- b.foamBot();
- },
- remove() {
- if (this.count) {
- tech.foamBotCount -= this.count;
- b.clearPermanentBots();
- b.respawnBots();
- }
+ requires: "",
+ effect() {
+ tech.foamBotCount++;
+ b.foamBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.foamBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
}
+ }
+ },
+ {
+ name: "foam-bot upgrade",
+ link: `
foam-bot upgrade`,
+ description: "
convert your bots to
foam-bots+300% foam
size and
fire rate",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.foamBotCount > 1 && !b.hasBotUpgrade()
},
- {
- name: "foam-bot upgrade",
- link: `
foam-bot upgrade`,
- description: "
convert your bots to
foam-bots+300% foam
size and
fire rate",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.foamBotCount > 1 && !b.hasBotUpgrade()
- },
- requires: "2 or more foam bots and no other bot upgrade",
- effect() {
- tech.isFoamBotUpgrade = true
- b.convertBotsTo("foam-bot")
+ requires: "2 or more foam bots and no other bot upgrade",
+ effect() {
+ tech.isFoamBotUpgrade = true
+ b.convertBotsTo("foam-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'foam') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("foam-bot", 5)
+ },
+ remove() {
+ if (this.count) {
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'foam') bullet[i].isUpgraded = true
+ if (bullet[i].botType === 'foam') bullet[i].isUpgraded = false
}
- tech.setBotTechFrequency()
- tech.setTechFrequency("foam-bot", 5)
- },
- remove() {
- if (this.count) {
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'foam') bullet[i].isUpgraded = false
- }
- tech.setBotTechFrequency(1)
- }
- tech.isFoamBotUpgrade = false
+ tech.setBotTechFrequency(1)
}
+ tech.isFoamBotUpgrade = false
+ }
+ },
+ {
+ name: "boom-bot",
+ link: `
boom-bot`,
+ description: "a
bot defends the space around you
ignites an
explosion after hitting a mob",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
},
- {
- name: "boom-bot",
- link: `
boom-bot`,
- description: "a
bot defends the space around you
ignites an
explosion after hitting a mob",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.boomBotCount++;
- b.boomBot();
- },
- remove() {
- if (this.count) {
- tech.boomBotCount -= this.count;
- b.clearPermanentBots();
- b.respawnBots();
- }
+ requires: "",
+ effect() {
+ tech.boomBotCount++;
+ b.boomBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.boomBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
}
+ }
+ },
+ {
+ name: "boom-bot upgrade",
+ link: `
boom-bot upgrade`,
+ description: "
convert your bots to
boom-bots+300% explosion damage and size",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.boomBotCount > 1 && !b.hasBotUpgrade()
},
- {
- name: "boom-bot upgrade",
- link: `
boom-bot upgrade`,
- description: "
convert your bots to
boom-bots+300% explosion damage and size",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.boomBotCount > 1 && !b.hasBotUpgrade()
- },
- requires: "2 or more boom bots and no other bot upgrade",
- effect() {
- tech.isBoomBotUpgrade = true
- b.convertBotsTo("boom-bot")
+ requires: "2 or more boom bots and no other bot upgrade",
+ effect() {
+ tech.isBoomBotUpgrade = true
+ b.convertBotsTo("boom-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'boom') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("boom-bot", 5)
+ },
+ remove() {
+ if (this.count) {
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'boom') bullet[i].isUpgraded = true
+ if (bullet[i].botType === 'boom') bullet[i].isUpgraded = false
}
- tech.setBotTechFrequency()
- tech.setTechFrequency("boom-bot", 5)
- },
- remove() {
- if (this.count) {
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'boom') bullet[i].isUpgraded = false
- }
- tech.setBotTechFrequency(1)
- }
- tech.isBoomBotUpgrade = false
+ tech.setBotTechFrequency(1)
}
+ tech.isBoomBotUpgrade = false
+ }
+ },
+ {
+ name: "laser-bot",
+ link: `
laser-bot`,
+ description: "a
bot uses
energy to emit a
laser beam
that targets nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return m.maxEnergy > 0.5
},
- {
- name: "laser-bot",
- link: `
laser-bot`,
- description: "a
bot uses
energy to emit a
laser beam
that targets nearby mobs",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return m.maxEnergy > 0.5
- },
- requires: "maximum energy above 50",
- effect() {
- tech.laserBotCount++;
- b.laserBot();
- },
- remove() {
- if (this.count) {
- tech.laserBotCount -= this.count;
- b.clearPermanentBots();
- b.respawnBots();
- }
+ requires: "maximum energy above 50",
+ effect() {
+ tech.laserBotCount++;
+ b.laserBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.laserBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
}
+ }
+ },
+ {
+ name: "laser-bot upgrade",
+ link: `
laser-bot upgrade`,
+ description: "
convert your bots to
laser-bots+100% damage, efficiency, and range",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.laserBotCount > 1 && !b.hasBotUpgrade()
},
- {
- name: "laser-bot upgrade",
- link: `
laser-bot upgrade`,
- description: "
convert your bots to
laser-bots+100% damage, efficiency, and range",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.laserBotCount > 1 && !b.hasBotUpgrade()
- },
- requires: "2 or more laser bots and no other bot upgrade",
- effect() {
- tech.isLaserBotUpgrade = true
- b.convertBotsTo("laser-bot")
+ requires: "2 or more laser bots and no other bot upgrade",
+ effect() {
+ tech.isLaserBotUpgrade = true
+ b.convertBotsTo("laser-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'laser') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("laser-bot", 5)
+ },
+ remove() {
+ if (this.count) {
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'laser') bullet[i].isUpgraded = true
+ if (bullet[i].botType === 'laser') bullet[i].isUpgraded = false
}
- tech.setBotTechFrequency()
- tech.setTechFrequency("laser-bot", 5)
- },
- remove() {
- if (this.count) {
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'laser') bullet[i].isUpgraded = false
- }
- tech.setBotTechFrequency(1)
- }
- tech.isLaserBotUpgrade = false
+ tech.setBotTechFrequency(1)
}
+ tech.isLaserBotUpgrade = false
+ }
+ },
+ {
+ name: "orbital-bot",
+ link: `
orbital-bot`,
+ description: "a
bot is locked in
orbit around you
stuns and
damages mobs on
contact",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
},
- {
- name: "orbital-bot",
- link: `
orbital-bot`,
- description: "a
bot is locked in
orbit around you
stuns and
damages mobs on
contact",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- b.orbitBot();
- tech.orbitBotCount++;
- },
- remove() {
- if (this.count) {
- tech.orbitBotCount -= this.count;
- b.clearPermanentBots();
- b.respawnBots();
+ requires: "",
+ effect() {
+ b.orbitBot();
+ tech.orbitBotCount++;
+ },
+ remove() {
+ if (this.count) {
+ tech.orbitBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "orbital-bot upgrade",
+ link: `
orbital-bot upgrade`,
+ description: "
convert your bots to
orbital-bots+300% orbital
damage and
+50% radius",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.orbitBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more orbital bots and no other bot upgrade",
+ effect() {
+ tech.isOrbitBotUpgrade = true
+ b.convertBotsTo("orbital-bot")
+ const range = 190 + 120 * tech.isOrbitBotUpgrade
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'orbit') {
+ bullet[i].isUpgraded = true
+ bullet[i].range = range
+ bullet[i].orbitalSpeed = Math.sqrt(0.25 / range)
}
}
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("orbital-bot", 5)
},
- {
- name: "orbital-bot upgrade",
- link: `
orbital-bot upgrade`,
- description: "
convert your bots to
orbital-bots+300% orbital
damage and
+50% radius",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.orbitBotCount > 1 && !b.hasBotUpgrade()
- },
- requires: "2 or more orbital bots and no other bot upgrade",
- effect() {
- tech.isOrbitBotUpgrade = true
- b.convertBotsTo("orbital-bot")
- const range = 190 + 120 * tech.isOrbitBotUpgrade
+ remove() {
+ if (this.count) {
+ const range = 190 + 100 * tech.isOrbitBotUpgrade
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType === 'orbit') {
- bullet[i].isUpgraded = true
bullet[i].range = range
bullet[i].orbitalSpeed = Math.sqrt(0.25 / range)
}
}
- tech.setBotTechFrequency()
- tech.setTechFrequency("orbital-bot", 5)
- },
- remove() {
- if (this.count) {
- const range = 190 + 100 * tech.isOrbitBotUpgrade
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'orbit') {
- bullet[i].range = range
- bullet[i].orbitalSpeed = Math.sqrt(0.25 / range)
- }
- }
- tech.setBotTechFrequency(1)
- }
- tech.isOrbitBotUpgrade = false
+ tech.setBotTechFrequency(1)
}
+ tech.isOrbitBotUpgrade = false
+ }
+ },
+ {
+ name: "dynamo-bot",
+ link: `
dynamo-bot`,
+ description: "a
bot damages mobs while it
traces your path
when it's near generate
+7 energy per second",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
},
- {
- name: "dynamo-bot",
- link: `
dynamo-bot`,
- description: "a
bot damages mobs while it
traces your path
when it's near generate
+7 energy per second",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.dynamoBotCount++;
- b.dynamoBot();
- },
- remove() {
- if (this.count) {
- tech.dynamoBotCount -= this.count;
- b.clearPermanentBots();
- b.respawnBots();
- }
+ requires: "",
+ effect() {
+ tech.dynamoBotCount++;
+ b.dynamoBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.dynamoBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
}
+ }
+ },
+ {
+ name: "dynamo-bot upgrade",
+ link: `
dynamo-bot upgrade`,
+ description: "
convert your bots to
dynamo-botswhen it's near generate
+23 energy per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.dynamoBotCount > 1 && !b.hasBotUpgrade()
},
- {
- name: "dynamo-bot upgrade",
- link: `
dynamo-bot upgrade`,
- description: "
convert your bots to
dynamo-botswhen it's near generate
+23 energy per second",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBotTech: true,
- allowed() {
- return tech.dynamoBotCount > 1 && !b.hasBotUpgrade()
- },
- requires: "2 or more dynamo bots and no other bot upgrade",
- effect() {
- tech.isDynamoBotUpgrade = true
- b.convertBotsTo("dynamo-bot")
+ requires: "2 or more dynamo bots and no other bot upgrade",
+ effect() {
+ tech.isDynamoBotUpgrade = true
+ b.convertBotsTo("dynamo-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("dynamo-bot", 5)
+ },
+ remove() {
+ if (this.count) {
for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = true
+ if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = false
}
- tech.setBotTechFrequency()
- tech.setTechFrequency("dynamo-bot", 5)
- },
- remove() {
- if (this.count) {
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = false
- }
- tech.setBotTechFrequency(1)
- }
- tech.isDynamoBotUpgrade = false
+ tech.setBotTechFrequency(1)
}
+ tech.isDynamoBotUpgrade = false
+ }
+ },
+ {
+ name: "perimeter defense",
+ description: "for each permanent
bot+6% defense",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return b.totalBots() > 1
},
- {
- name: "perimeter defense",
- description: "for each permanent
bot+6% defense",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBotTech: true,
- allowed() {
- return b.totalBots() > 1
- },
- requires: "at least 2 bots",
- effect() {
- tech.isBotArmor = true
- },
- remove() {
- tech.isBotArmor = false
- }
+ requires: "at least 2 bots",
+ effect() {
+ tech.isBotArmor = true
},
- {
- name: "network effect",
- description: "for each permanent
bot+6% damage",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBotTech: true,
- allowed() {
- return b.totalBots() > 1
- },
- requires: "at least 2 bots",
- effect() {
- tech.isBotDamage = true
- },
- remove() {
- tech.isBotDamage = false
- }
+ remove() {
+ tech.isBotArmor = false
+ }
+ },
+ {
+ name: "network effect",
+ description: "for each permanent
bot+6% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return b.totalBots() > 1
},
- {
- name: "bot fabrication",
- link: `
bot fabrication`,
- descriptionFunction() {
- return `after you collect ${powerUps.orb.research(2 + Math.floor(0.1666 * b.totalBots()))}use them to build a
random
bot (+1 cost every 5 bots)`
- },
- // description: `if you collect ${powerUps.orb.research(2)}use them to build a
random
bot (+1 cost every 5 bots)`,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBotTech: true,
- allowed() {
- return powerUps.research.count > 1 || build.isExperimentSelection
- },
- requires: "at least 2 research",
- effect() {
- tech.isRerollBots = true;
- powerUps.research.changeRerolls(0)
- simulation.makeTextLog(`
m.
research = 0`)
- },
- remove() {
- tech.isRerollBots = false;
- // this.description = `if you collect ${powerUps.orb.research(2 + Math.floor(0.2 * b.totalBots()))}use them to build a
random
bot (+1 cost every 5 bots)`
- }
+ requires: "at least 2 bots",
+ effect() {
+ tech.isBotDamage = true
},
- {
- name: "ersatz bots",
- link: `
ersatz bots`,
- description: "
double your current permanent
botsremove
all guns in your inventory",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBotTech: true,
- // isNonRefundable: true,
- isBadRandomOption: true,
- numberOfGunsLost: 0,
- allowed() {
- return b.totalBots() > 3 && !build.isExperimentSelection
- },
- requires: "NOT EXPERIMENT MODE, at least 4 bots",
- effect() {
- this.numberOfGunsLost = b.inventory.length
- b.removeAllGuns();
- simulation.makeGunHUD();
- //double bots
- for (let i = 0; i < tech.nailBotCount; i++) b.nailBot();
- tech.nailBotCount *= 2
- for (let i = 0; i < tech.laserBotCount; i++) b.laserBot();
- tech.laserBotCount *= 2
- for (let i = 0; i < tech.foamBotCount; i++) b.foamBot();
- tech.foamBotCount *= 2
- for (let i = 0; i < tech.boomBotCount; i++) b.boomBot();
- tech.boomBotCount *= 2
- for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot();
- tech.orbitBotCount *= 2
- for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot();
- tech.dynamoBotCount *= 2
- for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot();
- tech.plasmaBotCount *= 2
- for (let i = 0; i < tech.missileBotCount; i++) b.missileBot();
- tech.missileBotCount *= 2
- },
- remove() {
- if (this.count) {
- //return guns
- for (let i = 0; i < this.numberOfGunsLost; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
- this.numberOfGunsLost = 0;
+ remove() {
+ tech.isBotDamage = false
+ }
+ },
+ {
+ name: "bot fabrication",
+ link: `
bot fabrication`,
+ descriptionFunction() {
+ return `after you collect ${powerUps.orb.research(2 + Math.floor(0.1666 * b.totalBots()))}use them to build a
random
bot (+1 cost every 5 bots)`
+ },
+ // description: `if you collect ${powerUps.orb.research(2)}use them to build a
random
bot (+1 cost every 5 bots)`,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return powerUps.research.count > 1 || build.isExperimentSelection
+ },
+ requires: "at least 2 research",
+ effect() {
+ tech.isRerollBots = true;
+ powerUps.research.changeRerolls(0)
+ simulation.makeTextLog(`
m.
research = 0`)
+ },
+ remove() {
+ tech.isRerollBots = false;
+ // this.description = `if you collect ${powerUps.orb.research(2 + Math.floor(0.2 * b.totalBots()))}use them to build a
random
bot (+1 cost every 5 bots)`
+ }
+ },
+ {
+ name: "ersatz bots",
+ link: `
ersatz bots`,
+ description: "
double your current permanent
botsremove
all guns in your inventory",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ // isNonRefundable: true,
+ isBadRandomOption: true,
+ numberOfGunsLost: 0,
+ allowed() {
+ return b.totalBots() > 3 && !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE, at least 4 bots",
+ effect() {
+ this.numberOfGunsLost = b.inventory.length
+ b.removeAllGuns();
+ simulation.makeGunHUD();
+ //double bots
+ for (let i = 0; i < tech.nailBotCount; i++) b.nailBot();
+ tech.nailBotCount *= 2
+ for (let i = 0; i < tech.laserBotCount; i++) b.laserBot();
+ tech.laserBotCount *= 2
+ for (let i = 0; i < tech.foamBotCount; i++) b.foamBot();
+ tech.foamBotCount *= 2
+ for (let i = 0; i < tech.boomBotCount; i++) b.boomBot();
+ tech.boomBotCount *= 2
+ for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot();
+ tech.orbitBotCount *= 2
+ for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot();
+ tech.dynamoBotCount *= 2
+ for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot();
+ tech.plasmaBotCount *= 2
+ for (let i = 0; i < tech.missileBotCount; i++) b.missileBot();
+ tech.missileBotCount *= 2
+ },
+ remove() {
+ if (this.count) {
+ //return guns
+ for (let i = 0; i < this.numberOfGunsLost; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
+ this.numberOfGunsLost = 0;
- //half all current guns
- tech.nailBotCount = Math.round(tech.nailBotCount / 2)
- tech.laserBotCount = Math.round(tech.laserBotCount / 2)
- tech.foamBotCount = Math.round(tech.foamBotCount / 2)
- tech.boomBotCount = Math.round(tech.boomBotCount / 2)
- tech.orbitBotCount = Math.round(tech.orbitBotCount / 2)
- tech.dynamoBotCount = Math.round(tech.dynamoBotCount / 2)
- tech.plasmaBotCount = Math.round(tech.plasmaBotCount / 2)
- tech.missileBotCount = Math.round(tech.missileBotCount / 2)
- b.clearPermanentBots();
- b.respawnBots();
- }
+ //half all current guns
+ tech.nailBotCount = Math.round(tech.nailBotCount / 2)
+ tech.laserBotCount = Math.round(tech.laserBotCount / 2)
+ tech.foamBotCount = Math.round(tech.foamBotCount / 2)
+ tech.boomBotCount = Math.round(tech.boomBotCount / 2)
+ tech.orbitBotCount = Math.round(tech.orbitBotCount / 2)
+ tech.dynamoBotCount = Math.round(tech.dynamoBotCount / 2)
+ tech.plasmaBotCount = Math.round(tech.plasmaBotCount / 2)
+ tech.missileBotCount = Math.round(tech.missileBotCount / 2)
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ // {
+ // name: "robotics",
+ // description: `spawn
2 random
botsquadruple the
frequency of finding
bot tech`,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // isBotTech: true,
+ // allowed() {
+ // return b.totalBots() > 1 || build.isExperimentSelection
+ // },
+ // requires: "at least 2 bots",
+ // effect: () => {
+ // b.randomBot()
+ // b.randomBot()
+ // for (let i = 0, len = tech.tech.length; i < len; i++) {
+ // if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 4
+ // }
+ // },
+ // remove() {
+ // if (this.count > 0) {
+ // b.removeBot()
+ // b.removeBot()
+ // b.clearPermanentBots();
+ // b.respawnBots();
+ // for (let i = 0, len = tech.tech.length; i < len; i++) {
+ // if (tech.tech[i].isBotTech) tech.tech[i].frequency = Math.ceil(tech.tech[i].frequency / 4)
+ // }
+ // }
+ // }
+ // },
+ {
+ name: "robotics",
+ description: `spawn
2 random
botstech,
fields, and
guns have
+1 bot
choice`, //
tech have an extra
bot tech option
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ allowed() {
+ return b.totalBots() > 1
+ },
+ requires: "at least 2 bots",
+ effect() {
+ tech.isExtraBotOption = true
+ for (let i = 0; i < 2; i++) b.randomBot()
+ },
+ remove() {
+ if (this.count > 0) {
+ for (let i = 0; i < 2; i++) b.removeBot()
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ tech.isExtraBotOption = false
+ }
+ },
+ {
+ name: "open-source", //digital fabricator
+ description: `spawn
3 random
botstriple the
frequency of finding
bot tech`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isBotTech: true,
+ allowed() {
+ return tech.isExtraBotOption
+ },
+ requires: "robotics",
+ effect() {
+ for (let i = 0; i < 3; i++) b.randomBot()
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 3
}
},
- // {
- // name: "robotics",
- // description: `spawn
2 random
botsquadruple the
frequency of finding
bot tech`,
- // maxCount: 1,
- // count: 0,
- // frequency: 1,
- // frequencyDefault: 1,
- // isBotTech: true,
- // allowed() {
- // return b.totalBots() > 1 || build.isExperimentSelection
- // },
- // requires: "at least 2 bots",
- // effect: () => {
- // b.randomBot()
- // b.randomBot()
- // for (let i = 0, len = tech.tech.length; i < len; i++) {
- // if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 4
- // }
- // },
- // remove() {
- // if (this.count > 0) {
- // b.removeBot()
- // b.removeBot()
- // b.clearPermanentBots();
- // b.respawnBots();
- // for (let i = 0, len = tech.tech.length; i < len; i++) {
- // if (tech.tech[i].isBotTech) tech.tech[i].frequency = Math.ceil(tech.tech[i].frequency / 4)
- // }
- // }
- // }
- // },
- {
- name: "robotics",
- description: `spawn
2 random
botstech,
fields, and
guns have
+1 bot
choice`, //
tech have an extra
bot tech option
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBotTech: true,
- allowed() {
- return b.totalBots() > 1
- },
- requires: "at least 2 bots",
- effect() {
- tech.isExtraBotOption = true
- for (let i = 0; i < 2; i++) b.randomBot()
- },
- remove() {
- if (this.count > 0) {
- for (let i = 0; i < 2; i++) b.removeBot()
- b.clearPermanentBots();
- b.respawnBots();
- }
- tech.isExtraBotOption = false
- }
- },
- {
- name: "open-source", //digital fabricator
- description: `spawn
3 random
botstriple the
frequency of finding
bot tech`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- frequencyDefault: 0,
- isBotTech: true,
- allowed() {
- return tech.isExtraBotOption
- },
- requires: "robotics",
- effect() {
- for (let i = 0; i < 3; i++) b.randomBot()
+ remove() {
+ if (this.count > 0) {
+ for (let i = 0; i < 3; i++) b.removeBot()
+ b.clearPermanentBots();
+ b.respawnBots();
for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 3
+ if (tech.tech[i].isBotTech) tech.tech[i].frequency = Math.ceil(tech.tech[i].frequency / 3)
}
- },
- remove() {
- if (this.count > 0) {
- for (let i = 0; i < 3; i++) b.removeBot()
- b.clearPermanentBots();
- b.respawnBots();
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isBotTech) tech.tech[i].frequency = Math.ceil(tech.tech[i].frequency / 3)
- }
+ }
+ }
+ },
+ {
+ name: "decorrelation",
+ description: "if your
gun or
field are unused for
2 seconds
+70% defense",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isRewindField
+ },
+ requires: "not retrocausality",
+ effect() {
+ tech.isNoFireDefense = true
+ },
+ remove() {
+ tech.isNoFireDefense = false
+ }
+ },
+ {
+ name: "anticorrelation",
+ description: "if your
gun or
field are unused for
2 seconds
+100% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isRewindField
+ },
+ requires: "not retrocausality",
+ effect() {
+ tech.isNoFireDamage = true
+ },
+ remove() {
+ tech.isNoFireDamage = false
+ }
+ },
+ {
+ name: "mass driver",
+ description: "
+300% block collision
damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name !== "wormhole"
+ },
+ requires: "not wormhole",
+ effect() {
+ tech.blockDamage = 0.3
+ },
+ remove() {
+ tech.blockDamage = 0.075
+ }
+ },
+ {
+ name: "inflation",
+ link: `
inflation`,
+ description: "if
holding a
block +85% defenseafter
throwing a
block it expands
300%",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isTokamak
+ },
+ requires: "mass driver, not pilot wave, tokamak, wormhole",
+ effect() {
+ tech.isAddBlockMass = true
+ },
+ remove() {
+ tech.isAddBlockMass = false
+ }
+ },
+ {
+ name: "restitution",
+ description: "
+150% block collision
damageafter
throwing a
block it becomes very
bouncy",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isTokamak
+ },
+ requires: "mass driver, not pilot wave, tokamak, wormhole",
+ effect() {
+ tech.isBlockRestitution = true
+ },
+ remove() {
+ tech.isBlockRestitution = false
+ }
+ },
+ {
+ name: "flywheel",
+ description: "
+150% block collision
damageafter a mob
dies its
block is
flung at mobs",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.blockDamage > 0.075 && !tech.nailsDeathMob && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.iceIXOnDeath
+ },
+ requires: "mass driver, no other mob death tech",
+ effect() {
+ tech.isMobBlockFling = true
+ },
+ remove() {
+ tech.isMobBlockFling = false
+ }
+ },
+ // {
+ // name: "fermions",
+ // description: "
blocks thrown by you or
pilot wave will
collide with
intangible mobs, but not you",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return (tech.blockDamage > 0.075 || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isTokamak
+ // },
+ // requires: "mass driver or pilot wave, not tokamak",
+ // effect() {
+ // tech.isBlockBullets = true
+ // },
+ // remove() {
+ // tech.isBlockBullets = false
+ // }
+ // },
+ {
+ name: "buckling",
+ descriptionFunction() {
+ return `if a
block you threw kills a mob
spawn either ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && !tech.isTokamak
+ },
+ requires: "mass driver, not pilot wave, tokamak",
+ effect() {
+ tech.isBlockPowerUps = true
+ },
+ remove() {
+ tech.isBlockPowerUps = false
+ }
+ },
+ {
+ name: "NOR gate",
+ description: "if
flip-flop is
OFFbecome
invulnerable to your next collision",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop
+ },
+ requires: "flip-flop",
+ effect() {
+ tech.isFlipFlopHarm = true //do you have this tech
+ },
+ remove() {
+ tech.isFlipFlopHarm = false
+ }
+ },
+ {
+ name: "shape-memory alloy",
+ descriptionFunction() {
+ return `if
flip-flop is
ON+400 maximum
health and
+100% ${powerUps.orb.heal()} effect`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop
+ },
+ requires: "flip-flop",
+ effect() {
+ tech.isFlipFlopHealth = true;
+ m.setMaxHealth();
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
}
}
},
- {
- name: "decorrelation",
- description: "if your
gun or
field are unused for
2 seconds
+70% defense",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isRewindField
- },
- requires: "not retrocausality",
- effect() {
- tech.isNoFireDefense = true
- },
- remove() {
- tech.isNoFireDefense = false
- }
- },
- {
- name: "anticorrelation",
- description: "if your
gun or
field are unused for
2 seconds
+100% damage",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isRewindField
- },
- requires: "not retrocausality",
- effect() {
- tech.isNoFireDamage = true
- },
- remove() {
- tech.isNoFireDamage = false
- }
- },
- {
- name: "mass driver",
- description: "
+300% block collision
damage",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name !== "wormhole"
- },
- requires: "not wormhole",
- effect() {
- tech.blockDamage = 0.3
- },
- remove() {
- tech.blockDamage = 0.075
- }
- },
- {
- name: "inflation",
- link: `
inflation`,
- description: "if
holding a
block +85% defenseafter
throwing a
block it expands
300%",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isTokamak
- },
- requires: "mass driver, not pilot wave, tokamak, wormhole",
- effect() {
- tech.isAddBlockMass = true
- },
- remove() {
- tech.isAddBlockMass = false
- }
- },
- {
- name: "restitution",
- description: "
+150% block collision
damageafter
throwing a
block it becomes very
bouncy",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isTokamak
- },
- requires: "mass driver, not pilot wave, tokamak, wormhole",
- effect() {
- tech.isBlockRestitution = true
- },
- remove() {
- tech.isBlockRestitution = false
- }
- },
- {
- name: "flywheel",
- description: "
+150% block collision
damageafter a mob
dies its
block is
flung at mobs",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.blockDamage > 0.075 && !tech.nailsDeathMob && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.iceIXOnDeath
- },
- requires: "mass driver, no other mob death tech",
- effect() {
- tech.isMobBlockFling = true
- },
- remove() {
- tech.isMobBlockFling = false
- }
- },
- // {
- // name: "fermions",
- // description: "
blocks thrown by you or
pilot wave will
collide with
intangible mobs, but not you",
- // maxCount: 1,
- // count: 0,
- // frequency: 2,
- // frequencyDefault: 2,
- // allowed() {
- // return (tech.blockDamage > 0.075 || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isTokamak
- // },
- // requires: "mass driver or pilot wave, not tokamak",
- // effect() {
- // tech.isBlockBullets = true
- // },
- // remove() {
- // tech.isBlockBullets = false
- // }
- // },
- {
- name: "buckling",
- descriptionFunction() {
- return `if a
block you threw kills a mob
spawn either ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
- },
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.blockDamage > 0.075 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && !tech.isTokamak
- },
- requires: "mass driver, not pilot wave, tokamak",
- effect() {
- tech.isBlockPowerUps = true
- },
- remove() {
- tech.isBlockPowerUps = false
- }
- },
- {
- name: "NOR gate",
- description: "if
flip-flop is
OFFbecome
invulnerable to your next collision",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isFlipFlop
- },
- requires: "flip-flop",
- effect() {
- tech.isFlipFlopHarm = true //do you have this tech
- },
- remove() {
- tech.isFlipFlopHarm = false
- }
- },
- {
- name: "shape-memory alloy",
- descriptionFunction() {
- return `if
flip-flop is
ON+400 maximum
health and
+100% ${powerUps.orb.heal()} effect`
- },
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isFlipFlop
- },
- requires: "flip-flop",
- effect() {
- tech.isFlipFlopHealth = true;
- m.setMaxHealth();
- for (let i = 0; i < powerUp.length; i++) {
- if (powerUp[i].name === "heal") {
- const oldSize = powerUp[i].size
- powerUp[i].size = powerUps.heal.size() //update current heals
- const scale = powerUp[i].size / oldSize
- Matter.Body.scale(powerUp[i], scale, scale); //grow
- }
- }
- },
- remove() {
- tech.isFlipFlopHealth = false;
- m.setMaxHealth();
- for (let i = 0; i < powerUp.length; i++) {
- if (powerUp[i].name === "heal") {
- const oldSize = powerUp[i].size
- powerUp[i].size = powerUps.heal.size() //update current heals
- const scale = powerUp[i].size / oldSize
- Matter.Body.scale(powerUp[i], scale, scale); //grow
- }
+ remove() {
+ tech.isFlipFlopHealth = false;
+ m.setMaxHealth();
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
}
}
- },
- {
- name: "flip-flop",
- link: `
flip-flop`,
- description: `toggle
ON and
OFF after a
collisionunlock advanced
tech that runs if
ON`,
- nameInfo: "
",
- addNameInfo() {
- setTimeout(function() {
- if (document.getElementById("tech-flip-flop")) {
- if (tech.isFlipFlopOn) {
- document.getElementById("tech-flip-flop").innerHTML = ` =
ON`
- m.eyeFillColor = m.fieldMeterColor //'#5af'
- } else {
- document.getElementById("tech-flip-flop").innerHTML = ` =
OFF`
- m.eyeFillColor = "transparent"
- }
- }
- }, 100);
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isRelay
- },
- requires: "not relay switch",
- effect() {
- tech.isFlipFlop = true //do you have this tech?
- if (!tech.isFlipFlopOn) {
- tech.isFlipFlopOn = true //what is the state of flip-Flop?
- if (tech.isFlipFlopCoupling) {
- m.couplingChange(5)
- for (let i = 0; i < mob.length; i++) {
- if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
- }
+ }
+ },
+ {
+ name: "flip-flop",
+ link: `
flip-flop`,
+ description: `toggle
ON and
OFF after a
collisionunlock advanced
tech that runs if
ON`,
+ nameInfo: "
",
+ addNameInfo() {
+ setTimeout(function () {
+ if (document.getElementById("tech-flip-flop")) {
+ if (tech.isFlipFlopOn) {
+ document.getElementById("tech-flip-flop").innerHTML = ` =
ON`
+ m.eyeFillColor = m.fieldMeterColor //'#5af'
+ } else {
+ document.getElementById("tech-flip-flop").innerHTML = ` =
OFF`
+ m.eyeFillColor = "transparent"
}
}
- // if (!m.isShipMode) {
- // m.skin.flipFlop()
- // }
- },
- remove() {
- tech.isFlipFlop = false
- if (tech.isFlipFlopOn) {
- tech.isFlipFlopOn = false //what is the state of flip-Flop?
- if (tech.isFlipFlopCoupling) {
- m.couplingChange(5)
- for (let i = 0; i < mob.length; i++) {
- if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
- }
- }
- }
- m.eyeFillColor = 'transparent'
- // m.resetSkin();
- }
+ }, 100);
},
- {
- name: "NAND gate",
- description: "if
ON+55.5% damage",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isFlipFlop || tech.isRelay
- },
- requires: "ON/OFF tech",
- effect() {
- tech.isFlipFlopDamage = true;
- },
- remove() {
- tech.isFlipFlopDamage = false;
- }
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isRelay
},
- {
- name: "integrated circuit",
- description: "if
ON +7 power up
choicesif
OFF -1 power up
choices",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (tech.isFlipFlop || tech.isRelay) && !tech.isDeterminism
- },
- requires: "ON/OFF tech, not determinism",
- effect() {
- tech.isFlipFlopChoices = true //do you have this tech
- },
- remove() {
- tech.isFlipFlopChoices = false
- }
- },
- {
- name: "transistor",
- description: "if
ON generate
+20 energy per second
if
OFF drain
-1 energy per second",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isFlipFlop || tech.isRelay
- },
- requires: "ON/OFF tech",
- effect() {
- tech.isFlipFlopEnergy = true;
- },
- remove() {
- tech.isFlipFlopEnergy = false;
- }
- },
- {
- name: "decoupling",
- link: `
decoupling`,
- descriptionFunction() {
- //
(${ m.couplingDescription(this.bonus)})
- return `if
ON +5 couplingif
OFF a dangerous particle slowly
chases you`
- },
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- bonus: 5, //coupling given
- allowed() {
- return tech.isFlipFlop || tech.isRelay
- },
- requires: "ON/OFF tech",
- effect() {
- tech.isFlipFlopCoupling = true;
- if (tech.isFlipFlopOn) {
- m.couplingChange(this.bonus)
- } else {
+ requires: "not relay switch",
+ effect() {
+ tech.isFlipFlop = true //do you have this tech?
+ if (!tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = true //what is the state of flip-Flop?
+ if (tech.isFlipFlopCoupling) {
+ m.couplingChange(5)
for (let i = 0; i < mob.length; i++) {
if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
}
- spawn.WIMP()
- mob[mob.length - 1].isDecoupling = true //so you can find it to remove
}
- },
- remove() {
- tech.isFlipFlopCoupling = false;
- if (this.count) {
- if (tech.isFlipFlop || tech.isRelay) {
- if (tech.isFlipFlopOn) {
- m.couplingChange(-this.bonus)
- } else {
- for (let i = 0; i < mob.length; i++) {
- if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
- }
- }
+ }
+ // if (!m.isShipMode) {
+ // m.skin.flipFlop()
+ // }
+ },
+ remove() {
+ tech.isFlipFlop = false
+ if (tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = false //what is the state of flip-Flop?
+ if (tech.isFlipFlopCoupling) {
+ m.couplingChange(5)
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
}
}
}
+ m.eyeFillColor = 'transparent'
+ // m.resetSkin();
+ }
+ },
+ {
+ name: "NAND gate",
+ description: "if
ON+55.5% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop || tech.isRelay
},
- {
- name: "relay switch",
- description: `toggle
ON and
OFF after picking up a
power upunlock advanced
tech that runs if
ON`,
- nameInfo: "
",
- addNameInfo() {
- setTimeout(function() {
- if (document.getElementById("tech-switch")) {
- if (tech.isFlipFlopOn) {
- document.getElementById("tech-switch").innerHTML = ` =
ON`
- m.eyeFillColor = m.fieldMeterColor //'#5af'
- } else {
- document.getElementById("tech-switch").innerHTML = ` =
OFF`
- m.eyeFillColor = "transparent"
- }
- }
- }, 100);
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isFlipFlop
- },
- requires: "not flip-flop",
- effect() {
- m.isAltSkin = true
- tech.isRelay = true //do you have this tech?
- if (!tech.isFlipFlopOn) {
- tech.isFlipFlopOn = true //what is the state of flip-Flop?
- if (tech.isFlipFlopCoupling) {
- m.couplingChange(5)
+ requires: "ON/OFF tech",
+ effect() {
+ tech.isFlipFlopDamage = true;
+ },
+ remove() {
+ tech.isFlipFlopDamage = false;
+ }
+ },
+ {
+ name: "integrated circuit",
+ description: "if
ON +7 power up
choicesif
OFF -1 power up
choices",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.isFlipFlop || tech.isRelay) && !tech.isDeterminism
+ },
+ requires: "ON/OFF tech, not determinism",
+ effect() {
+ tech.isFlipFlopChoices = true //do you have this tech
+ },
+ remove() {
+ tech.isFlipFlopChoices = false
+ }
+ },
+ {
+ name: "transistor",
+ description: "if
ON generate
+20 energy per second
if
OFF drain
-1 energy per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop || tech.isRelay
+ },
+ requires: "ON/OFF tech",
+ effect() {
+ tech.isFlipFlopEnergy = true;
+ },
+ remove() {
+ tech.isFlipFlopEnergy = false;
+ }
+ },
+ {
+ name: "decoupling",
+ link: `
decoupling`,
+ descriptionFunction() {
+ //
(${ m.couplingDescription(this.bonus)})
+ return `if
ON +5 couplingif
OFF a dangerous particle slowly
chases you`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ bonus: 5, //coupling given
+ allowed() {
+ return tech.isFlipFlop || tech.isRelay
+ },
+ requires: "ON/OFF tech",
+ effect() {
+ tech.isFlipFlopCoupling = true;
+ if (tech.isFlipFlopOn) {
+ m.couplingChange(this.bonus)
+ } else {
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
+ }
+ spawn.WIMP()
+ mob[mob.length - 1].isDecoupling = true //so you can find it to remove
+ }
+ },
+ remove() {
+ tech.isFlipFlopCoupling = false;
+ if (this.count) {
+ if (tech.isFlipFlop || tech.isRelay) {
+ if (tech.isFlipFlopOn) {
+ m.couplingChange(-this.bonus)
+ } else {
for (let i = 0; i < mob.length; i++) {
if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
}
}
}
- // if (!m.isShipMode) {
- // m.skin.flipFlop()
- // }
- },
- remove() {
- tech.isRelay = false
- if (tech.isFlipFlopOn) {
- tech.isFlipFlopOn = false //what is the state of flip-Flop?
- if (tech.isFlipFlopCoupling) {
- m.couplingChange(-5)
- for (let i = 0; i < mob.length; i++) {
- if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
- }
+ }
+ }
+ },
+ {
+ name: "relay switch",
+ description: `toggle
ON and
OFF after picking up a
power upunlock advanced
tech that runs if
ON`,
+ nameInfo: "
",
+ addNameInfo() {
+ setTimeout(function () {
+ if (document.getElementById("tech-switch")) {
+ if (tech.isFlipFlopOn) {
+ document.getElementById("tech-switch").innerHTML = ` =
ON`
+ m.eyeFillColor = m.fieldMeterColor //'#5af'
+ } else {
+ document.getElementById("tech-switch").innerHTML = ` =
OFF`
+ m.eyeFillColor = "transparent"
}
}
- m.eyeFillColor = 'transparent'
- // m.resetSkin();
- }
+ }, 100);
},
- {
- name: "lithium-ion",
- description: "if
relay switch is
ON+300 maximum
energy",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isRelay
- },
- requires: "relay switch",
- effect() {
- tech.isRelayEnergy = true
- m.setMaxEnergy()
- },
- remove() {
- tech.isRelayEnergy = false
- m.setMaxEnergy()
- }
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isFlipFlop
},
- {
- name: "thermocouple",
- description: "if
relay switch is
ONcondense
4-13 ice IX crystals per second",
- maxCount: 9,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isRelay
- },
- requires: "relay switch",
- effect() {
- tech.relayIce++
- },
- remove() {
- tech.relayIce = 0
- }
- },
- {
- name: "first derivative",
- descriptionFunction() {
- return `while your
first gun is equipped
+15% defense per
gun (${(100*(1-0.85 ** b.inventory.length)).toFixed(0)}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isFirstDer = true
- },
- remove() {
- tech.isFirstDer = false;
- }
- },
- {
- name: "MACHO",
- description: "a massive but compact object slowly follows you
if you are inside the
MACHO +60% defense",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO
- spawn.MACHO()
- },
- remove() {
- tech.isMACHO = false;
- tech.isHarmMACHO = false;
- for (let i = 0, len = mob.length; i < len; i++) {
- if (mob[i].isMACHO) mob[i].alive = false;
+ requires: "not flip-flop",
+ effect() {
+ m.isAltSkin = true
+ tech.isRelay = true //do you have this tech?
+ if (!tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = true //what is the state of flip-Flop?
+ if (tech.isFlipFlopCoupling) {
+ m.couplingChange(5)
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
+ }
}
}
+ // if (!m.isShipMode) {
+ // m.skin.flipFlop()
+ // }
},
- {
- name: "axion",
- description: "while inside the
MACHOdefense increases
damage",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isMACHO
- },
- requires: "MACHO",
- effect() {
- tech.isAxion = true
- },
- remove() {
- tech.isAxion = false
+ remove() {
+ tech.isRelay = false
+ if (tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = false //what is the state of flip-Flop?
+ if (tech.isFlipFlopCoupling) {
+ m.couplingChange(-5)
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
+ }
+ }
}
+ m.eyeFillColor = 'transparent'
+ // m.resetSkin();
+ }
+ },
+ {
+ name: "lithium-ion",
+ description: "if
relay switch is
ON+300 maximum
energy",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isRelay
},
- {
- name: "ablative drones",
- description: "after losing
health there is a chance
to rebuild your broken parts as
drones",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.isDroneOnDamage = true;
- // for (let i = 0; i < 4; i++) b.drone()
- },
- remove() {
- tech.isDroneOnDamage = false;
+ requires: "relay switch",
+ effect() {
+ tech.isRelayEnergy = true
+ m.setMaxEnergy()
+ },
+ remove() {
+ tech.isRelayEnergy = false
+ m.setMaxEnergy()
+ }
+ },
+ {
+ name: "thermocouple",
+ description: "if
relay switch is
ONcondense
4-13 ice IX crystals per second",
+ maxCount: 9,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isRelay
+ },
+ requires: "relay switch",
+ effect() {
+ tech.relayIce++
+ },
+ remove() {
+ tech.relayIce = 0
+ }
+ },
+ {
+ name: "first derivative",
+ descriptionFunction() {
+ return `while your
first gun is equipped
+15% defense per
gun (${(100 * (1 - 0.85 ** b.inventory.length)).toFixed(0)}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isFirstDer = true
+ },
+ remove() {
+ tech.isFirstDer = false;
+ }
+ },
+ {
+ name: "MACHO",
+ description: "a massive but compact object slowly follows you
if you are inside the
MACHO +60% defense",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO
+ spawn.MACHO()
+ },
+ remove() {
+ tech.isMACHO = false;
+ tech.isHarmMACHO = false;
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isMACHO) mob[i].alive = false;
}
+ }
+ },
+ {
+ name: "axion",
+ description: "while inside the
MACHOdefense increases
damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMACHO
},
- {
- name: "non-Newtonian armor",
- link: `
non-Newtonian armor`,
- description: "after mob collisions
+66% defense for
10 seconds",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isHarmArmor = true;
- },
- remove() {
- tech.isHarmArmor = false;
- }
+ requires: "MACHO",
+ effect() {
+ tech.isAxion = true
},
- {
- name: "Pauli exclusion",
- description: `after mob collisions
become
invulnerable for
+3 seconds`,
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- m.collisionImmuneCycles += 180;
- if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
- },
- remove() {
- m.collisionImmuneCycles = 30;
- }
+ remove() {
+ tech.isAxion = false
+ }
+ },
+ {
+ name: "ablative drones",
+ description: "after losing
health there is a chance
to rebuild your broken parts as
drones",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isDroneOnDamage = true;
+ // for (let i = 0; i < 4; i++) b.drone()
},
- {
- name: "spin–statistics theorem",
- description: `every
7 seconds
become
invulnerable for
+1.8 seconds`,
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true //m.collisionImmuneCycles > 30
- },
- requires: "",
- effect() {
- tech.cyclicImmunity += 108;
- },
- remove() {
- tech.cyclicImmunity = 0;
- }
+ remove() {
+ tech.isDroneOnDamage = false;
+ }
+ },
+ {
+ name: "non-Newtonian armor",
+ link: `
non-Newtonian armor`,
+ description: "after mob collisions
+66% defense for
10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
},
- {
- name: "liquid cooling",
- description: `after losing
healthfreeze all mobs for
7 seconds`,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isSlowFPS
- },
- requires: "clock gating",
- effect() {
- tech.isHarmFreeze = true;
- },
- remove() {
- tech.isHarmFreeze = false;
- }
+ requires: "",
+ effect() {
+ tech.isHarmArmor = true;
},
- {
- name: "clock gating",
- description: `after losing
health slow time by
50%+20% defense`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return simulation.fpsCapDefault > 45
- },
- requires: "FPS above 45",
- effect() {
- tech.isSlowFPS = true;
- },
- remove() {
- tech.isSlowFPS = false;
- }
+ remove() {
+ tech.isHarmArmor = false;
+ }
+ },
+ {
+ name: "Pauli exclusion",
+ description: `after mob collisions
become
invulnerable for
+3 seconds`,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
},
+ requires: "",
+ effect() {
+ m.collisionImmuneCycles += 180;
+ if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ },
+ remove() {
+ m.collisionImmuneCycles = 30;
+ }
+ },
+ {
+ name: "spin–statistics theorem",
+ description: `every
7 seconds
become
invulnerable for
+1.8 seconds`,
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true //m.collisionImmuneCycles > 30
+ },
+ requires: "",
+ effect() {
+ tech.cyclicImmunity += 108;
+ },
+ remove() {
+ tech.cyclicImmunity = 0;
+ }
+ },
+ {
+ name: "liquid cooling",
+ description: `after losing
healthfreeze all mobs for
7 seconds`,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isSlowFPS
+ },
+ requires: "clock gating",
+ effect() {
+ tech.isHarmFreeze = true;
+ },
+ remove() {
+ tech.isHarmFreeze = false;
+ }
+ },
+ {
+ name: "clock gating",
+ description: `after losing
health slow time by
50%+20% defense`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return simulation.fpsCapDefault > 45
+ },
+ requires: "FPS above 45",
+ effect() {
+ tech.isSlowFPS = true;
+ },
+ remove() {
+ tech.isSlowFPS = false;
+ }
+ },
- {
- name: "piezoelectricity",
- description: "if you
collide with a mob
generate
+2048 energy", //
reduce
defense by
15%
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isEnergyHealth
- },
- requires: "not mass-energy",
- effect() {
- tech.isPiezo = true;
- // if (simulation.isTextLogOpen) m.energy += 20.48;
- },
- remove() {
- tech.isPiezo = false;
+ {
+ name: "piezoelectricity",
+ description: "if you
collide with a mob
generate
+2048 energy", //
reduce
defense by
15%
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyHealth
+ },
+ requires: "not mass-energy",
+ effect() {
+ tech.isPiezo = true;
+ // if (simulation.isTextLogOpen) m.energy += 20.48;
+ },
+ remove() {
+ tech.isPiezo = false;
+ }
+ },
+ {
+ name: "electronegativity",
+ descriptionFunction() {
+ return `
+0.1% damage per current stored
energy(+${(10 * m.energy).toFixed(0)}%)`
+ },
+ // description: "
+1% damage per
8 stored
energy",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.energyDamage++
+ },
+ remove() {
+ tech.energyDamage = 0;
+ }
+ },
+ {
+ name: "ground state",
+ description: "
+200 maximum
energy–40% passive
energy generation",
+ // description: "reduce
defense by
66%you
no longer passively regenerate
energy",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isTimeCrystals
+ },
+ requires: "not time crystals",
+ effect() {
+ tech.isGroundState = true
+ m.setFieldRegen()
+ m.setMaxEnergy()
+ },
+ remove() {
+ tech.isGroundState = false
+ m.setFieldRegen()
+ m.setMaxEnergy()
+ }
+ },
+ {
+ name: "heat engine",
+ description: `
+50% damage–50 maximum
energy`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "not CPT",
+ damage: 1.5,
+ effect() {
+ tech.damage *= this.damage
+ tech.isMaxEnergyTech = true;
+ m.setMaxEnergy()
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isMaxEnergyTech = false;
+ m.setMaxEnergy()
+ }
+ },
+ {
+ name: "exothermic process",
+ description: "
+50% damageafter mobs
die –20% energy",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.55,
+ effect() {
+ tech.damage *= this.damage
+ tech.isEnergyLoss = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isEnergyLoss = false;
+ }
+ },
+ {
+ name: "Gibbs free energy",
+ description: `for each
energy below
100+0.7% damage`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isLowEnergyDamage = true;
+ },
+ remove() {
+ tech.isLowEnergyDamage = false;
+ }
+ },
+ {
+ name: "overcharge",
+ description: "
+66 maximum
energy+6% JUNK to
tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.bonusEnergy += 0.66
+ m.setMaxEnergy()
+ this.refundAmount += tech.addJunkTechToPool(0.06)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.bonusEnergy = 0;
+ m.setMaxEnergy()
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "Maxwells demon",
+ description: "
energy above your max decays
96% slower
+5% JUNK to
tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.energy > m.maxEnergy || build.isExperimentSelection
+ },
+ requires: "energy above your max",
+ effect() {
+ tech.overfillDrain = 0.94 //70% = 1-(1-0.75)/(1-0.15) //92% = 1-(1-0.75)/(1-0.87)
+ this.refundAmount += tech.addJunkTechToPool(0.05)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.overfillDrain = 0.7
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "inductive charging",
+ description: "if
crouched +600% passive
energy generation
if not
crouched energy generation is disabled",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isDamageAfterKillNoRegen
+ },
+ requires: "not parasitism",
+ effect() {
+ tech.isCrouchRegen = true; //only used to check for requirements
+ m.regenEnergy = function () {
+ if (m.immuneCycle < m.cycle && m.crouch) m.energy += 7 * m.fieldRegen;
+ if (m.energy < 0) m.energy = 0
}
},
- {
- name: "electronegativity",
- descriptionFunction() {
- return `
+0.1% damage per current stored
energy(+${(10*m.energy).toFixed(0)}%)`
- },
- // description: "
+1% damage per
8 stored
energy",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.energyDamage++
- },
- remove() {
- tech.energyDamage = 0;
+ remove() {
+ tech.isCrouchRegen = false;
+ m.regenEnergy = m.regenEnergyDefault
+ }
+ },
+ {
+ name: "energy conservation",
+ description: "
4% of
damage done recovered as
energy",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.energySiphon += 0.04;
+ },
+ remove() {
+ tech.energySiphon = 0;
+ }
+ },
+ {
+ name: "parasitism",
+ description: "if a mob has
died in the last
5 seconds+60% damage, inhibit
energy generation",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isCrouchRegen
+ },
+ requires: "not inductive charging",
+ effect() {
+ tech.isDamageAfterKillNoRegen = true;
+ m.regenEnergy = function () {
+ if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen;
+ if (m.energy < 0) m.energy = 0
}
},
- {
- name: "ground state",
- description: "
+200 maximum
energy–40% passive
energy generation",
- // description: "reduce
defense by
66%you
no longer passively regenerate
energy",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isTimeCrystals
- },
- requires: "not time crystals",
- effect() {
- tech.isGroundState = true
- m.setFieldRegen()
- m.setMaxEnergy()
- },
- remove() {
- tech.isGroundState = false
- m.setFieldRegen()
- m.setMaxEnergy()
- }
+ remove() {
+ if (this.count) m.regenEnergy = m.regenEnergyDefault
+ tech.isDamageAfterKillNoRegen = false;
+ }
+ },
+ {
+ name: "waste heat recovery",
+ description: "if a mob has
died in the last
5 secondsgenerate
5% of max
energy per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
},
- {
- name: "heat engine",
- description: `
+50% damage–50 maximum
energy`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "not CPT",
- damage: 1.5,
- effect() {
- tech.damage *= this.damage
- tech.isMaxEnergyTech = true;
- m.setMaxEnergy()
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isMaxEnergyTech = false;
- m.setMaxEnergy()
- }
+ requires: "",
+ effect() {
+ tech.isEnergyRecovery = true;
},
- {
- name: "exothermic process",
- description: "
+50% damageafter mobs
die –20% energy",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- damage: 1.55,
- effect() {
- tech.damage *= this.damage
- tech.isEnergyLoss = true;
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isEnergyLoss = false;
- }
+ remove() {
+ tech.isEnergyRecovery = false;
+ }
+ },
+ {
+ name: "recycling",
+ description: "if a mob has
died in the last
5 secondsrecover
0.5% of max
health per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
},
- {
- name: "Gibbs free energy",
- description: `for each
energy below
100+0.7% damage`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.isLowEnergyDamage = true;
- },
- remove() {
- tech.isLowEnergyDamage = false;
- }
+ requires: "",
+ effect() {
+ tech.isHealthRecovery = true;
},
- {
- name: "overcharge",
- description: "
+66 maximum
energy+6% JUNK to
tech pool",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.bonusEnergy += 0.66
- m.setMaxEnergy()
- this.refundAmount += tech.addJunkTechToPool(0.06)
- },
- refundAmount: 0,
- remove() {
- tech.bonusEnergy = 0;
- m.setMaxEnergy()
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
+ remove() {
+ tech.isHealthRecovery = false;
+ }
+ },
+ {
+ name: "torpor",
+ description: "if a mob has
not died in the last
5 seconds+66% defense",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHarmReduceNoKill = true;
+ },
+ remove() {
+ tech.isHarmReduceNoKill = false;
+ }
+ },
+ {
+ name: "homeostasis",
+ descriptionFunction() {
+ return `for each
health below
100+0.8% defense (${(100 * (Math.max(0, 1 - m.health) * 0.8)).toFixed(0)}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.health < 0.6 || build.isExperimentSelection
+ },
+ requires: "health below 60",
+ effect() {
+ tech.isLowHealthDefense = true;
+ },
+ remove() {
+ tech.isLowHealthDefense = false;
+ }
+ },
+ {
+ name: "negative feedback",
+ descriptionFunction() {
+ return `for each ${tech.isEnergyHealth ? "
energy" : "
health"} below
100+0.7% damage (${(70 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health))).toFixed(0)}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.health < 0.6 || build.isExperimentSelection
+ },
+ requires: "health below 60",
+ effect() {
+ tech.isLowHealthDmg = true; //used in mob.damage()
+ },
+ remove() {
+ tech.isLowHealthDmg = false;
+ }
+ },
+ {
+ name: "Zenos paradox",
+ descriptionFunction() {
+ return `
+85% defense–5% of current ${tech.isEnergyHealth ? "
energy" : "
health"} every
5 seconds`
+ },
+ // description: "
+85% defense–5% of current
health every
5 seconds",
+ // description: "every
5 seconds remove
1/10 of your
healthreduce
defense by
90%",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isZeno = true;
+ },
+ remove() {
+ tech.isZeno = false;
+ }
+ },
+ {
+ name: "antiscience",
+ descriptionFunction() {
+ return `
+66% damage–10 ${tech.isEnergyHealth ? "
energy" : "
health"} after picking up a
tech`
+ },
+ // description: "
+66% damage–10 health after picking up a
tech",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.66,
+ effect() {
+ tech.damage *= this.damage
+ tech.isTechDamage = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isTechDamage = false;
+ }
+ },
+ {
+ name: "ergodicity",
+ descriptionFunction() {
+ return `${powerUps.orb.heal()} have
-50% effect
+66% damage`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.66,
+ effect() {
+ tech.damage *= this.damage
+ tech.isHalfHeals = true;
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const scale = Math.sqrt(0.5)
+ powerUp[i].size *= scale
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
}
}
},
- {
- name: "Maxwells demon",
- description: "
energy above your max decays
96% slower
+5% JUNK to
tech pool",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.energy > m.maxEnergy || build.isExperimentSelection
- },
- requires: "energy above your max",
- effect() {
- tech.overfillDrain = 0.94 //70% = 1-(1-0.75)/(1-0.15) //92% = 1-(1-0.75)/(1-0.87)
- this.refundAmount += tech.addJunkTechToPool(0.05)
- },
- refundAmount: 0,
- remove() {
- tech.overfillDrain = 0.7
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
- }
- }
- },
- {
- name: "inductive charging",
- description: "if
crouched +600% passive
energy generation
if not
crouched energy generation is disabled",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isDamageAfterKillNoRegen
- },
- requires: "not parasitism",
- effect() {
- tech.isCrouchRegen = true; //only used to check for requirements
- m.regenEnergy = function() {
- if (m.immuneCycle < m.cycle && m.crouch) m.energy += 7 * m.fieldRegen;
- if (m.energy < 0) m.energy = 0
- }
- },
- remove() {
- tech.isCrouchRegen = false;
- m.regenEnergy = m.regenEnergyDefault
- }
- },
- {
- name: "energy conservation",
- description: "
4% of
damage done recovered as
energy",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.energySiphon += 0.04;
- },
- remove() {
- tech.energySiphon = 0;
- }
- },
- {
- name: "parasitism",
- description: "if a mob has
died in the last
5 seconds+60% damage, inhibit
energy generation",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isCrouchRegen
- },
- requires: "not inductive charging",
- effect() {
- tech.isDamageAfterKillNoRegen = true;
- m.regenEnergy = function() {
- if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen;
- if (m.energy < 0) m.energy = 0
- }
- },
- remove() {
- if (this.count) m.regenEnergy = m.regenEnergyDefault
- tech.isDamageAfterKillNoRegen = false;
- }
- },
- {
- name: "waste heat recovery",
- description: "if a mob has
died in the last
5 secondsgenerate
5% of max
energy per second",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isEnergyRecovery = true;
- },
- remove() {
- tech.isEnergyRecovery = false;
- }
- },
- {
- name: "recycling",
- description: "if a mob has
died in the last
5 secondsrecover
0.5% of max
health per second",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isHealTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isHealthRecovery = true;
- },
- remove() {
- tech.isHealthRecovery = false;
- }
- },
- {
- name: "torpor",
- description: "if a mob has
not died in the last
5 seconds+66% defense",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isHarmReduceNoKill = true;
- },
- remove() {
- tech.isHarmReduceNoKill = false;
- }
- },
- {
- name: "homeostasis",
- descriptionFunction() {
- return `for each
health below
100+0.8% defense (${(100*(Math.max(0, 1 - m.health) * 0.8)).toFixed(0)}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return m.health < 0.6 || build.isExperimentSelection
- },
- requires: "health below 60",
- effect() {
- tech.isLowHealthDefense = true;
- },
- remove() {
- tech.isLowHealthDefense = false;
- }
- },
- {
- name: "negative feedback",
- descriptionFunction() {
- return `for each ${tech.isEnergyHealth ? "
energy": "
health"} below
100+0.7% damage (${(70*Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health))).toFixed(0)}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return m.health < 0.6 || build.isExperimentSelection
- },
- requires: "health below 60",
- effect() {
- tech.isLowHealthDmg = true; //used in mob.damage()
- },
- remove() {
- tech.isLowHealthDmg = false;
- }
- },
- {
- name: "Zenos paradox",
- descriptionFunction() {
- return `
+85% defense–5% of current ${tech.isEnergyHealth ? "
energy": "
health"} every
5 seconds`
- },
- // description: "
+85% defense–5% of current
health every
5 seconds",
- // description: "every
5 seconds remove
1/10 of your
healthreduce
defense by
90%",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isZeno = true;
- },
- remove() {
- tech.isZeno = false;
- }
- },
- {
- name: "antiscience",
- descriptionFunction() {
- return `
+66% damage–10 ${tech.isEnergyHealth ? "
energy": "
health"} after picking up a
tech`
- },
- // description: "
+66% damage–10 health after picking up a
tech",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- damage: 1.66,
- effect() {
- tech.damage *= this.damage
- tech.isTechDamage = true;
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isTechDamage = false;
- }
- },
- {
- name: "ergodicity",
- descriptionFunction() {
- return `${powerUps.orb.heal()} have
-50% effect
+66% damage`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- damage: 1.66,
- effect() {
- tech.damage *= this.damage
- tech.isHalfHeals = true;
+ remove() {
+ if (this.count) {
+ tech.damage /= this.damage
for (let i = 0; i < powerUp.length; i++) {
if (powerUp[i].name === "heal") {
- const scale = Math.sqrt(0.5)
+ const scale = 1 / Math.sqrt(0.5)
powerUp[i].size *= scale
Matter.Body.scale(powerUp[i], scale, scale); //grow
}
}
- },
- remove() {
- if (this.count) {
- tech.damage /= this.damage
- for (let i = 0; i < powerUp.length; i++) {
- if (powerUp[i].name === "heal") {
- const scale = 1 / Math.sqrt(0.5)
- powerUp[i].size *= scale
- Matter.Body.scale(powerUp[i], scale, scale); //grow
- }
- }
- }
- tech.isHalfHeals = false;
}
+ tech.isHalfHeals = false;
+ }
+ },
+ {
+ name: "fluoroantimonic acid",
+ description: "if your
health is above
100+35% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.maxHealth > 1;
},
- {
- name: "fluoroantimonic acid",
- description: "if your
health is above
100+35% damage",
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.maxHealth > 1;
- },
- requires: "max health above 100",
- effect() {
- tech.isAcidDmg = true;
- },
- remove() {
- tech.isAcidDmg = false;
- }
+ requires: "max health above 100",
+ effect() {
+ tech.isAcidDmg = true;
},
+ remove() {
+ tech.isAcidDmg = false;
+ }
+ },
- {
- name: "adiabatic healing",
- descriptionFunction() {
- return `${powerUps.orb.heal()} have
+100% effect
+5% JUNK to
tech pool`
- },
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isHealTech: true,
- allowed() {
- return (m.health / m.maxHealth) < 0.7 || build.isExperimentSelection
- },
- requires: "under 70% health",
- effect() {
- tech.largerHeals++;
- for (let i = 0; i < powerUp.length; i++) {
- if (powerUp[i].name === "heal") {
- const oldSize = powerUp[i].size
- powerUp[i].size = powerUps.heal.size() //update current heals
- const scale = powerUp[i].size / oldSize
- Matter.Body.scale(powerUp[i], scale, scale); //grow
- }
- }
- this.refundAmount += tech.addJunkTechToPool(0.05)
- },
- refundAmount: 0,
- remove() {
- tech.largerHeals = 1;
- for (let i = 0; i < powerUp.length; i++) {
- if (powerUp[i].name === "heal") {
- const oldSize = powerUp[i].size
- powerUp[i].size = powerUps.heal.size() //update current heals
- const scale = powerUp[i].size / oldSize
- Matter.Body.scale(powerUp[i], scale, scale); //grow
- }
- }
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
+ {
+ name: "adiabatic healing",
+ descriptionFunction() {
+ return `${powerUps.orb.heal()} have
+100% effect
+5% JUNK to
tech pool`
+ },
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return (m.health / m.maxHealth) < 0.7 || build.isExperimentSelection
+ },
+ requires: "under 70% health",
+ effect() {
+ tech.largerHeals++;
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
}
}
+ this.refundAmount += tech.addJunkTechToPool(0.05)
},
- {
- name: "quenching",
- descriptionFunction() {
- return `after over healing from ${powerUps.orb.heal()}
gain max
health and lose current
health`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isOverHeal = true;
- },
- remove() {
- tech.isOverHeal = false;
- }
- },
- {
- name: "negative entropy",
- descriptionFunction() {
- return `at the start of each
levelfor every
33% missing ${tech.isEnergyHealth ? "
energy": "
health"} spawn ${powerUps.orb.heal()}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isHealTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isHealLowHealth = true;
- },
- remove() {
- tech.isHealLowHealth = false;
- }
- },
- {
- name: "enthalpy",
- descriptionFunction() {
- return `doing
damage has a small chance to spawn ${powerUps.orb.heal(1)}` //
–10% defense
- },
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isHealTech: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.healthDrain += 0.019;
- },
- remove() {
- tech.healthDrain = 0;
- }
- },
- {
- name: "maintenance",
- descriptionFunction() {
- return `double the
frequency of finding
healing techspawn ${powerUps.orb.heal(13)}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0; i < 13; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "heal");
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isHealTech) tech.tech[i].frequency *= 2
+ refundAmount: 0,
+ remove() {
+ tech.largerHeals = 1;
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
}
- },
- remove() {}
+ }
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "quenching",
+ descriptionFunction() {
+ return `after over healing from ${powerUps.orb.heal()}
gain max
health and lose current
health`
},
- {
- name: "anthropic principle",
- nameInfo: "
",
- addNameInfo() {
- setTimeout(function() {
- powerUps.research.changeRerolls(0)
- }, 1000);
- },
- descriptionFunction() {
- return `once per level, instead of
dyinguse ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(5)}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isHealTech: true,
- allowed() {
- return powerUps.research.count > 0 || build.isExperimentSelection
- },
- requires: "at least 1 research",
- effect() {
- tech.isDeathAvoid = true;
- tech.isDeathAvoidedThisLevel = false;
- setTimeout(function() {
- powerUps.research.changeRerolls(0)
- }, 1000);
- },
- remove() {
- tech.isDeathAvoid = false;
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isOverHeal = true;
+ },
+ remove() {
+ tech.isOverHeal = false;
+ }
+ },
+ {
+ name: "negative entropy",
+ descriptionFunction() {
+ return `at the start of each
levelfor every
33% missing ${tech.isEnergyHealth ? "
energy" : "
health"} spawn ${powerUps.orb.heal()}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHealLowHealth = true;
+ },
+ remove() {
+ tech.isHealLowHealth = false;
+ }
+ },
+ {
+ name: "enthalpy",
+ descriptionFunction() {
+ return `doing
damage has a small chance to spawn ${powerUps.orb.heal(1)}` //
–10% defense
+ },
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.healthDrain += 0.019;
+ },
+ remove() {
+ tech.healthDrain = 0;
+ }
+ },
+ {
+ name: "maintenance",
+ descriptionFunction() {
+ return `double the
frequency of finding
healing techspawn ${powerUps.orb.heal(13)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < 13; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "heal");
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isHealTech) tech.tech[i].frequency *= 2
}
},
- {
- name: "weak anthropic principle",
- description: "after
anthropic principle prevents your
death+50% duplication chance for that level",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isDeathAvoid
- },
- requires: "anthropic principle",
- effect() {
- tech.isAnthropicTech = true
- powerUps.setDupChance(); //needed after adjusting duplication chance
- },
- remove() {
- tech.isAnthropicTech = false
- powerUps.setDupChance(); //needed after adjusting duplication chance
- }
+ remove() { }
+ },
+ {
+ name: "anthropic principle",
+ nameInfo: "
",
+ addNameInfo() {
+ setTimeout(function () {
+ powerUps.research.changeRerolls(0)
+ }, 1000);
},
- {
- name: "strong anthropic principle",
- description: "after
anthropic principle prevents your
death+137.03599% damage for that level",
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isDeathAvoid
- },
- requires: "anthropic principle",
- effect() {
- tech.isAnthropicDamage = true
- },
- remove() {
- tech.isAnthropicDamage = false
- }
+ descriptionFunction() {
+ return `once per level, instead of
dyinguse ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(5)}`
},
- {
- name: "quantum immortality",
- description: "
+33% defenseafter
dying, continue in an
alternate reality",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isImmortal = true;
- },
- remove() {
- tech.isImmortal = false;
- }
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return powerUps.research.count > 0 || build.isExperimentSelection
},
- {
- name: "Hilbert space",
- description: "
+91% damageafter a
collision enter an
alternate reality",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isResearchReality && !tech.isSwitchReality
- },
- requires: "not Ψ(t) collapse, many-worlds",
- damage: 1.91,
- effect() {
- tech.damage *= this.damage
- tech.isCollisionRealitySwitch = true;
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isCollisionRealitySwitch = false;
- }
+ requires: "at least 1 research",
+ effect() {
+ tech.isDeathAvoid = true;
+ tech.isDeathAvoidedThisLevel = false;
+ setTimeout(function () {
+ powerUps.research.changeRerolls(0)
+ }, 1000);
},
- {
- name: "many-worlds",
- // description: "each
level is an
alternate reality, where you
find a
tech at the start of each level",
- description: `on each new
level spawn a
tech power up
and enter an
alternate reality`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isResearchReality && !tech.isCollisionRealitySwitch
- },
- requires: "not Ψ(t) collapse, Hilbert space",
- effect() {
- tech.isSwitchReality = true;
- },
- remove() {
- tech.isSwitchReality = false;
- }
+ remove() {
+ tech.isDeathAvoid = false;
+ }
+ },
+ {
+ name: "weak anthropic principle",
+ description: "after
anthropic principle prevents your
death+50% duplication chance for that level",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isDeathAvoid
},
- {
- name: "Ψ(t) collapse",
- link: `
Ψ(t) collapse`,
- description: `spawn ${powerUps.orb.research(16)}
after you
research enter an
alternate reality`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch
- },
- requires: "not many-worlds, Hilbert space, pseudoscience",
- bonusResearch: 16,
- effect() {
- tech.isResearchReality = true;
- for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false);
- },
- remove() {
- tech.isResearchReality = false;
- if (this.count > 0) powerUps.research.changeRerolls(-this.bonusResearch)
- }
+ requires: "anthropic principle",
+ effect() {
+ tech.isAnthropicTech = true
+ powerUps.setDupChance(); //needed after adjusting duplication chance
},
- {
- name: "decoherence",
- description: `
tech options you don't
choose won't
reoccurspawn ${powerUps.orb.research(6)}`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism
- },
- requires: "not superdeterminism",
- bonusResearch: 6,
- effect() {
- tech.isBanish = true
- for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
- },
- remove() {
- if (tech.isBanish) {
- tech.isBanish = false
- //reset banish list
- for (let i = 0; i < tech.tech.length; i++) {
- if (tech.tech[i].isBanished) tech.tech[i].isBanished = false
- }
- powerUps.research.changeRerolls(-this.bonusResearch)
- }
+ remove() {
+ tech.isAnthropicTech = false
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "strong anthropic principle",
+ description: "after
anthropic principle prevents your
death+137.03599% damage for that level",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isDeathAvoid
+ },
+ requires: "anthropic principle",
+ effect() {
+ tech.isAnthropicDamage = true
+ },
+ remove() {
+ tech.isAnthropicDamage = false
+ }
+ },
+ {
+ name: "quantum immortality",
+ description: "
+33% defenseafter
dying, continue in an
alternate reality",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isImmortal = true;
+ },
+ remove() {
+ tech.isImmortal = false;
+ }
+ },
+ {
+ name: "Hilbert space",
+ description: "
+91% damageafter a
collision enter an
alternate reality",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isResearchReality && !tech.isSwitchReality
+ },
+ requires: "not Ψ(t) collapse, many-worlds",
+ damage: 1.91,
+ effect() {
+ tech.damage *= this.damage
+ tech.isCollisionRealitySwitch = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isCollisionRealitySwitch = false;
+ }
+ },
+ {
+ name: "many-worlds",
+ // description: "each
level is an
alternate reality, where you
find a
tech at the start of each level",
+ description: `on each new
level spawn a
tech power up
and enter an
alternate reality`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isResearchReality && !tech.isCollisionRealitySwitch
+ },
+ requires: "not Ψ(t) collapse, Hilbert space",
+ effect() {
+ tech.isSwitchReality = true;
+ },
+ remove() {
+ tech.isSwitchReality = false;
+ }
+ },
+ {
+ name: "Ψ(t) collapse",
+ link: `
Ψ(t) collapse`,
+ description: `spawn ${powerUps.orb.research(16)}
after you
research enter an
alternate reality`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch
+ },
+ requires: "not many-worlds, Hilbert space, pseudoscience",
+ bonusResearch: 16,
+ effect() {
+ tech.isResearchReality = true;
+ for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false);
+ },
+ remove() {
+ tech.isResearchReality = false;
+ if (this.count > 0) powerUps.research.changeRerolls(-this.bonusResearch)
+ }
+ },
+ {
+ name: "decoherence",
+ description: `
tech options you don't
choose won't
reoccurspawn ${powerUps.orb.research(6)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ bonusResearch: 6,
+ effect() {
+ tech.isBanish = true
+ for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ },
+ remove() {
+ if (tech.isBanish) {
tech.isBanish = false
- }
- },
- {
- name: "renormalization",
- description: `
44% chance to spawn ${powerUps.orb.research(1)}
after consuming ${powerUps.orb.research(1)}`,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (powerUps.research.count > 3 || build.isExperimentSelection) && !tech.isSuperDeterminism
- },
- requires: "at least 4 research, not superdeterminism",
- effect() {
- tech.renormalization = true;
- },
- remove() {
- tech.renormalization = false;
- }
- },
- {
- name: "perturbation theory",
- description: `if you have no ${powerUps.orb.research(1)} in your inventory
+60% fire rate`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return powerUps.research.count === 0
- },
- requires: "no research",
- effect() {
- tech.isRerollHaste = true;
- tech.researchHaste = 0.4;
- b.setFireCD();
- },
- remove() {
- tech.isRerollHaste = false;
- tech.researchHaste = 1;
- b.setFireCD();
- }
- },
- {
- name: "ansatz",
- description: `after choosing a
field,
tech, or
gunif you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(2)}`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return powerUps.research.count < 1 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality
- },
- requires: "no research, not superdeterminism, Ψ(t) collapse, perturbation theory",
- effect() {
- tech.isAnsatz = true;
- },
- remove() {
- tech.isAnsatz = false;
- }
- },
- {
- name: "Bayesian statistics",
- // description: `for each ${powerUps.orb.research(1)} in your inventory
+3.8% damage`,
- descriptionFunction() {
- return `spawn ${powerUps.orb.research(this.bonusResearch)}
+3% damage per ${powerUps.orb.research(1)}
(${(3*powerUps.research.count).toFixed(0)}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return powerUps.research.count > 2 || build.isExperimentSelection
- },
- requires: "at least 3 research",
- bonusResearch: 3,
- effect() {
- powerUps.spawnDelay("research", this.bonusResearch)
- tech.isRerollDamage = true;
- },
- remove() {
- tech.isRerollDamage = false;
- if (this.count) {
- powerUps.research.changeRerolls(-this.bonusResearch)
- }
- }
- },
- {
- name: "pseudoscience",
- description: "
when selecting a power up, research 3 timesfor
free, but add
1-4% JUNK to the
tech pool",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isResearchReality && !tech.isSuperDeterminism //tech.isResearchBoss || tech.isMetaAnalysis || tech.isRerollBots || tech.isDeathAvoid || tech.isRerollDamage || build.isExperimentSelection
- },
- requires: "not Ψ(t) collapse, superdeterminism", //"abiogenesis, meta-analysis, bot fabrication, anthropic principle, or Bayesian statistics, not Ψ(t) collapse",
- effect() {
- tech.isJunkResearch = true;
- },
- remove() {
- tech.isJunkResearch = false;
- }
- },
- {
- name: "brainstorming",
- description: "
tech choices
randomizeevery
2 seconds for
10 seconds",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism
- },
- requires: "not superdeterminism",
- effect() {
- tech.isBrainstorm = true
- tech.isBrainstormActive = false
- tech.brainStormDelay = 2000 - simulation.difficultyMode * 100
- },
- remove() {
- tech.isBrainstorm = false
- tech.isBrainstormActive = false
- }
- },
- {
- name: "cross-disciplinary",
- description: "
tech have an extra
field or
gun choice+5% chance to
duplicate spawned
power ups",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isDeterminism
- },
- requires: "not determinism",
- effect() {
- tech.isExtraGunField = true;
- },
- remove() {
- tech.isExtraGunField = false;
- }
- },
- {
- name: "emergence",
- description: "
tech,
fields, and
guns have
+1 choice+8% damage",
- // description: "
tech,
fields, and
guns have
+2 choices+3% JUNK to
tech pool",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isDeterminism
- },
- requires: "not determinism",
- damage: 1.08,
- effect() {
- tech.extraChoices += 1;
- tech.damage *= this.damage
- // this.refundAmount += tech.addJunkTechToPool(0.03)
- },
- refundAmount: 0,
- remove() {
- tech.extraChoices = 0;
- if (this.count > 0) {
- tech.damage /= this.damage
- // if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
- }
- }
- },
- {
- name: "path integral",
- link: `
path integral`,
- description: "your next
tech choice has all possible
options+5% JUNK to
tech pool",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- // isJunk: true,
- allowed() {
- return !tech.isDeterminism && !tech.isBrainstorm
- },
- requires: "not determinism, brainstorm",
- effect() {
- tech.tooManyTechChoices = 1
- // for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
- this.refundAmount += tech.addJunkTechToPool(0.05)
- },
- refundAmount: 0,
- remove() {
- tech.tooManyTechChoices = 0
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
- }
- }
- },
- {
- name: "determinism",
- description: "spawn
5 techonly
1 choice for
tech,
fields, and
guns",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBadRandomOption: true,
- isNonRefundable: true,
- allowed() {
- return !tech.extraChoices && !tech.isExtraGunField && !tech.isFlipFlopChoices
- },
- requires: "not emergence, cross-disciplinary, integrated circuit",
- effect() {
- tech.isDeterminism = true;
- //if you change the number spawned also change it in Born rule
- for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
- },
- remove() {
- if (!this.count) tech.isDeterminism = false;
- }
- },
- {
- name: "superdeterminism",
- description: `spawn
5 techyou can't
cancel and ${powerUps.orb.research(1)} no longer
spawn`,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBadRandomOption: true,
- isNonRefundable: true,
- allowed() {
- return tech.isDeterminism && !tech.isAnsatz && !tech.isJunkResearch && !tech.isBrainstorm
- },
- requires: "determinism, not ansatz, pseudoscience, brainstorming",
- effect() {
- tech.isSuperDeterminism = true;
- //if you change the number spawned also change it in Born rule
- for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
- },
- remove() {
- tech.isSuperDeterminism = false;
- }
- },
- {
- name: "technical debt",
- descriptionFunction() {
- return `
+300% damage –15% damagefor each
tech you have learned
(${(Math.floor(100*(Math.min(Math.pow(0.85, tech.totalCount-20), 4 - 0.15 * tech.totalCount)))-100)}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- tech.isTechDebt = true;
- },
- remove() {
- tech.isTechDebt = false;
- }
- },
- {
- name: "abiogenesis",
- // description: `use ${powerUps.orb.research(4)}(or
49% JUNK to the
tech pool if you can't) to add a 2nd
boss to each level`,
- description: `
as a level begins spawn a 2nd boss using ${powerUps.orb.research(4)}
(+49% JUNK to the tech pool if you can't pay)`,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 3) && !tech.isDuplicateBoss
- },
- requires: "at least 4 research, not parthenogenesis",
- effect() {
- tech.isResearchBoss = true;
- },
- remove() {
- tech.isResearchBoss = false;
- }
- },
- {
- name: "meta-analysis",
- description: `if you choose a
JUNKtech you instead get a
random normal
tech and spawn ${powerUps.orb.research(2)}`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.junkCount > 0
- },
- requires: "some JUNK tech",
- effect() {
- tech.isMetaAnalysis = true
- },
- remove() {
- tech.isMetaAnalysis = false
- }
- },
- {
- name: "dark patterns",
- description: "
+15% damage+15% JUNK to
tech pool",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- damage: 1.15,
- effect() {
- tech.damage *= this.damage
- this.refundAmount += tech.addJunkTechToPool(0.15)
- },
- refundAmount: 0,
- remove() {
- if (this.count > 0) {
- tech.damage /= this.damage
- if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
- }
- }
- },
- {
- name: "exciton",
- descriptionFunction() {
- return `
after mobs die they have a 16% chance to
spawn ${powerUps.orb.boost(1)} that give +${(powerUps.boost.damage*100).toFixed(0)}% damage for ${(powerUps.boost.duration/60).toFixed(0)} seconds`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.isBoostPowerUps = true
- },
- remove() {
- tech.isBoostPowerUps = false
- }
- },
- {
- name: "band gap",
- descriptionFunction() {
- return `${powerUps.orb.boost(1)} give
+77% damagebut their duration is reduced by
1 second`
- },
- maxCount: 9,
- count: 1,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isBoostPowerUps || tech.isBoostReplaceAmmo
- },
- requires: "exciton, quasiparticles",
- effect() {
- powerUps.boost.duration -= 60
- powerUps.boost.damage += 0.77
- },
- remove() {
- powerUps.boost.duration = 600
- powerUps.boost.damage = 1.25
- }
- },
- {
- name: "eternalism",
- description: "
+30% damagetime can't be
paused (time can be dilated)",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isPauseSwitchField && !tech.isPauseEjectTech && !tech.isWormHolePause
- },
- requires: "not unified field theory, paradigm shift, invariant",
- damage: 1.3,
- effect() {
- tech.damage *= this.damage
- tech.isNoDraftPause = true
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.isNoDraftPause = false
- }
- },
- {
- name: "paradigm shift",
- description: `
clicking tech while paused
ejects them
20% chance to remove without
ejecting`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism && !tech.isNoDraftPause
- },
- requires: "not superdeterminism, eternalism",
- effect() {
- tech.isPauseEjectTech = true;
- },
- remove() {
- tech.isPauseEjectTech = false;
- }
- },
- {
- name: "unified field theory",
- description: `
clicking the field box when paused cycles your field
double the frequency of finding fieldtech`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism && !tech.isNoDraftPause
- },
- requires: "not superdeterminism, eternalism",
- effect() {
- tech.isPauseSwitchField = true;
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isFieldTech) tech.tech[i].frequency *= 2
- }
- },
- remove() {
- tech.isPauseSwitchField = false;
- if (this.count > 1) {
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isFieldTech) tech.tech[i].frequency /= 2
- }
- }
- }
- },
- {
- name: "field coupling",
- descriptionFunction() {
- return `spawn ${powerUps.orb.coupling(10)}
that each give
+0.1 coupling${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}`
- },
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- powerUps.spawnDelay("coupling", 10)
- },
- remove() {
- if (this.count) {
- m.couplingChange(-this.count)
- }
- }
- },
- {
- name: "quintessence",
- descriptionFunction() {
- let converted = powerUps.research.count * this.couplingToResearch * 10
- if (this.count) converted = this.researchUsed * this.couplingToResearch * 10
-
- let orbText
- if (converted > 15) {
- orbText = `${converted} ${powerUps.orb.coupling()}`
- } else {
- orbText = powerUps.orb.coupling(converted)
- }
- return `use all your ${powerUps.orb.research(1)} to spawn
${orbText}that each give
+0.1 coupling${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return powerUps.research.count > 3
- },
- requires: "",
- researchUsed: 0,
- couplingToResearch: 0.25,
- effect() {
- // let count = 0
- // while (powerUps.research.count > 0 && powerUps.research.count !== Infinity) {
- // powerUps.research.changeRerolls(-1)
- // count += 2.5
- // this.researchUsed++
- // }
- // powerUps.spawnDelay("coupling", Math.floor(count))
-
- let cycle = () => {
- if (powerUps.research.count > 0 && powerUps.research.count !== Infinity) {
- if (m.alive) requestAnimationFrame(cycle);
- if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
- powerUps.research.changeRerolls(-1)
- this.researchUsed++
- powerUps.spawn(m.pos.x + 50 * (Math.random() - 0.5), m.pos.y + 50 * (Math.random() - 0.5), "coupling");
- }
- } else { //exit delay loop
- }
- }
- requestAnimationFrame(cycle);
- },
- remove() {
- if (this.count) {
- m.couplingChange(-this.researchUsed * this.couplingToResearch)
- powerUps.research.changeRerolls(this.researchUsed)
- this.researchUsed = 0
- }
- }
- },
- {
- name: "virtual particles",
- descriptionFunction() {
- return `after mobs
die they have a
17% chance to
spawn ${powerUps.orb.coupling(1)} that each give
+0.1 coupling${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => true,
- requires: "",
- effect() {
- tech.isCouplingPowerUps = true //about 20-30 mobs per level so at 16% and 0.1 coupling that's about 25 * 0.16 * 0.1 = 0.4 coupling per level with out duplication
- },
- remove() {
- tech.isCouplingPowerUps = false
- }
- },
- {
- name: "fine-structure constant",
- descriptionFunction() {
- return `spawn ${this.value} ${powerUps.orb.coupling(1)} that each give
+0.1 coupling-0.5 coupling after mob
collisions${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- value: 60,
- effect() {
- tech.isCouplingNoHit = true
- powerUps.spawnDelay("coupling", this.value)
- },
- remove() {
- if (this.count) {
- m.couplingChange(-this.value)
- }
- tech.isCouplingNoHit = false
- }
- },
- {
- name: "residual dipolar coupling",
- descriptionFunction() {
- return `clicking
cancel for a
field,
tech, or
gunspawns ${powerUps.orb.coupling(5)}that each give
+0.1 coupling${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism
- },
- requires: "not superdeterminism",
- effect() {
- tech.isCancelCouple = true
- },
- remove() {
- tech.isCancelCouple = false
- }
- },
- {
- name: "commodities exchange",
- descriptionFunction() {
- return `clicking
cancel for a
field,
tech, or
gunspawns
5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism
- },
- requires: "not superdeterminism",
- effect() {
- tech.isCancelRerolls = true
- },
- remove() {
- tech.isCancelRerolls = false
- }
- },
- {
- name: "options exchange",
- link: `
options exchange`,
- description: `clicking
cancel for a
field,
tech, or
gunhas a
85% chance to randomize
choices`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism //&& (tech.isCancelRerolls || tech.isCancelDuplication)
- },
- requires: "not superdeterminism", //futures exchange, commodities exchange,
- effect() {
- tech.isCancelTech = true
- },
- remove() {
- tech.isCancelTech = false
- }
- },
- {
- name: "futures exchange",
- description: "clicking
cancel for a
field,
tech, or
gungives
+4.3% power up
duplication chance",
- // descriptionFunction() {
- // return `clicking
× to
cancel a
field,
tech, or
gungives
+${4.9 - 0.15*simulation.difficultyMode}% power up
duplication chance`
- // },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() < 1 && !tech.isSuperDeterminism
- },
- requires: "below 100% duplication chance, not superdeterminism",
- effect() {
- tech.isCancelDuplication = true //search for tech.cancelCount to balance
- powerUps.setDupChance(); //needed after adjusting duplication chance
- },
- remove() {
- tech.isCancelDuplication = false
- powerUps.setDupChance(); //needed after adjusting duplication chance
- }
- },
- {
- name: "replication",
- description: "
+10% chance to
duplicate spawned
power ups+33% JUNK to
tech pool",
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() < 1.
- },
- requires: "below 100% duplication chance",
- effect() {
- tech.duplicateChance += 0.1
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
- this.refundAmount += tech.addJunkTechToPool(0.33)
- },
- refundAmount: 0,
- remove() {
- tech.duplicateChance = 0
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
- }
- }
- },
- {
- name: "stimulated emission",
- description: "
+15% chance to
duplicate spawned
power ups,
but after a
collision eject
1 tech",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() < 1
- },
- requires: "below 1% duplication chance",
- effect() {
- tech.isStimulatedEmission = true
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.15);
- },
- remove() {
- tech.isStimulatedEmission = false
- powerUps.setDupChance(); //needed after adjusting duplication chance
- }
- },
- {
- name: "metastability",
- description: "
+12% chance to
duplicate spawned
power upsduplicates explode with a
3 second
half-life",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() < 1
- },
- requires: "below 100% duplication chance",
- effect() {
- tech.isPowerUpsVanish = true
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
- },
- remove() {
- tech.isPowerUpsVanish = false
- powerUps.setDupChance(); //needed after adjusting duplication chance
- }
- },
- {
- name: "correlated damage",
- description: "
duplication increases
damage",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() > 0.15
- },
- requires: "duplication chance > 15%",
- effect() {
- tech.isDupDamage = true;
- },
- remove() {
- tech.isDupDamage = false;
- }
- },
- {
- name: "parthenogenesis",
- description: "your
duplication has a chance to
duplicate mobs and
bosses",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() > 0 && !tech.isResearchBoss
- },
- requires: "some duplication chance, not abiogenesis",
- effect() {
- tech.isDuplicateBoss = true;
- },
- remove() {
- tech.isDuplicateBoss = false;
- }
- },
- {
- name: "apomixis",
- description: `when you reach
100% duplicationspawn
11 bosses with
100% more
durability`,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isNonRefundable: true,
- allowed() {
- return tech.duplicationChance() > 0.5
- },
- requires: "duplication chance above 50%",
- effect() {
- tech.is100Duplicate = true;
- tech.maxDuplicationEvent()
- },
- remove() {
- tech.is100Duplicate = false;
- }
- },
- {
- name: "Born rule",
- description: "
remove all current
techspawn new
tech to replace them",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return (tech.totalCount > 6)
- },
- requires: "more than 6 tech",
- effect() {
- //remove active bullets //to get rid of bots
- for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
- bullet = [];
- let count = 1 //count tech
- for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
- if (!tech.tech[i].isNonRefundable) count += tech.tech[i].count
- }
- if (tech.isDeterminism) count -= 4 //remove the bonus tech
- if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech
-
- tech.setupAllTech(); // remove all tech
- if (simulation.isCheating) tech.setCheating();
- lore.techCount = 0;
- // tech.addLoreTechToPool();
- for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups
- //have state is checked in m.death()
- },
- remove() {}
- },
-
- {
- name: "Occams razor",
- descriptionFunction() {
- return `randomly remove
half your
techfor each removed
+${this.damagePerRemoved * 100 }% damage (~${(this.count === 0) ? this.damagePerRemoved * 50 * tech.totalCount : this.damage*100}%)`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return (tech.totalCount > 6)
- },
- requires: "more than 6 tech",
- // removePercent: 0.5,
- damagePerRemoved: 0.5,
- damage: null,
- effect() {
- let pool = []
- for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
- if (tech.tech[i].count && !tech.tech[i].isNonRefundable && !tech.tech[i].isFromAppliedScience) pool.push(i)
- }
- pool = shuffle(pool); //shuffles order of maps
- let removeCount = 0
- for (let i = 0, len = pool.length * this.damagePerRemoved; i < len; i++) removeCount += tech.removeTech(pool[i])
- this.damage = 1 + this.damagePerRemoved * removeCount
- tech.damage *= this.damage
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- }
- },
- {
- name: "exchange symmetry",
- description: "remove
1 random
techspawn
2 new
guns",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return (tech.totalCount > 3) && !tech.isSuperDeterminism
- },
- requires: "at least 4 tech, not superdeterminism",
- effect() {
- const have = [] //find which tech you have
+ //reset banish list
for (let i = 0; i < tech.tech.length; i++) {
- if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i)
+ if (tech.tech[i].isBanished) tech.tech[i].isBanished = false
}
- const choose = have[Math.floor(Math.random() * have.length)]
- simulation.makeTextLog(`
tech.removeTech("
${tech.tech[choose].name}")`, 360)
- for (let i = 0; i < tech.tech[choose].count; i++) {
- powerUps.spawn(m.pos.x, m.pos.y, "gun");
- }
- powerUps.spawn(m.pos.x, m.pos.y, "gun");
- // powerUps.spawn(m.pos.x, m.pos.y, "gun");
- tech.tech[choose].count = 0;
- tech.tech[choose].remove(); // remove a random tech form the list of tech you have
- tech.tech[choose].isLost = true
- simulation.updateTechHUD();
- },
- remove() {}
+ powerUps.research.changeRerolls(-this.bonusResearch)
+ }
+ tech.isBanish = false
+ }
+ },
+ {
+ name: "renormalization",
+ description: `
44% chance to spawn ${powerUps.orb.research(1)}
after consuming ${powerUps.orb.research(1)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (powerUps.research.count > 3 || build.isExperimentSelection) && !tech.isSuperDeterminism
},
- {
- name: "Monte Carlo method",
- description: "remove
1 random
techspawn
2 tech",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return (tech.totalCount > 3) && tech.duplicationChance() > 0 && !tech.isSuperDeterminism
- },
- requires: "some duplication, at least 4 tech, not superdeterminism",
- effect() {
- const removeTotal = tech.removeTech()
- for (let i = 0; i < removeTotal + 1; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
- },
- remove() {}
+ requires: "at least 4 research, not superdeterminism",
+ effect() {
+ tech.renormalization = true;
},
- {
- name: "strange attractor",
- descriptionFunction() {
- return `use ${powerUps.orb.research(2)} to spawn
1 tech with
double your
duplication chance
(${(2*tech.duplicationChance()*100).toFixed(0)}%)`
- },
- // description: `use ${powerUps.orb.research(2)} to spawn
1 tech with
doubleyour
duplication chance
(${(2*tech.duplicationChance()*100).toFixed(0)}%)`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return !tech.isSuperDeterminism && tech.duplicationChance() > 0 && powerUps.research.count > 1
- },
- requires: "some duplication, not superdeterminism",
- effect() {
- powerUps.research.changeRerolls(-2)
- simulation.makeTextLog(`
m.
research -= 2`)
- powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
- if (Math.random() < tech.duplicationChance() * 2) powerUps.directSpawn(m.pos.x + 10, m.pos.y + 5, "tech");
- },
- remove() {}
+ remove() {
+ tech.renormalization = false;
+ }
+ },
+ {
+ name: "perturbation theory",
+ description: `if you have no ${powerUps.orb.research(1)} in your inventory
+60% fire rate`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return powerUps.research.count === 0
},
- {
- name: "reinforcement learning",
- description: "increase the
frequency of finding copies of
your current
tech by
1000%",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.totalCount > 9
- },
- requires: "at least 10 tech",
- effect() {
+ requires: "no research",
+ effect() {
+ tech.isRerollHaste = true;
+ tech.researchHaste = 0.4;
+ b.setFireCD();
+ },
+ remove() {
+ tech.isRerollHaste = false;
+ tech.researchHaste = 1;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "ansatz",
+ description: `after choosing a
field,
tech, or
gunif you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(2)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return powerUps.research.count < 1 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality
+ },
+ requires: "no research, not superdeterminism, Ψ(t) collapse, perturbation theory",
+ effect() {
+ tech.isAnsatz = true;
+ },
+ remove() {
+ tech.isAnsatz = false;
+ }
+ },
+ {
+ name: "Bayesian statistics",
+ // description: `for each ${powerUps.orb.research(1)} in your inventory
+3.8% damage`,
+ descriptionFunction() {
+ return `spawn ${powerUps.orb.research(this.bonusResearch)}
+3% damage per ${powerUps.orb.research(1)}
(${(3 * powerUps.research.count).toFixed(0)}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return powerUps.research.count > 2 || build.isExperimentSelection
+ },
+ requires: "at least 3 research",
+ bonusResearch: 3,
+ effect() {
+ powerUps.spawnDelay("research", this.bonusResearch)
+ tech.isRerollDamage = true;
+ },
+ remove() {
+ tech.isRerollDamage = false;
+ if (this.count) {
+ powerUps.research.changeRerolls(-this.bonusResearch)
+ }
+ }
+ },
+ {
+ name: "pseudoscience",
+ description: "
when selecting a power up, research 3 timesfor
free, but add
1-4% JUNK to the
tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isResearchReality && !tech.isSuperDeterminism //tech.isResearchBoss || tech.isMetaAnalysis || tech.isRerollBots || tech.isDeathAvoid || tech.isRerollDamage || build.isExperimentSelection
+ },
+ requires: "not Ψ(t) collapse, superdeterminism", //"abiogenesis, meta-analysis, bot fabrication, anthropic principle, or Bayesian statistics, not Ψ(t) collapse",
+ effect() {
+ tech.isJunkResearch = true;
+ },
+ remove() {
+ tech.isJunkResearch = false;
+ }
+ },
+ {
+ name: "brainstorming",
+ description: "
tech choices
randomizeevery
2 seconds for
10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isBrainstorm = true
+ tech.isBrainstormActive = false
+ tech.brainStormDelay = 2000 - simulation.difficultyMode * 100
+ },
+ remove() {
+ tech.isBrainstorm = false
+ tech.isBrainstormActive = false
+ }
+ },
+ {
+ name: "cross-disciplinary",
+ description: "
tech have an extra
field or
gun choice+5% chance to
duplicate spawned
power ups",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isDeterminism
+ },
+ requires: "not determinism",
+ effect() {
+ tech.isExtraGunField = true;
+ },
+ remove() {
+ tech.isExtraGunField = false;
+ }
+ },
+ {
+ name: "emergence",
+ description: "
tech,
fields, and
guns have
+1 choice+8% damage",
+ // description: "
tech,
fields, and
guns have
+2 choices+3% JUNK to
tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isDeterminism
+ },
+ requires: "not determinism",
+ damage: 1.08,
+ effect() {
+ tech.extraChoices += 1;
+ tech.damage *= this.damage
+ // this.refundAmount += tech.addJunkTechToPool(0.03)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.extraChoices = 0;
+ if (this.count > 0) {
+ tech.damage /= this.damage
+ // if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
+ }
+ }
+ },
+ {
+ name: "path integral",
+ link: `
path integral`,
+ description: "your next
tech choice has all possible
options+5% JUNK to
tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ // isJunk: true,
+ allowed() {
+ return !tech.isDeterminism && !tech.isBrainstorm
+ },
+ requires: "not determinism, brainstorm",
+ effect() {
+ tech.tooManyTechChoices = 1
+ // for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ this.refundAmount += tech.addJunkTechToPool(0.05)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.tooManyTechChoices = 0
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "determinism",
+ description: "spawn
5 techonly
1 choice for
tech,
fields, and
guns",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBadRandomOption: true,
+ isNonRefundable: true,
+ allowed() {
+ return !tech.extraChoices && !tech.isExtraGunField && !tech.isFlipFlopChoices
+ },
+ requires: "not emergence, cross-disciplinary, integrated circuit",
+ effect() {
+ tech.isDeterminism = true;
+ //if you change the number spawned also change it in Born rule
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
+ },
+ remove() {
+ if (!this.count) tech.isDeterminism = false;
+ }
+ },
+ {
+ name: "superdeterminism",
+ description: `spawn
5 techyou can't
cancel and ${powerUps.orb.research(1)} no longer
spawn`,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBadRandomOption: true,
+ isNonRefundable: true,
+ allowed() {
+ return tech.isDeterminism && !tech.isAnsatz && !tech.isJunkResearch && !tech.isBrainstorm
+ },
+ requires: "determinism, not ansatz, pseudoscience, brainstorming",
+ effect() {
+ tech.isSuperDeterminism = true;
+ //if you change the number spawned also change it in Born rule
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
+ },
+ remove() {
+ tech.isSuperDeterminism = false;
+ }
+ },
+ {
+ name: "technical debt",
+ descriptionFunction() {
+ return `
+300% damage –15% damagefor each
tech you have learned
(${(Math.floor(100 * (Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount))) - 100)}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isTechDebt = true;
+ },
+ remove() {
+ tech.isTechDebt = false;
+ }
+ },
+ {
+ name: "abiogenesis",
+ // description: `use ${powerUps.orb.research(4)}(or
49% JUNK to the
tech pool if you can't) to add a 2nd
boss to each level`,
+ description: `
as a level begins spawn a 2nd boss using ${powerUps.orb.research(4)}
(+49% JUNK to the tech pool if you can't pay)`,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (build.isExperimentSelection || powerUps.research.count > 3) && !tech.isDuplicateBoss
+ },
+ requires: "at least 4 research, not parthenogenesis",
+ effect() {
+ tech.isResearchBoss = true;
+ },
+ remove() {
+ tech.isResearchBoss = false;
+ }
+ },
+ {
+ name: "meta-analysis",
+ description: `if you choose a
JUNKtech you instead get a
random normal
tech and spawn ${powerUps.orb.research(2)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.junkCount > 0
+ },
+ requires: "some JUNK tech",
+ effect() {
+ tech.isMetaAnalysis = true
+ },
+ remove() {
+ tech.isMetaAnalysis = false
+ }
+ },
+ {
+ name: "dark patterns",
+ description: "
+15% damage+15% JUNK to
tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.15,
+ effect() {
+ tech.damage *= this.damage
+ this.refundAmount += tech.addJunkTechToPool(0.15)
+ },
+ refundAmount: 0,
+ remove() {
+ if (this.count > 0) {
+ tech.damage /= this.damage
+ if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
+ }
+ }
+ },
+ {
+ name: "exciton",
+ descriptionFunction() {
+ return `
after mobs die they have a 16% chance to
spawn ${powerUps.orb.boost(1)} that give +${(powerUps.boost.damage * 100).toFixed(0)}% damage for ${(powerUps.boost.duration / 60).toFixed(0)} seconds`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isBoostPowerUps = true
+ },
+ remove() {
+ tech.isBoostPowerUps = false
+ }
+ },
+ {
+ name: "band gap",
+ descriptionFunction() {
+ return `${powerUps.orb.boost(1)} give
+77% damagebut their duration is reduced by
1 second`
+ },
+ maxCount: 9,
+ count: 1,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isBoostPowerUps || tech.isBoostReplaceAmmo
+ },
+ requires: "exciton, quasiparticles",
+ effect() {
+ powerUps.boost.duration -= 60
+ powerUps.boost.damage += 0.77
+ },
+ remove() {
+ powerUps.boost.duration = 600
+ powerUps.boost.damage = 1.25
+ }
+ },
+ {
+ name: "eternalism",
+ description: "
+30% damagetime can't be
paused (time can be dilated)",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isPauseSwitchField && !tech.isPauseEjectTech && !tech.isWormHolePause
+ },
+ requires: "not unified field theory, paradigm shift, invariant",
+ damage: 1.3,
+ effect() {
+ tech.damage *= this.damage
+ tech.isNoDraftPause = true
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isNoDraftPause = false
+ }
+ },
+ {
+ name: "paradigm shift",
+ description: `
clicking tech while paused
ejects them
20% chance to remove without
ejecting`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism && !tech.isNoDraftPause
+ },
+ requires: "not superdeterminism, eternalism",
+ effect() {
+ tech.isPauseEjectTech = true;
+ },
+ remove() {
+ tech.isPauseEjectTech = false;
+ }
+ },
+ {
+ name: "unified field theory",
+ description: `
clicking the field box when paused cycles your field
double the frequency of finding fieldtech`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism && !tech.isNoDraftPause
+ },
+ requires: "not superdeterminism, eternalism",
+ effect() {
+ tech.isPauseSwitchField = true;
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isFieldTech) tech.tech[i].frequency *= 2
+ }
+ },
+ remove() {
+ tech.isPauseSwitchField = false;
+ if (this.count > 1) {
for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10
- }
- },
- remove() {
- if (this.count) {
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 10
- }
+ if (tech.tech[i].isFieldTech) tech.tech[i].frequency /= 2
}
}
+ }
+ },
+ {
+ name: "field coupling",
+ descriptionFunction() {
+ return `spawn ${powerUps.orb.coupling(10)}
that each give
+0.1 coupling` //
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}
},
- // {
- // name: "backward induction",
- // descriptionFunction() {
- // if (build.isExperimentSelection || powerUps.tech.choiceLog.length < 10) return `use ${powerUps.orb.research(2)} to
choose all the unchosen
techfrom your last selection`
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ powerUps.spawnDelay("coupling", 10)
+ },
+ remove() {
+ if (this.count) {
+ m.couplingChange(-this.count)
+ }
+ }
+ },
+ {
+ name: "quintessence",
+ descriptionFunction() {
+ let converted = powerUps.research.count * this.couplingToResearch * 10
+ if (this.count) converted = this.researchUsed * this.couplingToResearch * 10
- // text = ``
- // let num = 3
- // if (tech.extraChoices) num = 5
- // if (tech.isDeterminism) num = 1
- // for (let i = 0; i < num; i++) {
- // const index = powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - i - 1]
- // if (index !== powerUps.lastTechIndex && tech.tech[index].count < tech.tech[index].maxCount && tech.tech[index].allowed() && tech.tech[index].name !== "backward induction") {
- // text += `${tech.tech[index].name}, `
- // }
- // }
- // text = text.slice(0, -2);
- // return `use ${powerUps.orb.research(2)}to
choose the unchosen
tech from your previous selection:
${text}`
- // },
- // // description: `use ${powerUps.orb.research(2)}to
choose all the unchosen
tech from your previous
tech selection`,
- // maxCount: 1,
- // count: 0,
- // frequency: 100,
- // frequencyDefault: 100,
- // isNonRefundable: true,
- // isBadRandomOption: true,
- // allowed() {
- // return powerUps.tech.choiceLog.length > 10 && !tech.isDeterminism && powerUps.research.count > 1
- // },
- // requires: "NOT EXPERIMENT MODE, rejected an option in the last tech selection, at least 2 research, not determinism",
- // effect: () => {
- // powerUps.research.changeRerolls(-2)
- // let num = 3
- // if (tech.extraChoices) num = 5
- // if (tech.isDeterminism) num = 1
- // for (let i = 0; i < num; i++) {
- // const index = powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - i - 1]
- // if (index !== powerUps.lastTechIndex && tech.tech[index].count < tech.tech[index].maxCount && tech.tech[index].allowed() && tech.tech[index].name !== "backward induction") {
- // tech.giveTech(index)
- // simulation.makeTextLog(`
tech.giveTech("
${tech.tech[index].name}")
//backward induction`);
- // }
- // }
- // },
- // remove() {}
+ let orbText
+ if (converted > 15) {
+ orbText = `${converted} ${powerUps.orb.coupling()}`
+ } else {
+ orbText = powerUps.orb.coupling(converted)
+ }
+ return `use all your ${powerUps.orb.research(1)} to spawn
${orbText}that each give
+0.1 coupling`//
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return powerUps.research.count > 3
+ },
+ requires: "",
+ researchUsed: 0,
+ couplingToResearch: 0.25,
+ effect() {
+ // let count = 0
+ // while (powerUps.research.count > 0 && powerUps.research.count !== Infinity) {
+ // powerUps.research.changeRerolls(-1)
+ // count += 2.5
+ // this.researchUsed++
+ // }
+ // powerUps.spawnDelay("coupling", Math.floor(count))
+
+ let cycle = () => {
+ if (powerUps.research.count > 0 && powerUps.research.count !== Infinity) {
+ if (m.alive) requestAnimationFrame(cycle);
+ if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
+ powerUps.research.changeRerolls(-1)
+ this.researchUsed++
+ powerUps.spawn(m.pos.x + 50 * (Math.random() - 0.5), m.pos.y + 50 * (Math.random() - 0.5), "coupling");
+ }
+ } else { //exit delay loop
+ }
+ }
+ requestAnimationFrame(cycle);
+ },
+ remove() {
+ if (this.count) {
+ m.couplingChange(-this.researchUsed * this.couplingToResearch)
+ powerUps.research.changeRerolls(this.researchUsed)
+ this.researchUsed = 0
+ }
+ }
+ },
+ {
+ name: "virtual particles",
+ descriptionFunction() {
+ return `after mobs
die they have a
17% chance to
spawn ${powerUps.orb.coupling(1)} that each give
+0.1 coupling` //
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isCouplingPowerUps = true //about 20-30 mobs per level so at 16% and 0.1 coupling that's about 25 * 0.16 * 0.1 = 0.4 coupling per level with out duplication
+ },
+ remove() {
+ tech.isCouplingPowerUps = false
+ }
+ },
+ {
+ name: "fine-structure constant",
+ descriptionFunction() {
+ return `spawn ${this.value} ${powerUps.orb.coupling(1)} that each give
+0.1 coupling-0.5 coupling after mob
collisions`//
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ value: 60,
+ effect() {
+ tech.isCouplingNoHit = true
+ powerUps.spawnDelay("coupling", this.value)
+ },
+ remove() {
+ if (this.count) {
+ m.couplingChange(-this.value)
+ }
+ tech.isCouplingNoHit = false
+ }
+ },
+ {
+ name: "residual dipolar coupling",
+ descriptionFunction() {
+ return `clicking
cancel for a
field,
tech, or
gunspawns ${powerUps.orb.coupling(5)}that each give
+0.1 coupling`//
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isCancelCouple = true
+ },
+ remove() {
+ tech.isCancelCouple = false
+ }
+ },
+ {
+ name: "commodities exchange",
+ descriptionFunction() {
+ return `clicking
cancel for a
field,
tech, or
gunspawns
5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isCancelRerolls = true
+ },
+ remove() {
+ tech.isCancelRerolls = false
+ }
+ },
+ {
+ name: "options exchange",
+ link: `
options exchange`,
+ description: `clicking
cancel for a
field,
tech, or
gunhas a
85% chance to randomize
choices`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism //&& (tech.isCancelRerolls || tech.isCancelDuplication)
+ },
+ requires: "not superdeterminism", //futures exchange, commodities exchange,
+ effect() {
+ tech.isCancelTech = true
+ },
+ remove() {
+ tech.isCancelTech = false
+ }
+ },
+ {
+ name: "futures exchange",
+ description: "clicking
cancel for a
field,
tech, or
gungives
+4.3% power up
duplication chance",
+ // descriptionFunction() {
+ // return `clicking
× to
cancel a
field,
tech, or
gungives
+${4.9 - 0.15*simulation.difficultyMode}% power up
duplication chance`
// },
- //**************************************************
- //************************************************** gun
- //************************************************** tech
- //**************************************************
- {
- name: "needle ice",
- description: `after
needles impact walls
they chip off
1-2 freezing
ice IX crystals`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.isNeedles || tech.isNeedles) && !tech.needleTunnel
- },
- requires: "nail gun, needle gun, not nanowires",
- effect() {
- tech.isNeedleIce = true
- },
- remove() {
- tech.isNeedleIce = false
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1 && !tech.isSuperDeterminism
+ },
+ requires: "below 100% duplication chance, not superdeterminism",
+ effect() {
+ tech.isCancelDuplication = true //search for tech.cancelCount to balance
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ },
+ remove() {
+ tech.isCancelDuplication = false
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "replication",
+ description: "
+10% chance to
duplicate spawned
power ups+33% JUNK to
tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1.
+ },
+ requires: "below 100% duplication chance",
+ effect() {
+ tech.duplicateChance += 0.1
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
+ this.refundAmount += tech.addJunkTechToPool(0.33)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.duplicateChance = 0
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "stimulated emission",
+ description: "
+15% chance to
duplicate spawned
power ups,
but after a
collision eject
1 tech",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1
+ },
+ requires: "below 1% duplication chance",
+ effect() {
+ tech.isStimulatedEmission = true
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.15);
+ },
+ remove() {
+ tech.isStimulatedEmission = false
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "metastability",
+ description: "
+12% chance to
duplicate spawned
power upsduplicates explode with a
3 second
half-life",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1
+ },
+ requires: "below 100% duplication chance",
+ effect() {
+ tech.isPowerUpsVanish = true
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
+ },
+ remove() {
+ tech.isPowerUpsVanish = false
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "correlated damage",
+ description: "
duplication increases
damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() > 0.15
+ },
+ requires: "duplication chance > 15%",
+ effect() {
+ tech.isDupDamage = true;
+ },
+ remove() {
+ tech.isDupDamage = false;
+ }
+ },
+ {
+ name: "parthenogenesis",
+ description: "your
duplication has a chance to
duplicate mobs and
bosses",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() > 0 && !tech.isResearchBoss
+ },
+ requires: "some duplication chance, not abiogenesis",
+ effect() {
+ tech.isDuplicateBoss = true;
+ },
+ remove() {
+ tech.isDuplicateBoss = false;
+ }
+ },
+ {
+ name: "apomixis",
+ description: `when you reach
100% duplicationspawn
11 bosses with
100% more
durability`,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isNonRefundable: true,
+ allowed() {
+ return tech.duplicationChance() > 0.5
+ },
+ requires: "duplication chance above 50%",
+ effect() {
+ tech.is100Duplicate = true;
+ tech.maxDuplicationEvent()
+ },
+ remove() {
+ tech.is100Duplicate = false;
+ }
+ },
+ {
+ name: "Born rule",
+ description: "
remove all current
techspawn new
tech to replace them",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 6)
+ },
+ requires: "more than 6 tech",
+ effect() {
+ //remove active bullets //to get rid of bots
+ for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
+ bullet = [];
+ let count = 1 //count tech
+ for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
+ if (!tech.tech[i].isNonRefundable) count += tech.tech[i].count
+ }
+ if (tech.isDeterminism) count -= 4 //remove the bonus tech
+ if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech
+
+ tech.setupAllTech(); // remove all tech
+ if (simulation.isCheating) tech.setCheating();
+ lore.techCount = 0;
+ // tech.addLoreTechToPool();
+ for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups
+ //have state is checked in m.death()
+ },
+ remove() { }
+ },
+
+ {
+ name: "Occams razor",
+ descriptionFunction() {
+ return `randomly remove
half your
techfor each removed
+${this.damagePerRemoved * 100}% damage (~${(this.count === 0) ? this.damagePerRemoved * 50 * tech.totalCount : this.damage * 100}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 6)
+ },
+ requires: "more than 6 tech",
+ // removePercent: 0.5,
+ damagePerRemoved: 0.5,
+ damage: null,
+ effect() {
+ let pool = []
+ for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
+ if (tech.tech[i].count && !tech.tech[i].isNonRefundable && !tech.tech[i].isFromAppliedScience) pool.push(i)
+ }
+ pool = shuffle(pool); //shuffles order of maps
+ let removeCount = 0
+ for (let i = 0, len = pool.length * this.damagePerRemoved; i < len; i++) removeCount += tech.removeTech(pool[i])
+ this.damage = 1 + this.damagePerRemoved * removeCount
+ tech.damage *= this.damage
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ }
+ },
+ {
+ name: "exchange symmetry",
+ description: "remove
1 random
techspawn
2 new
guns",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 3) && !tech.isSuperDeterminism
+ },
+ requires: "at least 4 tech, not superdeterminism",
+ effect() {
+ const have = [] //find which tech you have
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i)
+ }
+ const choose = have[Math.floor(Math.random() * have.length)]
+ simulation.makeTextLog(`
tech.removeTech("
${tech.tech[choose].name}")`, 360)
+ for (let i = 0; i < tech.tech[choose].count; i++) {
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ }
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ // powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ tech.tech[choose].count = 0;
+ tech.tech[choose].remove(); // remove a random tech form the list of tech you have
+ tech.tech[choose].isLost = true
+ simulation.updateTechHUD();
+ },
+ remove() { }
+ },
+ {
+ name: "Monte Carlo method",
+ description: "remove
1 random
techspawn
2 tech",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 3) && tech.duplicationChance() > 0 && !tech.isSuperDeterminism
+ },
+ requires: "some duplication, at least 4 tech, not superdeterminism",
+ effect() {
+ const removeTotal = tech.removeTech()
+ for (let i = 0; i < removeTotal + 1; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
+ },
+ remove() { }
+ },
+ {
+ name: "strange attractor",
+ descriptionFunction() {
+ return `use ${powerUps.orb.research(2)} to spawn
1 tech with
double your
duplication chance
(${(2 * tech.duplicationChance() * 100).toFixed(0)}%)`
+ },
+ // description: `use ${powerUps.orb.research(2)} to spawn
1 tech with
doubleyour
duplication chance
(${(2*tech.duplicationChance()*100).toFixed(0)}%)`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return !tech.isSuperDeterminism && tech.duplicationChance() > 0 && powerUps.research.count > 1
+ },
+ requires: "some duplication, not superdeterminism",
+ effect() {
+ powerUps.research.changeRerolls(-2)
+ simulation.makeTextLog(`
m.
research -= 2`)
+ powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ if (Math.random() < tech.duplicationChance() * 2) powerUps.directSpawn(m.pos.x + 10, m.pos.y + 5, "tech");
+ },
+ remove() { }
+ },
+ {
+ name: "reinforcement learning",
+ description: "increase the
frequency of finding copies of
your current
tech by
1000%",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.totalCount > 9
+ },
+ requires: "at least 10 tech",
+ effect() {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10
}
},
- {
- name: "nanowires",
- description: `
needles tunnel through
blocks and
map+20% needle
damage`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return ((tech.haveGunCheck("nail gun") && tech.isNeedles) || (tech.isNeedles && tech.haveGunCheck("shotgun"))) && !tech.isNeedleIce
- },
- requires: "nail gun, needle gun, not needle ice",
- effect() {
- tech.needleTunnel = true
- },
- remove() {
- tech.needleTunnel = false
+ remove() {
+ if (this.count) {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 10
+ }
+ }
+ }
+ },
+ // {
+ // name: "backward induction",
+ // descriptionFunction() {
+ // if (build.isExperimentSelection || powerUps.tech.choiceLog.length < 10) return `use ${powerUps.orb.research(2)} to
choose all the unchosen
techfrom your last selection`
+
+ // text = ``
+ // let num = 3
+ // if (tech.extraChoices) num = 5
+ // if (tech.isDeterminism) num = 1
+ // for (let i = 0; i < num; i++) {
+ // const index = powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - i - 1]
+ // if (index !== powerUps.lastTechIndex && tech.tech[index].count < tech.tech[index].maxCount && tech.tech[index].allowed() && tech.tech[index].name !== "backward induction") {
+ // text += `${tech.tech[index].name}, `
+ // }
+ // }
+ // text = text.slice(0, -2);
+ // return `use ${powerUps.orb.research(2)}to
choose the unchosen
tech from your previous selection:
${text}`
+ // },
+ // // description: `use ${powerUps.orb.research(2)}to
choose all the unchosen
tech from your previous
tech selection`,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 100,
+ // frequencyDefault: 100,
+ // isNonRefundable: true,
+ // isBadRandomOption: true,
+ // allowed() {
+ // return powerUps.tech.choiceLog.length > 10 && !tech.isDeterminism && powerUps.research.count > 1
+ // },
+ // requires: "NOT EXPERIMENT MODE, rejected an option in the last tech selection, at least 2 research, not determinism",
+ // effect: () => {
+ // powerUps.research.changeRerolls(-2)
+ // let num = 3
+ // if (tech.extraChoices) num = 5
+ // if (tech.isDeterminism) num = 1
+ // for (let i = 0; i < num; i++) {
+ // const index = powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - i - 1]
+ // if (index !== powerUps.lastTechIndex && tech.tech[index].count < tech.tech[index].maxCount && tech.tech[index].allowed() && tech.tech[index].name !== "backward induction") {
+ // tech.giveTech(index)
+ // simulation.makeTextLog(`
tech.giveTech("
${tech.tech[index].name}")
//backward induction`);
+ // }
+ // }
+ // },
+ // remove() {}
+ // },
+ //**************************************************
+ //************************************************** gun
+ //************************************************** tech
+ //**************************************************
+ {
+ name: "needle ice",
+ description: `after
needles impact walls
they chip off
1-2 freezing
ice IX crystals`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isNeedles || tech.isNeedles) && !tech.needleTunnel
+ },
+ requires: "nail gun, needle gun, not nanowires",
+ effect() {
+ tech.isNeedleIce = true
+ },
+ remove() {
+ tech.isNeedleIce = false
+ }
+ },
+ {
+ name: "nanowires",
+ description: `
needles tunnel through
blocks and
map+20% needle
damage`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("nail gun") && tech.isNeedles) || (tech.isNeedles && tech.haveGunCheck("shotgun"))) && !tech.isNeedleIce
+ },
+ requires: "nail gun, needle gun, not needle ice",
+ effect() {
+ tech.needleTunnel = true
+ },
+ remove() {
+ tech.needleTunnel = false
+ }
+ },
+ {
+ name: "ceramics",
+ description: `
needles and
harpoons pierce
shieldsdirectly
damaging shielded mobs`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (!tech.isLargeHarpoon && tech.haveGunCheck("harpoon")) || tech.isNeedles
+ },
+ requires: "needle gun, harpoon, not Bessemer process",
+ effect() {
+ tech.isShieldPierce = true
+ },
+ remove() {
+ tech.isShieldPierce = false
+ }
+ },
+ {
+ name: "needle gun",
+ description: "
nail gun and
shotgun fire mob piercing
needles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil && !tech.isRicochet) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals && !tech.isIceShot
+ },
+ requires: "nail gun, shotgun, not ice crystal, rivets, rotary cannon, pneumatic, incendiary, nail-shot, foam-shot, worm-shot, ice-shot",
+ effect() {
+ tech.isNeedles = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") {
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 3);
+ b.guns[i].ammoPack = Math.ceil(b.guns[i].defaultAmmoPack / 3);
+ b.guns[i].chooseFireMethod()
+ simulation.updateGunHUD();
+ break
+ }
}
},
- {
- name: "ceramics",
- description: `
needles and
harpoons pierce
shieldsdirectly
damaging shielded mobs`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (!tech.isLargeHarpoon && tech.haveGunCheck("harpoon")) || tech.isNeedles
- },
- requires: "needle gun, harpoon, not Bessemer process",
- effect() {
- tech.isShieldPierce = true
- },
- remove() {
- tech.isShieldPierce = false
- }
- },
- {
- name: "needle gun",
- description: "
nail gun and
shotgun fire mob piercing
needles",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil && !tech.isRicochet) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals && !tech.isIceShot
- },
- requires: "nail gun, shotgun, not ice crystal, rivets, rotary cannon, pneumatic, incendiary, nail-shot, foam-shot, worm-shot, ice-shot",
- effect() {
- tech.isNeedles = true
+ remove() {
+ if (tech.isNeedles) {
+ tech.isNeedles = false
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") {
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 3);
- b.guns[i].ammoPack = Math.ceil(b.guns[i].defaultAmmoPack / 3);
b.guns[i].chooseFireMethod()
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 3);
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
simulation.updateGunHUD();
break
}
}
- },
- remove() {
- if (tech.isNeedles) {
- tech.isNeedles = false
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "nail gun") {
- b.guns[i].chooseFireMethod()
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 3);
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
- simulation.updateGunHUD();
- break
- }
- }
+ }
+ }
+ },
+ {
+ name: "stress concentration",
+ description: "mobs below
50% durability
die after you shoot
them near their
center with
needles or
rivets",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isNeedles || tech.isRivets) && !tech.isNailCrit && !tech.isIncendiary
+ },
+ requires: "needles, rivets, not incendiary, supercritical fission",
+ effect() {
+ tech.isCritKill = true
+ },
+ remove() {
+ tech.isCritKill = false
+ }
+ },
+ {
+ name: "rivet gun",
+ description: "
nail gun and
shotgun slowly lob a heavy
rivet",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isRicochet) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea)) && !tech.isNeedles && !tech.isIceCrystals && !tech.isIceShot
+ },
+ requires: "nail gun, shotgun, not ice crystal, needles, or pneumatic actuator",
+ effect() {
+ tech.isRivets = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") {
+ b.guns[i].chooseFireMethod()
+ break
}
}
},
- {
- name: "stress concentration",
- description: "mobs below
50% durability
die after you shoot
them near their
center with
needles or
rivets",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.isNeedles || tech.isRivets) && !tech.isNailCrit && !tech.isIncendiary
- },
- requires: "needles, rivets, not incendiary, supercritical fission",
- effect() {
- tech.isCritKill = true
- },
- remove() {
- tech.isCritKill = false
- }
- },
- {
- name: "rivet gun",
- description: "
nail gun and
shotgun slowly lob a heavy
rivet",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isRicochet) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea)) && !tech.isNeedles && !tech.isIceCrystals && !tech.isIceShot
- },
- requires: "nail gun, shotgun, not ice crystal, needles, or pneumatic actuator",
- effect() {
- tech.isRivets = true
+ remove() {
+ if (tech.isRivets) {
+ tech.isRivets = false
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") {
b.guns[i].chooseFireMethod()
break
}
}
- },
- remove() {
- if (tech.isRivets) {
- tech.isRivets = false
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "nail gun") {
- b.guns[i].chooseFireMethod()
- break
- }
- }
- }
- tech.isRivets = false
+ }
+ tech.isRivets = false
+ }
+ },
+ {
+ name: "pneumatic actuator",
+ description: "
nail gun takes
no time to ramp up
to its fastest
fire rate",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles && !tech.nailRecoil
+ },
+ requires: "nail gun, not rotary cannon, rivets, or needles",
+ effect() {
+ tech.nailInstantFireRate = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
}
},
- {
- name: "pneumatic actuator",
- description: "
nail gun takes
no time to ramp up
to its fastest
fire rate",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles && !tech.nailRecoil
- },
- requires: "nail gun, not rotary cannon, rivets, or needles",
- effect() {
- tech.nailInstantFireRate = true
+ remove() {
+ if (tech.nailInstantFireRate) {
+ tech.nailInstantFireRate = false
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
}
- },
- remove() {
- if (tech.nailInstantFireRate) {
- tech.nailInstantFireRate = false
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
- }
- }
}
+ }
+ },
+ {
+ name: "ice crystal nucleation",
+ link: `
ice crystal nucleation`,
+ description: "
nail gun uses
energy to condense
unlimited
freezing ice shards",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles // && !tech.isNailRadiation && !tech.isNailCrit
},
- {
- name: "ice crystal nucleation",
- link: `
ice crystal nucleation`,
- description: "
nail gun uses
energy to condense
unlimited
freezing ice shards",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles // && !tech.isNailRadiation && !tech.isNailCrit
- },
- requires: "nail gun, not rivets, needles",
- effect() {
- tech.isIceCrystals = true;
- b.guns[0].ammoPack = Infinity
- b.guns[0].recordedAmmo = b.guns[i].ammo
- b.guns[0].ammo = Infinity
- simulation.updateGunHUD();
- },
- remove() {
- if (tech.isIceCrystals) {
- tech.isIceCrystals = false;
- b.guns[0].ammoPack = b.guns[0].defaultAmmoPack;
- if (b.guns[0].recordedAmmo) b.guns[0].ammo = b.guns[0].recordedAmmo
- simulation.updateGunHUD();
- }
+ requires: "nail gun, not rivets, needles",
+ effect() {
+ tech.isIceCrystals = true;
+ b.guns[0].ammoPack = Infinity
+ b.guns[0].recordedAmmo = b.guns[i].ammo
+ b.guns[0].ammo = Infinity
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isIceCrystals) {
tech.isIceCrystals = false;
- if (b.guns[0].ammo === Infinity) b.guns[0].ammo = 0
+ b.guns[0].ammoPack = b.guns[0].defaultAmmoPack;
+ if (b.guns[0].recordedAmmo) b.guns[0].ammo = b.guns[0].recordedAmmo
+ simulation.updateGunHUD();
+ }
+ tech.isIceCrystals = false;
+ if (b.guns[0].ammo === Infinity) b.guns[0].ammo = 0
+ }
+ },
+ {
+ name: "rotary cannon",
+ description: "
nail gun has increased muzzle
speed,
maximum
fire rate,
accuracy, and
recoil",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isNeedles
+ },
+ requires: "nail gun, not pneumatic actuator, needle gun",
+ effect() {
+ tech.nailRecoil = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
}
},
- {
- name: "rotary cannon",
- description: "
nail gun has increased muzzle
speed,
maximum
fire rate,
accuracy, and
recoil",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isNeedles
- },
- requires: "nail gun, not pneumatic actuator, needle gun",
- effect() {
- tech.nailRecoil = true
+ remove() {
+ if (tech.nailRecoil) {
+ tech.nailRecoil = false
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
}
- },
- remove() {
- if (tech.nailRecoil) {
- tech.nailRecoil = false
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
- }
+ }
+ }
+ },
+ {
+ name: "gauge",
+ description: `
rivets,
needles,
super balls, and
nailshave
+30% mass and physical
damage`,
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
+ },
+ requires: "nails, nail gun, rivets, shotgun, super balls, mine",
+ effect() {
+ tech.bulletSize = 1 + 0.25 * Math.pow(this.count + 1, 0.5)
+ },
+ remove() {
+ tech.bulletSize = 1;
+ }
+ },
+ {
+ name: "supercritical fission",
+ description: "if
nails,
needles, or
rivets strike mobs
near their
center they can
explode",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isNailShot || tech.isNeedles || tech.isNailBotUpgrade || tech.haveGunCheck("nail gun") || tech.isRivets || (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine))) && !tech.isIncendiary && !tech.isCritKill
+ },
+ requires: "nail gun, mine, needles, nails, rivets, not incendiary, stress concentration",
+ effect() {
+ tech.isNailCrit = true
+ },
+ remove() {
+ tech.isNailCrit = false
+ }
+ },
+ {
+ name: "irradiated nails",
+ link: `
irradiated nails`,
+ description: "
nails,
needles, and
rivets are
radioactive+90% radioactive damage over
3 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot))
+ },
+ requires: "nail gun, nails, rivets, mine, not ceramic needles",
+ effect() {
+ tech.isNailRadiation = true;
+ },
+ remove() {
+ tech.isNailRadiation = false;
+ }
+ },
+ {
+ name: "6s half-life",
+ link: `
6s half-life`,
+ description: "
nails, needles, rivets are made of plutonium-238radioactive damage lasts
+3 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation && !tech.isFastRadiation
+ },
+ requires: "nail gun, mine, irradiated nails, not 1s half-life",
+ effect() {
+ tech.isSlowRadiation = true;
+ },
+ remove() {
+ tech.isSlowRadiation = false;
+ }
+ },
+ {
+ name: "1s half-life",
+ link: `
1s half-life`,
+ description: "
nails, needles, rivets are made of lithium-8
+300% radioactive damage for 1 second",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation && !tech.isSlowRadiation
+ },
+ requires: "nail gun, mine, irradiated nails, not 6s half-life",
+ effect() {
+ tech.isFastRadiation = true;
+ },
+ remove() {
+ tech.isFastRadiation = false;
+ }
+ },
+ {
+ name: "spin-statistics",
+ link: `
spin-statistics`,
+ description: "after firing the
shotgun you are
invulnerableshotgun has
50% fewer shots",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun")
+ },
+ requires: "shotgun",
+ effect() {
+ tech.isShotgunImmune = true;
+
+ //cut current ammo by 1/2
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "shotgun") {
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.5);
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.5
+ break;
}
}
+ simulation.updateGunHUD();
},
- {
- name: "gauge",
- description: `
rivets,
needles,
super balls, and
nailshave
+30% mass and physical
damage`,
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
- },
- requires: "nails, nail gun, rivets, shotgun, super balls, mine",
- effect() {
- tech.bulletSize = 1 + 0.25 * Math.pow(this.count + 1, 0.5)
- },
- remove() {
- tech.bulletSize = 1;
- }
- },
- {
- name: "supercritical fission",
- description: "if
nails,
needles, or
rivets strike mobs
near their
center they can
explode",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.isNailShot || tech.isNeedles || tech.isNailBotUpgrade || tech.haveGunCheck("nail gun") || tech.isRivets || (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine))) && !tech.isIncendiary && !tech.isCritKill
- },
- requires: "nail gun, mine, needles, nails, rivets, not incendiary, stress concentration",
- effect() {
- tech.isNailCrit = true
- },
- remove() {
- tech.isNailCrit = false
- }
- },
- {
- name: "irradiated nails",
- link: `
irradiated nails`,
- description: "
nails,
needles, and
rivets are
radioactive+90% radioactive damage over
3 seconds",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot))
- },
- requires: "nail gun, nails, rivets, mine, not ceramic needles",
- effect() {
- tech.isNailRadiation = true;
- },
- remove() {
- tech.isNailRadiation = false;
- }
- },
- {
- name: "6s half-life",
- link: `
6s half-life`,
- description: "
nails, needles, rivets are made of plutonium-238radioactive damage lasts
+3 seconds",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNailRadiation && !tech.isFastRadiation
- },
- requires: "nail gun, mine, irradiated nails, not 1s half-life",
- effect() {
- tech.isSlowRadiation = true;
- },
- remove() {
- tech.isSlowRadiation = false;
- }
- },
- {
- name: "1s half-life",
- link: `
1s half-life`,
- description: "
nails, needles, rivets are made of lithium-8
+300% radioactive damage for 1 second",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNailRadiation && !tech.isSlowRadiation
- },
- requires: "nail gun, mine, irradiated nails, not 6s half-life",
- effect() {
- tech.isFastRadiation = true;
- },
- remove() {
- tech.isFastRadiation = false;
- }
- },
- {
- name: "spin-statistics",
- link: `
spin-statistics`,
- description: "after firing the
shotgun you are
invulnerableshotgun has
50% fewer shots",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("shotgun")
- },
- requires: "shotgun",
- effect() {
- tech.isShotgunImmune = true;
-
- //cut current ammo by 1/2
+ remove() {
+ if (tech.isShotgunImmune) {
+ tech.isShotgunImmune = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "shotgun") {
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.5);
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.5
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 2);
break;
}
}
simulation.updateGunHUD();
- },
- remove() {
- if (tech.isShotgunImmune) {
- tech.isShotgunImmune = false;
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "shotgun") {
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 2);
- break;
- }
- }
- simulation.updateGunHUD();
- }
+ }
+ }
+ },
+ {
+ name: "Newtons 3rd law",
+ description: "
+66% shotgun fire rate and
recoil",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isShotgunReversed
+ },
+ requires: "shotgun, not Noether violation",
+ effect() {
+ tech.isShotgunRecoil = true;
+ },
+ remove() {
+ tech.isShotgunRecoil = false;
+ }
+ },
+ {
+ name: "Noether violation",
+ link: `
Noether violation`,
+ description: "
+50% shotgun damageshotgun recoil is
reversed",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("shotgun")) && !tech.isShotgunRecoil
+ },
+ requires: "shotgun, not Newtons 3rd law",
+ effect() {
+ tech.isShotgunReversed = true;
+ },
+ remove() {
+ tech.isShotgunReversed = false;
+ }
+ },
+ {
+ name: "repeater",
+ description: "
shotgun immediately fires again for no
ammo-50% shotgun fire rate",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("shotgun"))
+ },
+ requires: "shotgun, not Newtons 3rd law",
+ effect() {
+ tech.shotgunExtraShots++;
+ },
+ remove() {
+ tech.shotgunExtraShots = 0
+ }
+ },
+ {
+ name: "nail-shot",
+ link: `
nail-shot`,
+ description: "
shotgun drives a long clip of
nails",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
+ },
+ requires: "shotgun, not incendiary, rivets, foam-shot, worm-shot, ice-shot, needles",
+ effect() {
+ tech.isNailShot = true;
+ },
+ remove() {
+ tech.isNailShot = false;
+ }
+ },
+ {
+ name: "foam-shot",
+ link: `
foam-shot`,
+ description: "
shotgun sprays sticky
foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
+ },
+ requires: "shotgun, not incendiary, nail-shot, rivet, worm-shot, ice-shot, needle",
+ effect() {
+ tech.isFoamShot = true;
+ },
+ remove() {
+ tech.isFoamShot = false;
+ }
+ },
+ {
+ name: "ice-shot",
+ link: `
ice-shot`,
+ description: "
shotgun grows freezing
ice IX crystals",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
+ },
+ requires: "shotgun, not incendiary, nail-shot, rivet, foam-shot, worm-shot",
+ effect() {
+ tech.isIceShot = true;
+ },
+ remove() {
+ tech.isIceShot = false;
+ }
+ },
+ {
+ name: "freezer burn",
+ description: "mobs
frozen while below
33% durability
die",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3)
+ },
+ requires: "a freeze effect",
+ effect() {
+ tech.isIceKill = true
+ },
+ remove() {
+ tech.isIceKill = false
+ }
+ },
+ {
+ name: "flash freeze",
+ description: "mobs
frozen while above
66% durability
have their durability reduced to
66%",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3)
+ },
+ requires: "a freeze effect",
+ effect() {
+ tech.isIceMaxHealthLoss = true
+ },
+ remove() {
+ tech.isIceMaxHealthLoss = false
+ }
+ },
+ {
+ name: "crystallizer",
+ description: "after
frozen mobs
die they
shatter into
ice IX crystals",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3)) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob
+ },
+ requires: "a localized freeze effect, no other mob death tech",
+ effect() {
+ tech.iceIXOnDeath++
+ },
+ remove() {
+ tech.iceIXOnDeath = 0
+ }
+ },
+ {
+ name: "thermoelectric effect",
+ description: "after
killing mobs with
ice IX+100 energy",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3) || tech.iceIXOnDeath || tech.isIceShot
+ },
+ requires: "ice IX",
+ effect() {
+ tech.iceEnergy++
+ },
+ remove() {
+ tech.iceEnergy = 0;
+ }
+ },
+ {
+ name: "superfluidity",
+ description: "
freeze effects are applied
to a small area around the target",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3) || tech.iceIXOnDeath || tech.isIceShot
+ },
+ requires: "a localized freeze effect",
+ effect() {
+ tech.isAoESlow = true
+ },
+ remove() {
+ tech.isAoESlow = false
+ }
+ },
+ {
+ name: "incendiary ammunition",
+ description: "
shotgun,
rivets,
super balls, and
dronesare loaded with
explosives",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIceShot && !tech.isRivets && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles) || ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce && !tech.isFoamBall && !tech.isSuperHarm) || (tech.isRivets && !tech.isNailCrit) || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3) || (tech.haveGunCheck("drones") && !tech.isForeverDrones && !tech.isDroneRadioactive && !tech.isDroneTeleport)
+ },
+ requires: "shotgun, super balls, rivets, drones, not irradiated drones, burst drones, polyurethane, Zectron",
+ effect() {
+ tech.isIncendiary = true
+ },
+ remove() {
+ tech.isIncendiary = false;
+ }
+ },
+ {
+ name: "rebound",
+ description: `after they collide with a mob,
super ballsgain
speed,
duration, and
+33% damage`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isIncendiary && !tech.isFoamBall
+ },
+ requires: "super balls, not incendiary",
+ effect() {
+ tech.isSuperBounce = true
+ },
+ remove() {
+ tech.isSuperBounce = false
+ }
+ },
+ {
+ name: "Zectron",
+ description: `
+75% super ball density and
damage, but
after colliding with
super balls -25% energy`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isIncendiary
+ },
+ requires: "super balls not incendiary ammunition",
+ effect() {
+ tech.isSuperHarm = true
+ },
+ remove() {
+ tech.isSuperHarm = false
+ }
+ },
+ {
+ name: "polyurethane foam",
+ description: "
super balls and
harpoons colliding with
mobscatalyzes a reaction that yields
foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce) || (tech.haveGunCheck("harpoon") && !tech.fragments)
+ },
+ requires: "super balls, harpoon, not fragmentation",
+ effect() {
+ tech.isFoamBall = true;
+ },
+ remove() {
+ tech.isFoamBall = false;
+ }
+ },
+ {
+ name: "autocannon",
+ description: "fire
+1 extra
super ballballs are quickly released in same direction",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("super balls") && !tech.oneSuperBall
+ },
+ requires: "super balls, but not the tech super ball",
+ effect() {
+ tech.superBallDelay = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
}
},
- {
- name: "Newtons 3rd law",
- description: "
+66% shotgun fire rate and
recoil",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("shotgun") && !tech.isShotgunReversed
- },
- requires: "shotgun, not Noether violation",
- effect() {
- tech.isShotgunRecoil = true;
- },
- remove() {
- tech.isShotgunRecoil = false;
- }
- },
- {
- name: "Noether violation",
- link: `
Noether violation`,
- description: "
+50% shotgun damageshotgun recoil is
reversed",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (tech.haveGunCheck("shotgun")) && !tech.isShotgunRecoil
- },
- requires: "shotgun, not Newtons 3rd law",
- effect() {
- tech.isShotgunReversed = true;
- },
- remove() {
- tech.isShotgunReversed = false;
- }
- },
- {
- name: "repeater",
- description: "
shotgun immediately fires again for no
ammo-50% shotgun fire rate",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("shotgun"))
- },
- requires: "shotgun, not Newtons 3rd law",
- effect() {
- tech.shotgunExtraShots++;
- },
- remove() {
- tech.shotgunExtraShots = 0
- }
- },
- {
- name: "nail-shot",
- link: `
nail-shot`,
- description: "
shotgun drives a long clip of
nails",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
- },
- requires: "shotgun, not incendiary, rivets, foam-shot, worm-shot, ice-shot, needles",
- effect() {
- tech.isNailShot = true;
- },
- remove() {
- tech.isNailShot = false;
- }
- },
- {
- name: "foam-shot",
- link: `
foam-shot`,
- description: "
shotgun sprays sticky
foam bubbles",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
- },
- requires: "shotgun, not incendiary, nail-shot, rivet, worm-shot, ice-shot, needle",
- effect() {
- tech.isFoamShot = true;
- },
- remove() {
- tech.isFoamShot = false;
- }
- },
- {
- name: "ice-shot",
- link: `
ice-shot`,
- description: "
shotgun grows freezing
ice IX crystals",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
- },
- requires: "shotgun, not incendiary, nail-shot, rivet, foam-shot, worm-shot",
- effect() {
- tech.isIceShot = true;
- },
- remove() {
- tech.isIceShot = false;
- }
- },
- {
- name: "freezer burn",
- description: "mobs
frozen while below
33% durability
die",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3)
- },
- requires: "a freeze effect",
- effect() {
- tech.isIceKill = true
- },
- remove() {
- tech.isIceKill = false
- }
- },
- {
- name: "flash freeze",
- description: "mobs
frozen while above
66% durability
have their durability reduced to
66%",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3)
- },
- requires: "a freeze effect",
- effect() {
- tech.isIceMaxHealthLoss = true
- },
- remove() {
- tech.isIceMaxHealthLoss = false
- }
- },
- {
- name: "crystallizer",
- description: "after
frozen mobs
die they
shatter into
ice IX crystals",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3)) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob
- },
- requires: "a localized freeze effect, no other mob death tech",
- effect() {
- tech.iceIXOnDeath++
- },
- remove() {
- tech.iceIXOnDeath = 0
- }
- },
- {
- name: "thermoelectric effect",
- description: "after
killing mobs with
ice IX+100 energy",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3) || tech.iceIXOnDeath || tech.isIceShot
- },
- requires: "ice IX",
- effect() {
- tech.iceEnergy++
- },
- remove() {
- tech.iceEnergy = 0;
- }
- },
- {
- name: "superfluidity",
- description: "
freeze effects are applied
to a small area around the target",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 2) || tech.relayIce || tech.isNeedleIce || (m.coupling && m.fieldMode < 3) || tech.iceIXOnDeath || tech.isIceShot
- },
- requires: "a localized freeze effect",
- effect() {
- tech.isAoESlow = true
- },
- remove() {
- tech.isAoESlow = false
- }
- },
- {
- name: "incendiary ammunition",
- description: "
shotgun,
rivets,
super balls, and
dronesare loaded with
explosives",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIceShot && !tech.isRivets && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles) || ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce && !tech.isFoamBall && !tech.isSuperHarm) || (tech.isRivets && !tech.isNailCrit) || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3) || (tech.haveGunCheck("drones") && !tech.isForeverDrones && !tech.isDroneRadioactive && !tech.isDroneTeleport)
- },
- requires: "shotgun, super balls, rivets, drones, not irradiated drones, burst drones, polyurethane, Zectron",
- effect() {
- tech.isIncendiary = true
- },
- remove() {
- tech.isIncendiary = false;
- }
- },
- {
- name: "rebound",
- description: `after they collide with a mob,
super ballsgain
speed,
duration, and
+33% damage`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isIncendiary && !tech.isFoamBall
- },
- requires: "super balls, not incendiary",
- effect() {
- tech.isSuperBounce = true
- },
- remove() {
- tech.isSuperBounce = false
- }
- },
- {
- name: "Zectron",
- description: `
+75% super ball density and
damage, but
after colliding with
super balls -25% energy`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isIncendiary
- },
- requires: "super balls not incendiary ammunition",
- effect() {
- tech.isSuperHarm = true
- },
- remove() {
- tech.isSuperHarm = false
- }
- },
- {
- name: "polyurethane foam",
- description: "
super balls and
harpoons colliding with
mobscatalyzes a reaction that yields
foam bubbles",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce) || (tech.haveGunCheck("harpoon") && !tech.fragments)
- },
- requires: "super balls, harpoon, not fragmentation",
- effect() {
- tech.isFoamBall = true;
- },
- remove() {
- tech.isFoamBall = false;
- }
- },
- {
- name: "autocannon",
- description: "fire
+1 extra
super ballballs are quickly released in same direction",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("super balls") && !tech.oneSuperBall
- },
- requires: "super balls, but not the tech super ball",
- effect() {
- tech.superBallDelay = true
+ remove() {
+ if (tech.superBallDelay) {
+ tech.superBallDelay = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
}
- },
- remove() {
- if (tech.superBallDelay) {
- tech.superBallDelay = false;
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
- }
- }
+ }
+ }
+ },
+ {
+ name: "super duper",
+ description: `randomly fire
+0,
+1,
+2, or
+3 extra
super balls`,
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.oneSuperBall
+ },
+ requires: "super balls, not super ball",
+ effect() {
+ tech.extraSuperBalls += 4
+ },
+ remove() {
+ tech.extraSuperBalls = 0;
+ }
+ },
+ {
+ name: "super ball",
+ description: "fire just
1 large super
ballthat
stuns mobs for
2 second",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.extraSuperBalls && !tech.superBallDelay
+ },
+ requires: "super balls, not super duper or autocannon",
+ effect() {
+ tech.oneSuperBall = true;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
}
},
- {
- name: "super duper",
- description: `randomly fire
+0,
+1,
+2, or
+3 extra
super balls`,
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.oneSuperBall
- },
- requires: "super balls, not super ball",
- effect() {
- tech.extraSuperBalls += 4
- },
- remove() {
- tech.extraSuperBalls = 0;
- }
- },
- {
- name: "super ball",
- description: "fire just
1 large super
ballthat
stuns mobs for
2 second",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.extraSuperBalls && !tech.superBallDelay
- },
- requires: "super balls, not super duper or autocannon",
- effect() {
- tech.oneSuperBall = true;
+ remove() {
+ if (tech.oneSuperBall) {
+ tech.oneSuperBall = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
}
- },
- remove() {
- if (tech.oneSuperBall) {
- tech.oneSuperBall = false;
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
- }
- }
}
+ }
+ },
+ {
+ name: "phase velocity",
+ description: "wave particles
propagate faster as
solids+40% wave
damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave") && !tech.isLongitudinal
},
- {
- name: "phase velocity",
- description: "wave particles
propagate faster as
solids+40% wave
damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("wave") && !tech.isLongitudinal
- },
- requires: "wave, not phonon",
- effect() {
- tech.isPhaseVelocity = true;
- },
- remove() {
- tech.isPhaseVelocity = false;
- }
+ requires: "wave, not phonon",
+ effect() {
+ tech.isPhaseVelocity = true;
},
- {
- name: "amplitude",
- description: "
+37% wave
damage+37% wave particle
amplitude",
- isGunTech: true,
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("wave")
- },
- requires: "wave",
- effect() {
- tech.waveFrequency *= 0.66
- tech.wavePacketDamage *= 1.37
- },
- remove() {
- tech.waveFrequency = 0.2
- tech.wavePacketDamage = 1
- }
+ remove() {
+ tech.isPhaseVelocity = false;
+ }
+ },
+ {
+ name: "amplitude",
+ description: "
+37% wave
damage+37% wave particle
amplitude",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave")
},
- {
- name: "propagation",
- description: "
–25% wave packet propagation
speed+41% wave
damage",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("wave")
- },
- requires: "wave",
- effect() {
- tech.waveBeamSpeed *= 0.75;
- tech.waveBeamDamage += 0.27 * 0.41 //this sets base wave damage
- },
- remove() {
- tech.waveBeamSpeed = 11;
- tech.waveBeamDamage = 0.27 //this sets base wave damage
- }
+ requires: "wave",
+ effect() {
+ tech.waveFrequency *= 0.66
+ tech.wavePacketDamage *= 1.37
},
- {
- name: "bound state",
- description: "wave packets
reflect backwards
2 times
–33% range",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("wave")
- },
- requires: "wave",
- effect() {
- tech.waveReflections += 2
- },
- remove() {
- tech.waveReflections = 1
- }
+ remove() {
+ tech.waveFrequency = 0.2
+ tech.wavePacketDamage = 1
+ }
+ },
+ {
+ name: "propagation",
+ description: "
–25% wave packet propagation
speed+41% wave
damage",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave")
},
- {
- name: "frequency",
- description: `
wave has unlimited
ammo-25% wave
damage`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed: () => tech.haveGunCheck("wave"),
- requires: "wave",
- effect() {
- tech.isInfiniteWaveAmmo = true
- b.guns[3].savedAmmo = b.guns[3].ammo
- b.guns[3].ammo = Infinity
+ requires: "wave",
+ effect() {
+ tech.waveBeamSpeed *= 0.75;
+ tech.waveBeamDamage += 0.27 * 0.41 //this sets base wave damage
+ },
+ remove() {
+ tech.waveBeamSpeed = 11;
+ tech.waveBeamDamage = 0.27 //this sets base wave damage
+ }
+ },
+ {
+ name: "bound state",
+ description: "wave packets
reflect backwards
2 times
–33% range",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave")
+ },
+ requires: "wave",
+ effect() {
+ tech.waveReflections += 2
+ },
+ remove() {
+ tech.waveReflections = 1
+ }
+ },
+ {
+ name: "frequency",
+ description: `
wave has unlimited
ammo-25% wave
damage`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => tech.haveGunCheck("wave"),
+ requires: "wave",
+ effect() {
+ tech.isInfiniteWaveAmmo = true
+ b.guns[3].savedAmmo = b.guns[3].ammo
+ b.guns[3].ammo = Infinity
+ simulation.updateGunHUD();
+ },
+ remove() {
+ tech.isInfiniteWaveAmmo = false
+ if (this.count > 0 && b.guns[3].savedAmmo !== undefined) {
+ b.guns[3].ammo = b.guns[3].savedAmmo
simulation.updateGunHUD();
- },
- remove() {
- tech.isInfiniteWaveAmmo = false
- if (this.count > 0 && b.guns[3].savedAmmo !== undefined) {
- b.guns[3].ammo = b.guns[3].savedAmmo
- simulation.updateGunHUD();
- } else if (b.guns[3].ammo === Infinity) {
- b.guns[3].ammo = 0
- }
+ } else if (b.guns[3].ammo === Infinity) {
+ b.guns[3].ammo = 0
}
+ }
+ },
+ {
+ name: "phonon", //longitudinal //gravitational wave?
+ description: "waves are low
frequency, high
damageexpanding arcs that propagate through
solids",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.haveGunCheck("wave") && !tech.isPhaseVelocity
},
- {
- name: "phonon", //longitudinal //gravitational wave?
- description: "waves are low
frequency, high
damageexpanding arcs that propagate through
solids",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.haveGunCheck("wave") && !tech.isPhaseVelocity
- },
- requires: "wave, not phase velocity",
- ammoScale: 6,
- effect() {
- tech.isLongitudinal = true;
- b.guns[3].chooseFireMethod()
- b.guns[3].ammoPack = b.guns[3].defaultAmmoPack / this.ammoScale
- if (tech.isInfiniteWaveAmmo) {
- b.guns[3].savedAmmo = Math.ceil(b.guns[3].savedAmmo / this.ammoScale); //used with low frequency
- } else {
- b.guns[3].ammo = Math.ceil(b.guns[3].ammo / this.ammoScale);
- }
- simulation.updateGunHUD();
- },
- remove() {
- if (tech.isLongitudinal) {
- tech.isLongitudinal = false;
- b.guns[3].chooseFireMethod()
- b.guns[3].ammoPack = b.guns[3].defaultAmmoPack
- if (tech.isInfiniteWaveAmmo) {
- b.guns[3].savedAmmo = Math.ceil(b.guns[3].savedAmmo * this.ammoScale); //used with low frequency
- } else {
- b.guns[3].ammo = Math.ceil(b.guns[3].ammo * this.ammoScale);
- }
- simulation.updateGunHUD();
- }
+ requires: "wave, not phase velocity",
+ ammoScale: 6,
+ effect() {
+ tech.isLongitudinal = true;
+ b.guns[3].chooseFireMethod()
+ b.guns[3].ammoPack = b.guns[3].defaultAmmoPack / this.ammoScale
+ if (tech.isInfiniteWaveAmmo) {
+ b.guns[3].savedAmmo = Math.ceil(b.guns[3].savedAmmo / this.ammoScale); //used with low frequency
+ } else {
+ b.guns[3].ammo = Math.ceil(b.guns[3].ammo / this.ammoScale);
+ }
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isLongitudinal) {
tech.isLongitudinal = false;
- }
- },
- {
- name: "isotropic",
- description: "
waves expand in
all directions
–40% range and
+50% damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return tech.isLongitudinal && tech.haveGunCheck("wave") && !tech.isBulletTeleport
- },
- requires: "wave, phonon, not uncertainty principle",
- effect() {
- tech.is360Longitudinal = true;
- b.guns[3].chooseFireMethod()
- },
- remove() {
- tech.is360Longitudinal = false;
b.guns[3].chooseFireMethod()
+ b.guns[3].ammoPack = b.guns[3].defaultAmmoPack
+ if (tech.isInfiniteWaveAmmo) {
+ b.guns[3].savedAmmo = Math.ceil(b.guns[3].savedAmmo * this.ammoScale); //used with low frequency
+ } else {
+ b.guns[3].ammo = Math.ceil(b.guns[3].ammo * this.ammoScale);
+ }
+ simulation.updateGunHUD();
+ }
+ tech.isLongitudinal = false;
+ }
+ },
+ {
+ name: "isotropic",
+ description: "
waves expand in
all directions
–40% range and
+50% damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isLongitudinal && tech.haveGunCheck("wave") && !tech.isBulletTeleport
+ },
+ requires: "wave, phonon, not uncertainty principle",
+ effect() {
+ tech.is360Longitudinal = true;
+ b.guns[3].chooseFireMethod()
+ },
+ remove() {
+ tech.is360Longitudinal = false;
+ b.guns[3].chooseFireMethod()
+ }
+ },
+ {
+ name: "mechanical resonance",
+ description: "after a
block gets vibrated by a
phononthere is a chance it's
flung at nearby mobs",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isLongitudinal && tech.haveGunCheck("wave")
+ },
+ requires: "wave, phonon",
+ effect() {
+ tech.isPhononBlock = true
+ },
+ remove() {
+ tech.isPhononBlock = false
+ }
+ },
+ {
+ name: "sympathetic resonance",
+ description: "after a
mob gets vibrated by a
phonona new
resonance wave expands",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isLongitudinal && tech.haveGunCheck("wave")
+ },
+ requires: "wave, phonon",
+ effect() {
+ tech.isPhononWave = true
+ },
+ remove() {
+ tech.isPhononWave = false
+ }
+ },
+ {
+ name: "cruise missile",
+ description: "
+100% missile explosive damage, radius
–50% missile speed",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("missiles") && tech.missileFireCD === 45) || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount
+ },
+ requires: "missiles, not launch system",
+ effect() {
+ tech.isMissileBig = true
+ },
+ remove() {
+ tech.isMissileBig = false
+ }
+ },
+ {
+ name: "ICBM",
+ description: "
+75% missile explosive damage, radius
–50% missile speed",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1)) && tech.isMissileBig
+ },
+ requires: "missiles, cruise missile",
+ effect() {
+ tech.isMissileBiggest = true
+ },
+ remove() {
+ tech.isMissileBiggest = false
+ }
+ },
+ {
+ name: "launch system",
+ description: `
+500% missile gun fire rate+20% missile
ammo per ${powerUps.orb.ammo(1)}`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("missiles") && !tech.isMissileBig
+ },
+ requires: "missiles, not cruise missile",
+ ammoBonus: 1.2,
+ effect() {
+ tech.missileFireCD = 10
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "missiles") {
+ b.guns[i].ammoPack *= this.ammoBonus;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * this.ammoBonus);
+ simulation.updateGunHUD();
+ break
+ }
}
},
- {
- name: "mechanical resonance",
- description: "after a
block gets vibrated by a
phononthere is a chance it's
flung at nearby mobs",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isLongitudinal && tech.haveGunCheck("wave")
- },
- requires: "wave, phonon",
- effect() {
- tech.isPhononBlock = true
- },
- remove() {
- tech.isPhononBlock = false
- }
- },
- {
- name: "sympathetic resonance",
- description: "after a
mob gets vibrated by a
phonona new
resonance wave expands",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isLongitudinal && tech.haveGunCheck("wave")
- },
- requires: "wave, phonon",
- effect() {
- tech.isPhononWave = true
- },
- remove() {
- tech.isPhononWave = false
- }
- },
- {
- name: "cruise missile",
- description: "
+100% missile explosive damage, radius
–50% missile speed",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("missiles") && tech.missileFireCD === 45) || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount
- },
- requires: "missiles, not launch system",
- effect() {
- tech.isMissileBig = true
- },
- remove() {
- tech.isMissileBig = false
- }
- },
- {
- name: "ICBM",
- description: "
+75% missile explosive damage, radius
–50% missile speed",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1)) && tech.isMissileBig
- },
- requires: "missiles, cruise missile",
- effect() {
- tech.isMissileBiggest = true
- },
- remove() {
- tech.isMissileBiggest = false
- }
- },
- {
- name: "launch system",
- description: `
+500% missile gun fire rate+20% missile
ammo per ${powerUps.orb.ammo(1)}`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("missiles") && !tech.isMissileBig
- },
- requires: "missiles, not cruise missile",
- ammoBonus: 1.2,
- effect() {
- tech.missileFireCD = 10
+ remove() {
+ if (tech.missileFireCD !== 45) {
+ tech.missileFireCD = 45;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "missiles") {
- b.guns[i].ammoPack *= this.ammoBonus;
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo * this.ammoBonus);
+ b.guns[i].ammoPack = 5;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoBonus);
simulation.updateGunHUD();
break
}
}
- },
- remove() {
- if (tech.missileFireCD !== 45) {
- tech.missileFireCD = 45;
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "missiles") {
- b.guns[i].ammoPack = 5;
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoBonus);
- simulation.updateGunHUD();
+ }
+ }
+ },
+ {
+ name: "missile-bot",
+ link: `
missile-bot`,
+ description: `use ${powerUps.orb.research(1)}to trade your
missile gunfor a
bot that fires
missiles`,
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return tech.haveGunCheck("missiles", false) && tech.missileFireCD === 45 && (build.isExperimentSelection || powerUps.research.count > 0)
+ },
+ requires: "missiles, not launch system",
+ effect() {
+ tech.missileBotCount++;
+ b.missileBot();
+ if (tech.haveGunCheck("missiles", false)) b.removeGun("missiles") //remove your last gun
+ for (let i = 0; i < 1; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ if (this.count) {
+ tech.missileBotCount = 0;
+ b.clearPermanentBots();
+ b.respawnBots();
+ if (!tech.haveGunCheck("missiles", false)) b.giveGuns("missiles")
+ powerUps.research.changeRerolls(1)
+ }
+ }
+ },
+ {
+ name: "iridium-192",
+ description: "
explosions release
gamma radiation+100% explosion damage over
4 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isImmuneExplosion && tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.isBoomBotUpgrade || tech.isTokamak)
+ },
+ requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation, electric armor",
+ effect() {
+ tech.isExplodeRadio = true; //iridium-192
+ },
+ remove() {
+ tech.isExplodeRadio = false;
+ }
+ },
+ {
+ name: "fragmentation",
+ description: "some
detonations and collisions eject
nailsblocks, grenades, missiles, rivets, harpoon",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isExplodeRadio && ((tech.haveGunCheck("harpoon") && !tech.isFoamBall) || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount || tech.isRivets || tech.blockDamage > 0.075)
+ },
+ requires: "grenades, missiles, rivets, harpoon, or mass driver, not iridium-192, not polyurethane foam",
+ effect() {
+ tech.fragments++
+ },
+ remove() {
+ tech.fragments = 0
+ }
+ },
+ {
+ name: "ammonium nitrate",
+ description: "
+24% explosive damage, radius",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source, not iridium-192",
+ effect() {
+ tech.explosiveRadius += 0.24;
+ },
+ remove() {
+ tech.explosiveRadius = 1;
+ }
+ },
+ {
+ name: "nitroglycerin",
+ description: "
+66% explosive damage–33% explosive radius",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isExplosionHarm
+ },
+ requires: "an explosive damage source, not iridium-192, acetone peroxide",
+ effect() {
+ tech.isSmallExplosion = true;
+ },
+ remove() {
+ tech.isSmallExplosion = false;
+ }
+ },
+ {
+ name: "acetone peroxide",
+ description: "
+70% explosive radius–40% explosive defense",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBadRandomOption: true,
+ allowed() {
+ return tech.hasExplosiveDamageCheck() && !tech.isSmallExplosion
+ },
+ requires: "an explosive damage source, not nitroglycerin",
+ effect() {
+ tech.isExplosionHarm = true;
+ },
+ remove() {
+ tech.isExplosionHarm = false;
+ }
+ },
+ {
+ name: "shock wave",
+ description: "
mines and
sporangium stun for
3-5 seconds
explosions stun for
0.5 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.haveGunCheck("mine") || (!tech.isExplodeRadio && tech.hasExplosiveDamageCheck())
+ },
+ requires: "mine, spores, an explosive damage source, not iridium-192",
+ effect() {
+ tech.isStun = true;
+ },
+ remove() {
+ tech.isStun = false;
+ }
+ },
+ {
+ name: "shaped charge",
+ description: `use ${powerUps.orb.research(3)} to dynamically
reduceall
explosions to prevent
health loss`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 2) && (tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
+ },
+ requires: "an explosive damage source, not rocket propelled grenade",
+ effect() {
+ tech.isSmartRadius = true;
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isSmartRadius = false;
+ if (this.count > 0) powerUps.research.changeRerolls(3)
+ }
+ },
+ // {
+ // name: "electric armor",
+ // // description: "
explosions do no
defense while your
energy is above
98%",
+ // description: "instead of causing
health loss,
explosionsdrain
12 energy and have more knockback",
+ // isGunTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ // },
+ // requires: "an explosive damage source, not iridium-192",
+ // effect() {
+ // tech.isImmuneExplosion = true;
+ // },
+ // remove() {
+ // tech.isImmuneExplosion = false;
+ // }
+ // },
+ {
+ name: "MIRV",
+ description: "fire
+1 missile or
grenade per shot
–12% explosion damage and
radius",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("missiles") || tech.missileBotCount || tech.haveGunCheck("grenades")
+ },
+ requires: "missiles, grenades",
+ effect() {
+ tech.missileCount++;
+ },
+ remove() {
+ tech.missileCount = 1;
+ }
+ },
+ {
+ name: "rocket-propelled grenade",
+ description: "
grenades explode on map
collisionsexplosions drain
energy, not
health",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isVacuumBomb
+ },
+ requires: "grenades, not vacuum bomb",
+ effect() {
+ tech.isImmuneExplosion = true;
+ tech.isRPG = true;
+ b.setGrenadeMode()
+ },
+ remove() {
+ tech.isImmuneExplosion = false;
+ tech.isRPG = false;
+ b.setGrenadeMode()
+ }
+ },
+ {
+ name: "vacuum bomb",
+ description: "
grenades fire slower,
explode bigger,
and
suck everything towards them",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode && !tech.isRPG
+ },
+ requires: "grenades, not neutron bomb, chain reaction, RPG",
+ effect() {
+ tech.isVacuumBomb = true;
+ b.setGrenadeMode()
+ },
+ remove() {
+ tech.isVacuumBomb = false;
+ b.setGrenadeMode()
+ }
+ },
+ {
+ name: "chain reaction",
+ description: "
+33% grenade radius and
damageblocks caught in
explosions also
explode",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb && !tech.isVacuumBomb
+ },
+ requires: "grenades, not iridium-192, neutron bomb, vacuum bomb",
+ effect() {
+ tech.isBlockExplode = true; //chain reaction
+ },
+ remove() {
+ tech.isBlockExplode = false;
+ }
+ },
+ {
+ name: "flame test",
+ description: "after
grenades detonate they release
a colorful
cluster of small
explosions",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isCircleExplode && !tech.isPetalsExplode
+ },
+ requires: "grenades, not neutron bomb, pyrotechnics, fireworks",
+ effect() {
+ tech.isClusterExplode = true;
+ },
+ remove() {
+ tech.isClusterExplode = false;
+ }
+ },
+ {
+ name: "pyrotechnics",
+ description: "after
grenades detonate they release
a colorful
circle of
explosions",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isClusterExplode && !tech.isPetalsExplode
+ },
+ requires: "grenades, not neutron bomb, flame test, fireworks",
+ effect() {
+ tech.isCircleExplode = true;
+ },
+ remove() {
+ tech.isCircleExplode = false;
+ }
+ },
+ {
+ name: "fireworks",
+ description: "after
grenades detonate they release
colorful
petals of
explosions",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isClusterExplode && !tech.isCircleExplode
+ },
+ requires: "grenades, not neutron bomb, pyrotechnics, flame test",
+ effect() {
+ tech.isPetalsExplode = true;
+ },
+ remove() {
+ tech.isPetalsExplode = false;
+ }
+ },
+ {
+ name: "neutron bomb",
+ description: "
grenades are
irradiated with
Cf-252does
radioactive damage over time",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && !tech.isPetalsExplode && !tech.isCircleExplode
+ },
+ requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test, chain reaction",
+ effect() {
+ tech.isNeutronBomb = true;
+ b.setGrenadeMode()
+ },
+ remove() {
+ tech.isNeutronBomb = false;
+ b.setGrenadeMode()
+ }
+ },
+ {
+ name: "vacuum permittivity",
+ description: "
+20% radioactive range
objects in range of the bomb are
slowed",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNeutronBomb
+ },
+ requires: "grenades, neutron bomb",
+ effect() {
+ tech.isNeutronSlow = true
+ },
+ remove() {
+ tech.isNeutronSlow = false
+ }
+ },
+ {
+ name: "radioactive contamination",
+ description: "after a mob or shield
dies,
leftover
radiation spreads to a nearby mob",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio || tech.isBlockRadiation
+ },
+ requires: "radiation damage source",
+ effect() {
+ tech.isRadioactive = true
+ },
+ remove() {
+ tech.isRadioactive = false
+ }
+ },
+ {
+ name: "nuclear transmutation",
+ description: "
+47% radiation damagenail, drone, neutron bomb, iridium, cosmic string, deflect",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio || tech.isBlockRadiation || tech.isDroneRadioactive
+ },
+ requires: "radiation damage source",
+ effect() {
+ tech.radioactiveDamage += 1.47
+ },
+ remove() {
+ tech.radioactiveDamage = 1
+ }
+ },
+ {
+ name: "water shielding",
+ link: `
water shielding`,
+ description: "
radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio
+ },
+ requires: "neutron bomb, irradiated drones, iridium-192",
+ effect() {
+ tech.isRadioactiveResistance = true
+ },
+ remove() {
+ tech.isRadioactiveResistance = false
+ }
+ },
+ {
+ name: "ricochet",
+ description: "after
nails hit a mob they
rebound towards
a new mob with
+180% damage per bounce",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines"))
+ return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles)
+ },
+ //
+ requires: "nail gun, not rotary cannon, rivets, or needles",
+ effect() {
+ tech.isRicochet = true
+ },
+ remove() {
+ tech.isRicochet = false
+ }
+ },
+ {
+ name: "booby trap",
+ description: "
50% chance to drop a
mine from
power ups+36% JUNK to
tech pool",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine")
+ },
+ requires: "mines",
+ effect() {
+ tech.isMineDrop = true;
+ if (tech.isMineDrop) b.mine(m.pos, {
+ x: 0,
+ y: 0
+ }, 0)
+ this.refundAmount += tech.addJunkTechToPool(0.36)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.isMineDrop = false;
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "elephants toothpaste",
+ description: "instead of nails
mines catalyze a reaction
that yields
foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && !tech.isSuperMine && !tech.isRicochet && !tech.isNailRadiation && !tech.isNailCrit
+ },
+ requires: "mines, not blast ball, ricochet, irradiated nails, supercritical fission",
+ effect() {
+ tech.isFoamMine = true;
+ },
+ remove() {
+ tech.isFoamMine = false;
+ }
+ },
+ {
+ name: "blast ball",
+ descriptionFunction() {
+ return `instead of nails
mines fire
bouncy balls`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && !tech.isFoamMine && !tech.isRicochet && !tech.isNailRadiation && !tech.isNailCrit
+ },
+ requires: "mines, not elephants toothpaste, ricochet, irradiated nails, supercritical fission",
+ effect() {
+ tech.isSuperMine = true;
+ },
+ remove() {
+ tech.isSuperMine = false;
+ }
+ },
+ {
+ name: "laser-mines",
+ link: `
laser-mines`,
+ description: "
mines laid while you are
croucheduse
energy to emit
3 unaimed
lasers",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine")
+ },
+ requires: "mines",
+ effect() {
+ tech.isLaserMine = true;
+ },
+ remove() {
+ tech.isLaserMine = false;
+ }
+ },
+ {
+ name: "sentry",
+ descriptionFunction() {
+ return `
mines fire one ${b.guns[10].nameString()} at a time
mines fire
50% more ${b.guns[10].nameString('s')}`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && !tech.isFoamMine
+ },
+ requires: "mines, not elephants toothpaste",
+ effect() {
+ tech.isMineSentry = true;
+ },
+ remove() {
+ tech.isMineSentry = false;
+ }
+ },
+ {
+ name: "extended magazine",
+ descriptionFunction() {
+ return `sentry
mines fire
50% more ${b.guns[10].nameString('s')}`
+ },
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && tech.isMineSentry
+ },
+ requires: "mines, sentry",
+ effect() {
+ tech.sentryAmmo += 17;
+ },
+ remove() {
+ tech.sentryAmmo = 33;
+ }
+ },
+ {
+ name: "mycelial fragmentation",
+ link: `
mycelial fragmentation`,
+ description: "during their
growth phase
+70% sporangium discharge",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores")
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeGrowth = true
+ },
+ remove() {
+ tech.isSporeGrowth = false
+ }
+ },
+ {
+ name: "cordyceps",
+ // descriptionFunction() {
+ // return `mobs infected by ${b.guns[6].nameString('s')} have a
5% chance
to
resurrect and attack other mobs`
+ // },
+ description: "
sporangium infect mobs they attach to
infected mobs
resurrect and attack other mobs",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores")
+ },
+ requires: "spores",
+ effect() {
+ tech.isZombieMobs = true
+ },
+ remove() {
+ tech.isZombieMobs = false
+ }
+ },
+ {
+ name: "colony",
+ description: "
+50% sporangium discharge
40% chance to discharge something different",
+ link: `
colony`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores")
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeColony = true
+ },
+ remove() {
+ tech.isSporeColony = false
+ }
+ },
+ {
+ name: "cryodesiccation",
+ descriptionFunction() {
+ return `
+25% sporangium discharge
${b.guns[6].nameString('s')}
freeze mobs for
1.5 second`
+ },
+ // description: "
+25% sporangium discharge
spores freeze mobs for
1.5 second",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeFreeze = true
+ },
+ remove() {
+ tech.isSporeFreeze = false
+ }
+ },
+ {
+ name: "flagella",
+ descriptionFunction() {
+ return `
+50% ${b.guns[6].nameString()} acceleration
if they can't find a target ${b.guns[6].nameString('s')} follow you`
+ },
+ // description: "
+50% spore acceleration
if they can't find a target
spores follow you",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeFollow = true
+ },
+ remove() {
+ tech.isSporeFollow = false
+ }
+ },
+ {
+ name: "junk DNA",
+ descriptionFunction() {
+ return `
+53% ${b.guns[6].nameString()}
damage per
JUNKtech (${(53 * tech.junkCount).toFixed(0)}%)+50% JUNK to
tech pool`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isJunkDNA = true
+ this.refundAmount += tech.addJunkTechToPool(0.5)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.isJunkDNA = false
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ // {
+ // name: "junk DNA",
+ // //increase damage by 10% for each JUNK tech percent in the tech pool, remove all JUNK tech,
+ // descriptionFunction() { return `
+50% ${b.guns[6].nameString()}
damage+15% JUNK to
tech pool` },
+ // isGunTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ // },
+ // requires: "spores",
+ // effect() {
+ // tech.isSporeWorm = true
+ // this.refundAmount += tech.addJunkTechToPool(0.15)
+ // },
+ // refundAmount: 0,
+ // remove() {
+ // tech.isSporeWorm = false
+ // if (this.count > 0 && this.refundAmount > 0) {
+ // tech.removeJunkTechFromPool(this.refundAmount)
+ // this.refundAmount = 0
+ // }
+ // }
+ // },
+ {
+ name: "mutualism",
+ descriptionFunction() {
+ return `
+200% ${b.guns[6].nameString()}
damage${b.guns[6].nameString('s')} borrow
1 health until they
die`
+ },
+ // description: `
+150% ${b.guns[6].name()}
damagespores borrow
0.5 health until they
die`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0)) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isMutualism = true
+ },
+ remove() {
+ tech.isMutualism = false
+ }
+ },
+ {
+ name: "necrophage",
+ description: "if
foam,
fleas, or
worms kill their target
they grow 3
copies",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine
+ },
+ requires: "foam, spores, worms, fleas",
+ effect() {
+ tech.isSpawnBulletsOnDeath = true
+ },
+ remove() {
+ tech.isSpawnBulletsOnDeath = false;
+ }
+ },
+ {
+ name: "siphonaptera",
+ description: "
sporangium and
shotgun hatch
fleas",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeWorm
+ },
+ requires: "spores, not worms",
+ effect() {
+ tech.isSporeFlea = true
+ },
+ remove() {
+ tech.isSporeFlea = false
+
+ }
+ },
+ {
+ name: "nematodes",
+ description: "
shotgun and
sporangium hatch
worms",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeFlea
+ },
+ requires: "spores, not fleas",
+ effect() {
+ tech.isSporeWorm = true
+ },
+ remove() {
+ tech.isSporeWorm = false
+ }
+ },
+ {
+ name: "K-selection",
+ description: "
+37% worm and
flea damage",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores, shotgun, worms, fleas",
+ effect() {
+ tech.wormSize++
+ },
+ remove() {
+ tech.wormSize = 0
+ }
+ },
+ {
+ name: "path integration",
+ descriptionFunction() {
+ return `
drones and ${b.guns[6].nameString("s")}
travel with you through
levels`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isSporeFollow && (tech.haveGunCheck("spores") || (tech.haveGunCheck("shotgun") && tech.isSporeWorm))) || tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && (simulation.molecularMode === 0 || simulation.molecularMode === 3))
+ },
+ requires: "spores, worms, flagella, drones",
+ effect() {
+ tech.isDronesTravel = true
+ },
+ remove() {
+ tech.isDronesTravel = false
+ }
+ },
+ {
+ name: "reduced tolerances",
+ link: `
reduced tolerances`,
+ description: `
+66% drones per ${powerUps.orb.ammo()} and
energy–40% drone
duration`,
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isDroneRadioactive && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3))
+ },
+ requires: "drones, not irradiated drones",
+ effect() {
+ tech.droneCycleReduction = Math.pow(0.6, 1 + this.count)
+ tech.droneEnergyReduction = Math.pow(0.333, 1 + this.count)
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ const scale = Math.pow(3, this.count + 1)
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * scale
+ }
+ }
+ },
+ remove() {
+ tech.droneCycleReduction = 1
+ tech.droneEnergyReduction = 1
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ }
+ }
+ },
+ {
+ name: "delivery drone",
+ description: "if a
drone picks up a
power up,
it becomes
larger,
faster, and more
durable",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3)
+ },
+ requires: "drones",
+ effect() {
+ tech.isDroneGrab = true
+ },
+ remove() {
+ tech.isDroneGrab = false
+ }
+ },
+ {
+ name: "drone repair",
+ link: `
drone repair`,
+ description: "after a
drone expires it
redeploysfor a
20% chance to use
1 drone ammo",
+ // description: "broken
drones repair if the drone
gun is active
repairing has a
25% chance to use
1 drone",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("drones")
+ },
+ requires: "drones",
+ effect() {
+ tech.isDroneRespawn = true
+ },
+ remove() {
+ tech.isDroneRespawn = false
+ }
+ },
+ {
+ name: "brushless motor",
+ description: "
drones rapidly
rush towards their target
+33% drone collision
damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3)) && !tech.isDroneRadioactive && !tech.isIncendiary
+ },
+ requires: "drones, molecular assembler, not irradiated drones, incendiary",
+ effect() {
+ tech.isDroneTeleport = true
+ },
+ remove() {
+ tech.isDroneTeleport = false
+ }
+ },
+ {
+ name: "axial flux motor",
+ description: "
+66% drones rush frequency
+44% drone collision
damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isDroneTeleport
+ },
+ requires: "drones, brushless motor",
+ effect() {
+ tech.isDroneFastLook = true
+ },
+ remove() {
+ tech.isDroneFastLook = false
+ }
+ },
+ {
+ name: "irradiated drones",
+ link: `
irradiated drones`,
+ description: `the space around
drones is
irradiated–75% drones per ${powerUps.orb.ammo()} and
energy`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.droneCycleReduction === 1 && !tech.isIncendiary && !tech.isDroneTeleport && (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3))
+ },
+ requires: "drones, not reduced tolerances, incendiary, torque bursts",
+ effect() {
+ tech.isDroneRadioactive = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.25
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.25)
+ simulation.makeGunHUD();
+ }
+ }
+ },
+ remove() {
+ if (tech.isDroneRadioactive) {
+ tech.isDroneRadioactive = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ b.guns[i].ammo = b.guns[i].ammo * 4
+ simulation.makeGunHUD();
+ }
+ }
+ }
+ }
+ },
+ {
+ name: "beta radiation", //"control rod ejection",
+ description: "
–50% drone duration
+100% drone radiation damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isDroneRadioactive
+ },
+ requires: "drones, irradiated drones",
+ effect() {
+ tech.droneRadioDamage = 2
+ },
+ remove() {
+ tech.droneRadioDamage = 1
+ }
+ },
+ {
+ name: "orthocyclic winding",
+ link: `
orthocyclic winding`,
+ description: "
+66% drone acceleration
+33% radiation damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isDroneRadioactive
+ },
+ requires: "drones, irradiated drones",
+ effect() {
+ tech.isFastDrones = true
+ },
+ remove() {
+ tech.isFastDrones = false
+ }
+ },
+ {
+ name: "fault tolerance",
+ description: `use ${powerUps.orb.research(2)}to trade your
drone gunfor
5 drones that last
forever`,
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.isBulletsLastLonger === 1 && !tech.isDronesTravel && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "drones, not drone repair, anti-shear topology, autonomous navigation",
+ effect() {
+ const num = 5
+ tech.isForeverDrones += num
+ if (tech.haveGunCheck("drones", false)) b.removeGun("drones")
+ //spawn drones
+ if (tech.isDroneRadioactive) {
+ for (let i = 0; i < num * 0.25; i++) {
+ b.droneRadioactive({
+ x: m.pos.x + 30 * (Math.random() - 0.5),
+ y: m.pos.y + 30 * (Math.random() - 0.5)
+ }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ } else {
+ for (let i = 0; i < num; i++) {
+ b.drone({
+ x: m.pos.x + 30 * (Math.random() - 0.5),
+ y: m.pos.y + 30 * (Math.random() - 0.5)
+ }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ }
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isForeverDrones = 0
+ if (this.count && !tech.haveGunCheck("drones", false)) b.giveGuns("drones")
+ if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "surfactant",
+ description: `use ${powerUps.orb.research(2)}to trade your
foam gunfor
2 foam-bots and
foam-bot upgrade`,
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ isNonRefundable: true,
+ requires: "foam gun, not bot upgrades, fractionation, pressure vessel",
+ allowed() {
+ return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade() && !tech.isAmmoFoamSize && !tech.isFoamPressure && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ effect() {
+ tech.giveTech("foam-bot upgrade")
+ for (let i = 0; i < 2; i++) {
+ b.foamBot()
+ tech.foamBotCount++;
+ }
+ simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
+ if (tech.haveGunCheck("foam", false)) b.removeGun("foam")
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ // if (this.count) {
+ // b.clearPermanentBots();
+ // b.respawnBots();
+ // if (!tech.haveGunCheck("foam")) b.giveGuns("foam")
+ // }
+ // if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "electrostatic induction",
+ description: "
foam bubbles are electrically charged
causing
attraction to nearby
mobs",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isBulletTeleport && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)
+ },
+ requires: "foam, not uncertainty",
+ effect() {
+ tech.isFoamAttract = true
+ },
+ remove() {
+ tech.isFoamAttract = false
+ }
+ },
+ {
+ name: "uncertainty principle",
+ description: "
foam and
wave positions are erratic
+53% foam and
wave damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (!tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)) || (tech.haveGunCheck("wave") && !tech.is360Longitudinal)
+ },
+ requires: "foam, wave, not isotropic, electrostatic induction",
+ effect() {
+ tech.isBulletTeleport = true
+ },
+ remove() {
+ tech.isBulletTeleport = false;
+ }
+ },
+ {
+ name: "aerogel",
+ description: "
–50% foam duration and
foam bubbles
float+180% foam damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
+ },
+ requires: "foam",
+ effect() {
+ tech.isFastFoam = true
+ tech.foamGravity = -0.0003
+ },
+ remove() {
+ tech.isFastFoam = false;
+ tech.foamGravity = 0.00008
+ }
+ },
+ {
+ name: "surface tension",
+ description: "
+43% foam damage",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
+ },
+ requires: "foam",
+ effect() {
+ tech.foamDamage += 0.011 * 0.43
+ },
+ remove() {
+ tech.foamDamage = 0.011;
+ }
+ },
+ {
+ name: "foam fractionation",
+ description: "if you have below
300 ammo+100% foam gun bubble
size",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam")
+ },
+ requires: "foam",
+ effect() {
+ tech.isAmmoFoamSize = true
+ },
+ remove() {
+ tech.isAmmoFoamSize = false;
+ }
+ },
+ {
+ name: "ideal gas law",
+ description: `remove
all current
foam ammo+1200% foam ammo per ${powerUps.orb.ammo(1)}`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") && !tech.isEnergyNoAmmo
+ },
+ requires: "foam, not non-renewables",
+ ammoLost: 0,
+ effect() {
+ b.guns[8].ammoPack = b.guns[8].ammoPack * 12;
+ this.ammoLost = b.guns[8].ammo
+ b.guns[8].ammo = 0
+ simulation.updateGunHUD()
+ },
+ remove() {
+ b.guns[8].ammoPack = 24
+ if (this.count) {
+ b.guns[8].ammo += this.ammoLost
+ simulation.updateGunHUD()
+ }
+ }
+ },
+ {
+ name: "pressure vessel",
+ description: "build up
charge while firing
foam gunafter firing
discharge foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam")
+ },
+ requires: "foam",
+ effect() {
+ tech.isFoamPressure = true;
+ b.guns[8].chooseFireMethod()
+ },
+ remove() {
+ tech.isFoamPressure = false;
+ b.guns[8].chooseFireMethod()
+ }
+ },
+ {
+ name: "capacitor bank",
+ // description: "
charge effects build up almost
instantlythrowing blocks, foam, railgun, pulse, tokamak",
+ descriptionFunction() {
+ return `
charge effects build up almost
instantlythrowing, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isPlasmaBall ? "plasma ball" : "plasma ball"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.blockDamage > 0.075 || tech.isRailGun || (tech.haveGunCheck("foam") && tech.isFoamPressure) || tech.isTokamak || tech.isPulseLaser || tech.isPlasmaBall
+ },
+ requires: "mass driver, railgun, foam, pressure vessel, pulse, tokamak, plasma ball",
+ effect() {
+ tech.isCapacitor = true;
+ },
+ remove() {
+ tech.isCapacitor = false;
+ }
+ },
+ {
+ name: "Bitter electromagnet",
+ descriptionFunction() {
+ return `
railgun charges
+33% slower
+100% harpoon density and
damage`
+ },
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && tech.isRailGun
+ },
+ requires: "harpoon, railgun",
+ effect() {
+ tech.railChargeRate *= 1.06
+ tech.harpoonDensity += 0.0065
+ },
+ remove() {
+ tech.railChargeRate = 0.97;
+ tech.harpoonDensity = 0.0065
+ }
+ },
+ {
+ name: "railgun",
+ description: `hold fire to charge
harpoon and release to launch
harpoons can't
retract`,
+ // description: `
+900% harpoon ammo, but it can't
retract+50% harpoon density and
damage`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple && !tech.isBoostReplaceAmmo
+ },
+ requires: "harpoon, not UHMWPE, induction furnace, grappling hook, quasiparticles",
+ ammoBonus: 9,
+ effect() {
+ tech.isRailGun = true;
+ b.guns[9].chooseFireMethod()
+ b.guns[9].ammoPack = 5;
+ b.guns[9].ammo = b.guns[9].ammo * 6;
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isRailGun) {
+ tech.isRailGun = false;
+ b.guns[9].chooseFireMethod()
+ b.guns[9].ammoPack = 1.7;
+ b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6);
+ simulation.updateGunHUD();
+ }
+ }
+ },
+ {
+ name: "grappling hook",
+ description: `
harpoons attach to the
map and pull you
your
rope extends while holding
fire`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
+ },
+ requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism",
+ effect() {
+ tech.isGrapple = true;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
+ }
+ },
+ remove() {
+ if (tech.isGrapple) {
+ tech.isGrapple = false;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
+ }
+ }
+ }
+ },
+ {
+ name: "bulk modulus",
+ description: `while
grappling become
invulnerabledrain
energy`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy
+ },
+ requires: "grappling hook, not alternator",
+ effect() {
+ tech.isImmuneGrapple = true;
+ },
+ remove() {
+ tech.isImmuneGrapple = false
+ }
+ },
+ {
+ name: "alternator",
+ description: "
+90% harpoon energy efficiency",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isImmuneGrapple
+ },
+ requires: "harpoon, not bulk modulus",
+ effect() {
+ tech.isRailEnergy = true;
+ },
+ remove() {
+ tech.isRailEnergy = false;
+ }
+ },
+ {
+ name: "Bessemer process",
+ descriptionFunction() {
+ return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}%
harpoon size and
damage(1/10 √ harpoon ammo)`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isShieldPierce
+ },
+ requires: "harpoon, not ceramics",
+ effect() {
+ tech.isLargeHarpoon = true;
+ },
+ remove() {
+ tech.isLargeHarpoon = false;
+ }
+ },
+ {
+ name: "smelting",
+ descriptionFunction() {
+ return `forge
${this.removeAmmo()} ammo into a new harpoon
fire
+1 harpoon with each shot`
+ },
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ ammoRemoved: 0,
+ removeAmmo() {
+ return (tech.isRailGun ? 5 : 1) * (2 + 2 * this.count)
+ },
+ allowed() {
+ return tech.haveGunCheck("harpoon") && b.guns[9].ammo >= this.removeAmmo()
+ },
+ requires: "harpoon",
+ effect() {
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") {
+ const removeAmmo = this.removeAmmo()
+ this.ammoRemoved += removeAmmo
+ b.guns[i].ammo -= removeAmmo
+ if (b.guns[i].ammo < 0) b.guns[i].ammo = 0
+ simulation.updateGunHUD();
+ tech.extraHarpoons++;
+ break
+ }
+ }
+ },
+ remove() {
+ if (tech.extraHarpoons) {
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") {
+ b.guns[i].ammo += this.ammoRemoved
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ }
+ this.ammoRemoved = 0
+ tech.extraHarpoons = 0;
+ }
+ },
+ {
+ name: "UHMWPE",
+ descriptionFunction() {
+ return `+${(b.guns[9].ammo * 1.25).toFixed(0)}%
harpoon rope length(1/80 of harpoon ammo)`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
+ },
+ requires: "harpoon, not grappling hook, railgun",
+ effect() {
+ tech.isFilament = true;
+ },
+ remove() {
+ tech.isFilament = false;
+ }
+ },
+ {
+ name: "induction furnace",
+ description: "after using
harpoon to collect a
power up+600% harpoon damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
+ },
+ requires: "harpoon, not grappling hook, railgun",
+ effect() {
+ tech.isHarpoonPowerUp = true
+ },
+ remove() {
+ tech.isHarpoonPowerUp = false
+ }
+ },
+ {
+ name: "quasiparticles",
+ descriptionFunction() {
+ return `convert current and future ${powerUps.orb.ammo(1)} into ${powerUps.orb.boost(1)} which
give
+${(powerUps.boost.damage * 100).toFixed(0)}% damage for
${(powerUps.boost.duration / 60).toFixed(0)} seconds`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return ((tech.haveGunCheck("wave") && !tech.isInfiniteWaveAmmo) || tech.haveGunCheck("laser") || (tech.haveGunCheck("harpoon") && !tech.isRailGun)) && !tech.isEnergyNoAmmo
+ },
+ requires: "harpoon, laser, wave, frequency, not railgun, non-renewables",
+ effect() {
+ tech.isBoostReplaceAmmo = true
+ for (let i = powerUp.length - 1; i > -1; i--) {
+ if (powerUp[i].name === "ammo") {
+ powerUps.spawn(powerUp[i].position.x + 50 * (Math.random() - 0.5), powerUp[i].position.y + 50 * (Math.random() - 0.5), "boost");
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ }
+ }
+
+ },
+ remove() {
+ tech.isBoostReplaceAmmo = false
+ }
+ },
+ {
+ name: "optical amplifier",
+ description: "gain
3 random
laser guntechlaser only turns
off if you have no
energy",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isNonRefundable: true,
+ allowed() {
+ return tech.haveGunCheck("laser") && !tech.isPulseLaser
+ },
+ requires: "laser gun, not pulse",
+ effect() {
+ 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"]
+ //convert names into indexes
+ const options = []
+ for (let i = 0; i < names.length; i++) {
+ for (let k = 0; k < tech.tech.length; k++) {
+ if (tech.tech[k].name === names[i]) {
+ options.push(k)
break
}
}
}
- }
- },
- {
- name: "missile-bot",
- link: `
missile-bot`,
- description: `use ${powerUps.orb.research(1)}to trade your
missile gunfor a
bot that fires
missiles`,
- isGunTech: true,
- isRemoveGun: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- allowed() {
- return tech.haveGunCheck("missiles", false) && tech.missileFireCD === 45 && (build.isExperimentSelection || powerUps.research.count > 0)
- },
- requires: "missiles, not launch system",
- effect() {
- tech.missileBotCount++;
- b.missileBot();
- if (tech.haveGunCheck("missiles", false)) b.removeGun("missiles") //remove your last gun
- for (let i = 0; i < 1; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- if (this.count) {
- tech.missileBotCount = 0;
- b.clearPermanentBots();
- b.respawnBots();
- if (!tech.haveGunCheck("missiles", false)) b.giveGuns("missiles")
- powerUps.research.changeRerolls(1)
- }
- }
- },
- {
- name: "iridium-192",
- description: "
explosions release
gamma radiation+100% explosion damage over
4 seconds",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isImmuneExplosion && tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.isBoomBotUpgrade || tech.isTokamak)
- },
- requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation, electric armor",
- effect() {
- tech.isExplodeRadio = true; //iridium-192
- },
- remove() {
- tech.isExplodeRadio = false;
- }
- },
- {
- name: "fragmentation",
- description: "some
detonations and collisions eject
nailsblocks, grenades, missiles, rivets, harpoon",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isExplodeRadio && ((tech.haveGunCheck("harpoon") && !tech.isFoamBall) || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount || tech.isRivets || tech.blockDamage > 0.075)
- },
- requires: "grenades, missiles, rivets, harpoon, or mass driver, not iridium-192, not polyurethane foam",
- effect() {
- tech.fragments++
- },
- remove() {
- tech.fragments = 0
- }
- },
- {
- name: "ammonium nitrate",
- description: "
+24% explosive damage, radius",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
- },
- requires: "an explosive damage source, not iridium-192",
- effect() {
- tech.explosiveRadius += 0.24;
- },
- remove() {
- tech.explosiveRadius = 1;
- }
- },
- {
- name: "nitroglycerin",
- description: "
+66% explosive damage–33% explosive radius",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isExplosionHarm
- },
- requires: "an explosive damage source, not iridium-192, acetone peroxide",
- effect() {
- tech.isSmallExplosion = true;
- },
- remove() {
- tech.isSmallExplosion = false;
- }
- },
- {
- name: "acetone peroxide",
- description: "
+70% explosive radius–40% explosive defense",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBadRandomOption: true,
- allowed() {
- return tech.hasExplosiveDamageCheck() && !tech.isSmallExplosion
- },
- requires: "an explosive damage source, not nitroglycerin",
- effect() {
- tech.isExplosionHarm = true;
- },
- remove() {
- tech.isExplosionHarm = false;
- }
- },
- {
- name: "shock wave",
- description: "
mines and
sporangium stun for
3-5 seconds
explosions stun for
0.5 seconds",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.haveGunCheck("spores") || tech.haveGunCheck("mine") || (!tech.isExplodeRadio && tech.hasExplosiveDamageCheck())
- },
- requires: "mine, spores, an explosive damage source, not iridium-192",
- effect() {
- tech.isStun = true;
- },
- remove() {
- tech.isStun = false;
- }
- },
- {
- name: "shaped charge",
- description: `use ${powerUps.orb.research(3)} to dynamically
reduceall
explosions to prevent
health loss`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 2) && (tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
- },
- requires: "an explosive damage source, not rocket propelled grenade",
- effect() {
- tech.isSmartRadius = true;
- for (let i = 0; i < 3; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isSmartRadius = false;
- if (this.count > 0) powerUps.research.changeRerolls(3)
- }
- },
- // {
- // name: "electric armor",
- // // description: "
explosions do no
defense while your
energy is above
98%",
- // description: "instead of causing
health loss,
explosionsdrain
12 energy and have more knockback",
- // isGunTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 2,
- // frequencyDefault: 2,
- // allowed() {
- // return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
- // },
- // requires: "an explosive damage source, not iridium-192",
- // effect() {
- // tech.isImmuneExplosion = true;
- // },
- // remove() {
- // tech.isImmuneExplosion = false;
- // }
- // },
- {
- name: "MIRV",
- description: "fire
+1 missile or
grenade per shot
–12% explosion damage and
radius",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("missiles") || tech.missileBotCount || tech.haveGunCheck("grenades")
- },
- requires: "missiles, grenades",
- effect() {
- tech.missileCount++;
- },
- remove() {
- tech.missileCount = 1;
- }
- },
- {
- name: "rocket-propelled grenade",
- description: "
grenades explode on map
collisionsexplosions drain
energy, not
health",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.isVacuumBomb
- },
- requires: "grenades, not vacuum bomb",
- effect() {
- tech.isImmuneExplosion = true;
- tech.isRPG = true;
- b.setGrenadeMode()
- },
- remove() {
- tech.isImmuneExplosion = false;
- tech.isRPG = false;
- b.setGrenadeMode()
- }
- },
- {
- name: "vacuum bomb",
- description: "
grenades fire slower,
explode bigger,
and
suck everything towards them",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode && !tech.isRPG
- },
- requires: "grenades, not neutron bomb, chain reaction, RPG",
- effect() {
- tech.isVacuumBomb = true;
- b.setGrenadeMode()
- },
- remove() {
- tech.isVacuumBomb = false;
- b.setGrenadeMode()
- }
- },
- {
- name: "chain reaction",
- description: "
+33% grenade radius and
damageblocks caught in
explosions also
explode",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb && !tech.isVacuumBomb
- },
- requires: "grenades, not iridium-192, neutron bomb, vacuum bomb",
- effect() {
- tech.isBlockExplode = true; //chain reaction
- },
- remove() {
- tech.isBlockExplode = false;
- }
- },
- {
- name: "flame test",
- description: "after
grenades detonate they release
a colorful
cluster of small
explosions",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isCircleExplode && !tech.isPetalsExplode
- },
- requires: "grenades, not neutron bomb, pyrotechnics, fireworks",
- effect() {
- tech.isClusterExplode = true;
- },
- remove() {
- tech.isClusterExplode = false;
- }
- },
- {
- name: "pyrotechnics",
- description: "after
grenades detonate they release
a colorful
circle of
explosions",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isClusterExplode && !tech.isPetalsExplode
- },
- requires: "grenades, not neutron bomb, flame test, fireworks",
- effect() {
- tech.isCircleExplode = true;
- },
- remove() {
- tech.isCircleExplode = false;
- }
- },
- {
- name: "fireworks",
- description: "after
grenades detonate they release
colorful
petals of
explosions",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isClusterExplode && !tech.isCircleExplode
- },
- requires: "grenades, not neutron bomb, pyrotechnics, flame test",
- effect() {
- tech.isPetalsExplode = true;
- },
- remove() {
- tech.isPetalsExplode = false;
- }
- },
- {
- name: "neutron bomb",
- description: "
grenades are
irradiated with
Cf-252does
radioactive damage over time",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && !tech.isPetalsExplode && !tech.isCircleExplode
- },
- requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test, chain reaction",
- effect() {
- tech.isNeutronBomb = true;
- b.setGrenadeMode()
- },
- remove() {
- tech.isNeutronBomb = false;
- b.setGrenadeMode()
- }
- },
- {
- name: "vacuum permittivity",
- description: "
+20% radioactive range
objects in range of the bomb are
slowed",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNeutronBomb
- },
- requires: "grenades, neutron bomb",
- effect() {
- tech.isNeutronSlow = true
- },
- remove() {
- tech.isNeutronSlow = false
- }
- },
- {
- name: "radioactive contamination",
- description: "after a mob or shield
dies,
leftover
radiation spreads to a nearby mob",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio || tech.isBlockRadiation
- },
- requires: "radiation damage source",
- effect() {
- tech.isRadioactive = true
- },
- remove() {
- tech.isRadioactive = false
- }
- },
- {
- name: "nuclear transmutation",
- description: "
+47% radiation damagenail, drone, neutron bomb, iridium, cosmic string, deflect",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio || tech.isBlockRadiation || tech.isDroneRadioactive
- },
- requires: "radiation damage source",
- effect() {
- tech.radioactiveDamage += 1.47
- },
- remove() {
- tech.radioactiveDamage = 1
- }
- },
- {
- name: "water shielding",
- link: `
water shielding`,
- description: "
radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio
- },
- requires: "neutron bomb, irradiated drones, iridium-192",
- effect() {
- tech.isRadioactiveResistance = true
- },
- remove() {
- tech.isRadioactiveResistance = false
- }
- },
- {
- name: "ricochet",
- description: "after
nails hit a mob they
rebound towards
a new mob with
+180% damage per bounce",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines"))
- return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles)
- },
- //
- requires: "nail gun, not rotary cannon, rivets, or needles",
- effect() {
- tech.isRicochet = true
- },
- remove() {
- tech.isRicochet = false
- }
- },
- {
- name: "booby trap",
- description: "
50% chance to drop a
mine from
power ups+36% JUNK to
tech pool",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("mine")
- },
- requires: "mines",
- effect() {
- tech.isMineDrop = true;
- if (tech.isMineDrop) b.mine(m.pos, {
- x: 0,
- y: 0
- }, 0)
- this.refundAmount += tech.addJunkTechToPool(0.36)
- },
- refundAmount: 0,
- remove() {
- tech.isMineDrop = false;
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
- }
- }
- },
- {
- name: "elephants toothpaste",
- description: "instead of nails
mines catalyze a reaction
that yields
foam bubbles",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("mine") && !tech.isSuperMine && !tech.isRicochet && !tech.isNailRadiation && !tech.isNailCrit
- },
- requires: "mines, not blast ball, ricochet, irradiated nails, supercritical fission",
- effect() {
- tech.isFoamMine = true;
- },
- remove() {
- tech.isFoamMine = false;
- }
- },
- {
- name: "blast ball",
- descriptionFunction() {
- return `instead of nails
mines fire
bouncy balls`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("mine") && !tech.isFoamMine && !tech.isRicochet && !tech.isNailRadiation && !tech.isNailCrit
- },
- requires: "mines, not elephants toothpaste, ricochet, irradiated nails, supercritical fission",
- effect() {
- tech.isSuperMine = true;
- },
- remove() {
- tech.isSuperMine = false;
- }
- },
- {
- name: "laser-mines",
- link: `
laser-mines`,
- description: "
mines laid while you are
croucheduse
energy to emit
3 unaimed
lasers",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("mine")
- },
- requires: "mines",
- effect() {
- tech.isLaserMine = true;
- },
- remove() {
- tech.isLaserMine = false;
- }
- },
- {
- name: "sentry",
- descriptionFunction() {
- return `
mines fire one ${b.guns[10].nameString()} at a time
mines fire
50% more ${b.guns[10].nameString('s')}`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("mine") && !tech.isFoamMine
- },
- requires: "mines, not elephants toothpaste",
- effect() {
- tech.isMineSentry = true;
- },
- remove() {
- tech.isMineSentry = false;
- }
- },
- {
- name: "extended magazine",
- descriptionFunction() {
- return `sentry
mines fire
50% more ${b.guns[10].nameString('s')}`
- },
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("mine") && tech.isMineSentry
- },
- requires: "mines, sentry",
- effect() {
- tech.sentryAmmo += 17;
- },
- remove() {
- tech.sentryAmmo = 33;
- }
- },
- {
- name: "mycelial fragmentation",
- link: `
mycelial fragmentation`,
- description: "during their
growth phase
+70% sporangium discharge",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("spores")
- },
- requires: "spores",
- effect() {
- tech.isSporeGrowth = true
- },
- remove() {
- tech.isSporeGrowth = false
- }
- },
- {
- name: "cordyceps",
- // descriptionFunction() {
- // return `mobs infected by ${b.guns[6].nameString('s')} have a
5% chance
to
resurrect and attack other mobs`
- // },
- description: "
sporangium infect mobs they attach to
infected mobs
resurrect and attack other mobs",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("spores")
- },
- requires: "spores",
- effect() {
- tech.isZombieMobs = true
- },
- remove() {
- tech.isZombieMobs = false
- }
- },
- {
- name: "colony",
- description: "
+50% sporangium discharge
40% chance to discharge something different",
- link: `
colony`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("spores")
- },
- requires: "spores",
- effect() {
- tech.isSporeColony = true
- },
- remove() {
- tech.isSporeColony = false
- }
- },
- {
- name: "cryodesiccation",
- descriptionFunction() {
- return `
+25% sporangium discharge
${b.guns[6].nameString('s')}
freeze mobs for
1.5 second`
- },
- // description: "
+25% sporangium discharge
spores freeze mobs for
1.5 second",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
- },
- requires: "spores",
- effect() {
- tech.isSporeFreeze = true
- },
- remove() {
- tech.isSporeFreeze = false
- }
- },
- {
- name: "flagella",
- descriptionFunction() {
- return `
+50% ${b.guns[6].nameString()} acceleration
if they can't find a target ${b.guns[6].nameString('s')} follow you`
- },
- // description: "
+50% spore acceleration
if they can't find a target
spores follow you",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
- },
- requires: "spores",
- effect() {
- tech.isSporeFollow = true
- },
- remove() {
- tech.isSporeFollow = false
- }
- },
- {
- name: "junk DNA",
- descriptionFunction() {
- return `
+53% ${b.guns[6].nameString()}
damage per
JUNKtech (${(53*tech.junkCount).toFixed(0)}%)+50% JUNK to
tech pool`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
- },
- requires: "spores",
- effect() {
- tech.isJunkDNA = true
- this.refundAmount += tech.addJunkTechToPool(0.5)
- },
- refundAmount: 0,
- remove() {
- tech.isJunkDNA = false
- if (this.count > 0 && this.refundAmount > 0) {
- tech.removeJunkTechFromPool(this.refundAmount)
- this.refundAmount = 0
- }
- }
- },
- // {
- // name: "junk DNA",
- // //increase damage by 10% for each JUNK tech percent in the tech pool, remove all JUNK tech,
- // descriptionFunction() { return `
+50% ${b.guns[6].nameString()}
damage+15% JUNK to
tech pool` },
- // isGunTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 3,
- // frequencyDefault: 3,
- // allowed() {
- // return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
- // },
- // requires: "spores",
- // effect() {
- // tech.isSporeWorm = true
- // this.refundAmount += tech.addJunkTechToPool(0.15)
- // },
- // refundAmount: 0,
- // remove() {
- // tech.isSporeWorm = false
- // if (this.count > 0 && this.refundAmount > 0) {
- // tech.removeJunkTechFromPool(this.refundAmount)
- // this.refundAmount = 0
- // }
- // }
- // },
- {
- name: "mutualism",
- descriptionFunction() {
- return `
+200% ${b.guns[6].nameString()}
damage${b.guns[6].nameString('s')} borrow
1 health until they
die`
- },
- // description: `
+150% ${b.guns[6].name()}
damagespores borrow
0.5 health until they
die`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0)) || tech.isSporeWorm || tech.isSporeFlea
- },
- requires: "spores",
- effect() {
- tech.isMutualism = true
- },
- remove() {
- tech.isMutualism = false
- }
- },
- {
- name: "necrophage",
- description: "if
foam,
fleas, or
worms kill their target
they grow 3
copies",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine
- },
- requires: "foam, spores, worms, fleas",
- effect() {
- tech.isSpawnBulletsOnDeath = true
- },
- remove() {
- tech.isSpawnBulletsOnDeath = false;
- }
- },
- {
- name: "siphonaptera",
- description: "
sporangium and
shotgun hatch
fleas",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeWorm
- },
- requires: "spores, not worms",
- effect() {
- tech.isSporeFlea = true
- },
- remove() {
- tech.isSporeFlea = false
-
- }
- },
- {
- name: "nematodes",
- description: "
shotgun and
sporangium hatch
worms",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeFlea
- },
- requires: "spores, not fleas",
- effect() {
- tech.isSporeWorm = true
- },
- remove() {
- tech.isSporeWorm = false
- }
- },
- {
- name: "K-selection",
- description: "
+37% worm and
flea damage",
- isGunTech: true,
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isSporeWorm || tech.isSporeFlea
- },
- requires: "spores, shotgun, worms, fleas",
- effect() {
- tech.wormSize++
- },
- remove() {
- tech.wormSize = 0
- }
- },
- {
- name: "path integration",
- descriptionFunction() {
- return `
drones and ${b.guns[6].nameString("s")}
travel with you through
levels`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.isSporeFollow && (tech.haveGunCheck("spores") || (tech.haveGunCheck("shotgun") && tech.isSporeWorm))) || tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && (simulation.molecularMode === 0 || simulation.molecularMode === 3))
- },
- requires: "spores, worms, flagella, drones",
- effect() {
- tech.isDronesTravel = true
- },
- remove() {
- tech.isDronesTravel = false
- }
- },
- {
- name: "reduced tolerances",
- link: `
reduced tolerances`,
- description: `
+66% drones per ${powerUps.orb.ammo()} and
energy–40% drone
duration`,
- isGunTech: true,
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isDroneRadioactive && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3))
- },
- requires: "drones, not irradiated drones",
- effect() {
- tech.droneCycleReduction = Math.pow(0.6, 1 + this.count)
- tech.droneEnergyReduction = Math.pow(0.333, 1 + this.count)
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "drones") {
- const scale = Math.pow(3, this.count + 1)
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * scale
+ //remove options that don't meet requirements
+ for (let i = options.length - 1; i > -1; i--) {
+ const index = options[i]
+ if (!(tech.tech[index].count < tech.tech[index].maxCount) || !tech.tech[index].allowed()) {
+ options.splice(i, 1);
}
}
- },
- remove() {
- tech.droneCycleReduction = 1
- tech.droneEnergyReduction = 1
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ //pick one option
+ if (options.length) {
+ const index = options[Math.floor(Math.random() * options.length)]
+ simulation.makeTextLog(`
tech.giveTech("
${tech.tech[index].name}")
//optical amplifier`, 360);
+ tech.giveTech(index)
+ techGiven++
}
}
- },
- {
- name: "delivery drone",
- description: "if a
drone picks up a
power up,
it becomes
larger,
faster, and more
durable",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3)
- },
- requires: "drones",
- effect() {
- tech.isDroneGrab = true
- },
- remove() {
- tech.isDroneGrab = false
- }
- },
- {
- name: "drone repair",
- link: `
drone repair`,
- description: "after a
drone expires it
redeploysfor a
20% chance to use
1 drone ammo",
- // description: "broken
drones repair if the drone
gun is active
repairing has a
25% chance to use
1 drone",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("drones")
- },
- requires: "drones",
- effect() {
- tech.isDroneRespawn = true
- },
- remove() {
- tech.isDroneRespawn = false
- }
- },
- {
- name: "brushless motor",
- description: "
drones rapidly
rush towards their target
+33% drone collision
damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3)) && !tech.isDroneRadioactive && !tech.isIncendiary
- },
- requires: "drones, molecular assembler, not irradiated drones, incendiary",
- effect() {
- tech.isDroneTeleport = true
- },
- remove() {
- tech.isDroneTeleport = false
- }
- },
- {
- name: "axial flux motor",
- description: "
+66% drones rush frequency
+44% drone collision
damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isDroneTeleport
- },
- requires: "drones, brushless motor",
- effect() {
- tech.isDroneFastLook = true
- },
- remove() {
- tech.isDroneFastLook = false
- }
- },
- {
- name: "irradiated drones",
- link: `
irradiated drones`,
- description: `the space around
drones is
irradiated–75% drones per ${powerUps.orb.ammo()} and
energy`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.droneCycleReduction === 1 && !tech.isIncendiary && !tech.isDroneTeleport && (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 3))
- },
- requires: "drones, not reduced tolerances, incendiary, torque bursts",
- effect() {
- tech.isDroneRadioactive = true
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "drones") {
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.25
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.25)
- simulation.makeGunHUD();
- }
- }
- },
- remove() {
- if (tech.isDroneRadioactive) {
- tech.isDroneRadioactive = false
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "drones") {
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
- b.guns[i].ammo = b.guns[i].ammo * 4
- simulation.makeGunHUD();
+ if (techGiven > 0) {
+ tech.isStuckOn = true
+ } else { //eject if none found
+ simulation.makeTextLog(`0
tech found
//optical amplifier`);
+ const loop = () => {
+ if (!simulation.paused && m.alive) {
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].name === this.name) powerUps.ejectTech(i)
}
+ return
}
+ requestAnimationFrame(loop);
}
+ requestAnimationFrame(loop);
}
},
- {
- name: "beta radiation", //"control rod ejection",
- description: "
–50% drone duration
+100% drone radiation damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isDroneRadioactive
- },
- requires: "drones, irradiated drones",
- effect() {
- tech.droneRadioDamage = 2
- },
- remove() {
- tech.droneRadioDamage = 1
+ remove() {
+ tech.isStuckOn = false
+ }
+ },
+ {
+ name: "relativistic momentum",
+ description: "
lasers push
mobs and
blocks",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade
+ },
+ requires: "laser, not pulse",
+ effect() {
+ tech.isLaserPush = true;
+ },
+ remove() {
+ tech.isLaserPush = false;
+ }
+ },
+ {
+ name: "iridescence",
+ // description: "if a
laser hits a mob at a low angle of illumination
+66% laser damage",
+ description: "if
laser beams hit mobs near their
center+100% laser damage",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade || tech.isLaserMine
+ },
+ requires: "laser, not pulse",
+ effect() {
+ tech.laserCrit += 1;
+ },
+ remove() {
+ tech.laserCrit = 0;
+ }
+ },
+ {
+ name: "lens",
+ description: "
+150% laser gun damage if it passes
through a revolving
90° arc circular lens", //
π / 2
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser")
+ },
+ requires: "laser",
+ effect() {
+ tech.isLaserLens = true
+ b.guns[11].chooseFireMethod()
+ // if (this.count > 0) b.guns[11].lensDamageOn += 20 * Math.PI / 180
+ // b.guns[11].arcRange = 0.78
+ },
+ remove() {
+ tech.isLaserLens = false
+ b.guns[11].chooseFireMethod()
+ // b.guns[11].lensDamageOn = 2.5 // 100% + 150%
+ // b.guns[11].arcRange = 0
+ }
+ },
+ {
+ name: "compound lens",
+ description: "
+50% laser lens
damage+15° lens arc",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.isLaserLens
+ },
+ requires: "lens",
+ effect() {
+ b.guns[11].arcRange += 15 * Math.PI / 180 / 2
+ b.guns[11].lensDamageOn += 0.5
+ },
+ remove() {
+ b.guns[11].arcRange = 90 * Math.PI / 180 / 2 //0.78 divded by 2 because of how it's drawn
+ b.guns[11].lensDamageOn = 2.5
+ }
+ },
+ {
+ name: "specular reflection",
+ description: "
+2 laser beam reflections",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade) && !tech.isWideLaser && !tech.isPulseLaser && !tech.historyLaser
+ },
+ requires: "laser, not diffuse beam, pulse, or slow light",
+ effect() {
+ tech.laserReflections += 2;
+ },
+ remove() {
+ tech.laserReflections = 2;
+ }
+ },
+ {
+ name: "diffraction grating",
+ description: `
+1 diverging
laser gun beam`,
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.historyLaser
+ },
+ requires: "laser gun, diffuse beam, or slow light",
+ effect() {
+ tech.beamSplitter++
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.beamSplitter !== 0) {
+ tech.beamSplitter = 0
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ {
+ name: "diffuse beam",
+ link: `
diffuse beam`,
+ description: "
laser gun beam is
wider and doesn't
reflect+220% laser damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isPulseLaser && !tech.historyLaser
+ },
+ requires: "laser gun, not specular reflection, diffraction grating, slow light, pulse",
+ effect() {
+ if (tech.wideLaser === 0) tech.wideLaser = 3
+ tech.isWideLaser = true;
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.isWideLaser) {
+ // tech.wideLaser = 0
+ tech.isWideLaser = false;
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ {
+ name: "output coupler",
+ description: "
+30% laser gun beam
width+30% laser damage",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.isWideLaser
+ },
+ requires: "laser gun, diffuse beam",
+ effect() {
+ tech.wideLaser += 2
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.isWideLaser) {
+ tech.wideLaser = 3
+ } else {
+ tech.wideLaser = 0
+ }
+ b.guns[11].chooseFireMethod()
+ }
+ },
+ {
+ name: "slow light",
+ description: "
laser gun beam is
spread into your recent
past+300% total beam
damage",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isWideLaser
+ },
+ requires: "laser gun, not specular reflection, diffraction grating, diffuse beam",
+ effect() {
+ // this.description = `add 5 more
laser beams into into your past`
+ tech.historyLaser++
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.historyLaser) {
+ tech.historyLaser = 0
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ {
+ name: "infrared diode",
+ description: "
+60% laser energy efficiency
infrared light is outside visual perception",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && !tech.isPulseLaser && tech.laserDrain === 0.0018
+ },
+ requires: "laser, not free-electron, pulse",
+ effect() {
+ tech.laserDrain *= 0.4; //100%-50%
+ tech.laserColor = "transparent" //"rgb(255,0,20,0.02)"
+ // tech.laserColorAlpha = "rgba(255,0,20,0.05)"
+ },
+ remove() {
+ tech.laserDrain = 0.0018;
+ tech.laserColor = "#f02"
+ tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
+ }
+ },
+ {
+ name: "dye laser",
+ description: "
+25% laser energy efficiency
+25% laser damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade) && !tech.isPulseLaser && tech.laserDrain === 0.0018
+ },
+ requires: "laser, not pulse, infrared diode",
+ effect() {
+ tech.laserDrain *= 0.75
+ tech.laserDamage *= 1.25
+ tech.laserColor = "rgb(0, 11, 255)"
+ tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
+ },
+ remove() {
+ tech.laserDrain = 0.0018;
+ tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
+ tech.laserColor = "#f00"
+ tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
+ }
+ },
+ {
+ name: "free-electron laser",
+ description: "
–250% laser energy efficiency
+200% laser damage",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade) && !tech.isPulseLaser && tech.laserDrain === 0.0018
+ },
+ requires: "laser, not pulse, infrared diode",
+ effect() {
+ tech.laserDrain *= 1 + 2.5 //250% more drain
+ tech.laserDamage *= 1 + 2 //190% more damage
+ tech.laserColor = "#83f"
+ tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
+ },
+ remove() {
+ tech.laserDrain = 0.0018;
+ tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
+ tech.laserColor = "#f00"
+ tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
+ }
+ },
+ {
+ name: "pulse",
+ description: "charge your
energy and release it as a
laser pulse that initiates an
explosion cluster",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDrain === 0.0018 && !tech.isStuckOn
+ },
+ requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
+ effect() {
+ tech.isPulseLaser = true;
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.isPulseLaser) {
+ tech.isPulseLaser = false;
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ //**************************************************
+ //************************************************** field
+ //************************************************** tech
+ //**************************************************
+ {
+ name: "zero point energy",
+ description: `use ${powerUps.orb.research(2)}
+100 maximum
energy`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation") && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "standing wave, pilot wave, time dilation",
+ effect() {
+ tech.harmonicEnergy = 1
+ m.setMaxEnergy()
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
- {
- name: "orthocyclic winding",
- link: `
orthocyclic winding`,
- description: "
+66% drone acceleration
+33% radiation damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isDroneRadioactive
- },
- requires: "drones, irradiated drones",
- effect() {
- tech.isFastDrones = true
- },
- remove() {
- tech.isFastDrones = false
+ remove() {
+ tech.harmonicEnergy = 0;
+ m.setMaxEnergy()
+ if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "spherical harmonics",
+ description: "
+40% standing wave deflection efficiency
no longer deactivates on mob
shields", //
standing wave oscillates in a 3rd dimension
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "standing wave"
+ },
+ requires: "standing wave",
+ effect() {
+ tech.harmonics++
+ m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.6) * Math.pow(0.6, (tech.harmonics - 2))
+ m.harmonicShield = m.harmonicAtomic
+ },
+ remove() {
+ tech.harmonics = 2
+ m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.6) * Math.pow(0.6, (tech.harmonics - 2))
+ m.harmonicShield = m.harmonic3Phase
+ }
+ },
+ {
+ name: "expansion",
+ description: "
+50% standing wave deflection efficiency
using
standing wave field
expands its
radius",
+ // description: "use
energy to
expand standing wavethe field slowly
contracts when not used",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "standing wave"
+ },
+ requires: "standing wave",
+ effect() {
+ tech.isStandingWaveExpand = true
+ m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.3) * Math.pow(0.6, (tech.harmonics - 2))
+ },
+ remove() {
+ tech.isStandingWaveExpand = false
+ m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.3) * Math.pow(0.6, (tech.harmonics - 2))
+ m.harmonicRadius = 1
+ }
+ },
+ {
+ name: "triple point",
+ descriptionFunction() {
+ return `
+1.5 second
ice IX freeze effect
spawn ${powerUps.orb.coupling(10)} that each give
+0.1 coupling` //
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}
+ },
+ isFieldTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
+ },
+ requires: "standing wave, perfect diamagnetism",
+ effect() {
+ tech.iceIXFreezeTime += 90
+ powerUps.spawnDelay("coupling", 10)
+ },
+ remove() {
+ tech.iceIXFreezeTime = 150
+ if (this.count) {
+ m.couplingChange(-this.count)
+ }
+ }
+ },
+ {
+ name: "bremsstrahlung",
+ description: "
deflecting and thrown
blocksdo braking
damage to mobs",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
+ },
+ requires: "standing wave, perfect diamagnetism, pilot wave",
+ effect() {
+ tech.blockDmg += 3 //if you change this value also update the for loop in the electricity graphics in m.pushMass
+ },
+ remove() {
+ tech.blockDmg = 0;
+ }
+ },
+ {
+ name: "cherenkov radiation", //
deflecting and
blocks
+ description: "bremsstrahlung's effects are
radioactive+300% damage over
6 seconds",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && tech.blockDmg
+ },
+ requires: "bremsstrahlung",
+ effect() {
+ tech.isBlockRadiation = true
+ },
+ remove() {
+ tech.isBlockRadiation = false;
+ }
+ },
+ {
+ name: "flux pinning",
+ description: "after
deflecting a mob
it is
stunned for up to
4 seconds",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
+ },
+ requires: "a field that can block",
+ effect() {
+ tech.isStunField += 240;
+ },
+ remove() {
+ tech.isStunField = 0;
+ }
+ },
+ {
+ name: "eddy current brake",
+ description: "perfect diamagnetism
slows nearby mobs
effect
radius scales with stored
energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
+ },
+ requires: "perfect diamagnetism",
+ effect() {
+ tech.isPerfectBrake = true;
+ },
+ remove() {
+ tech.isPerfectBrake = false;
+ }
+ },
+ {
+ name: "Meissner effect",
+ description: "
+55% perfect diamagnetism
radius+22° perfect diamagnetism circular
arc",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
+ },
+ requires: "perfect diamagnetism",
+ effect() {
+ tech.isBigField = true;
+ },
+ remove() {
+ tech.isBigField = false;
+ }
+ },
+ {
+ name: "tessellation",
+ description: `use ${powerUps.orb.research(2)}
+50% defense`,
+ // description: "use
4 researchreduce
defense by
50%",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "negative mass") && (build.isExperimentSelection || powerUps.research.count > 3)
+ },
+ requires: "perfect diamagnetism, negative mass, pilot wave",
+ effect() {
+ tech.isFieldHarmReduction = true
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
- {
- name: "fault tolerance",
- description: `use ${powerUps.orb.research(2)}to trade your
drone gunfor
5 drones that last
forever`,
- isGunTech: true,
- isRemoveGun: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.isBulletsLastLonger === 1 && !tech.isDronesTravel && (build.isExperimentSelection || powerUps.research.count > 1)
- },
- requires: "drones, not drone repair, anti-shear topology, autonomous navigation",
- effect() {
- const num = 5
- tech.isForeverDrones += num
- if (tech.haveGunCheck("drones", false)) b.removeGun("drones")
- //spawn drones
- if (tech.isDroneRadioactive) {
- for (let i = 0; i < num * 0.25; i++) {
- b.droneRadioactive({
- x: m.pos.x + 30 * (Math.random() - 0.5),
- y: m.pos.y + 30 * (Math.random() - 0.5)
- }, 5)
- bullet[bullet.length - 1].endCycle = Infinity
- }
- } else {
- for (let i = 0; i < num; i++) {
- b.drone({
- x: m.pos.x + 30 * (Math.random() - 0.5),
- y: m.pos.y + 30 * (Math.random() - 0.5)
- }, 5)
- bullet[bullet.length - 1].endCycle = Infinity
- }
+ remove() {
+ tech.isFieldHarmReduction = false
+ if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "radiative equilibrium",
+ description: "after losing
health+200% damage for
10 seconds",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass"
+ },
+ requires: "negative mass, pilot wave",
+ effect() {
+ tech.isHarmDamage = true;
+ },
+ remove() {
+ tech.isHarmDamage = false;
+ }
+ },
+ {
+ name: "dynamic equilibrium",
+ descriptionFunction() {
+ return `increase
damage by your
defense and
5% of your last ${tech.isEnergyHealth ? "
energy" : "
health"} loss
(+${(100 * Math.max(5, tech.lastHitDamage) * m.lastHit * (2 - m.defense())).toFixed(0)}% damage)`
+ }, // =
+${10*m.defense()}%
+ // descriptionFunction() { return `increase
damage by your last ${tech.isEnergyHealth ? "
energy" : "
health"} loss
(${(tech.lastHitDamage).toFixed(0)}%)(${(100*m.lastHit).toFixed(0)} ${tech.isEnergyHealth ? "energy" : "health"})(${2 - m.defense()} defense) = ${(100*tech.lastHitDamage * m.lastHit * (2 - m.defense())).toFixed(0)}% damage ` }, // =
+${10*m.defense()}%
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "standing wave") && !tech.isCloakHealLastHit
+ },
+ requires: "negative mass, pilot wave, standing wave, not patch",
+ effect() {
+ tech.lastHitDamage += 5;
+ },
+ remove() {
+ tech.lastHitDamage = 0;
+ }
+ },
+ {
+ name: "neutronium",
+ description: `
move and
jump 20% slowerif your
field is active
+90% defense`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "negative mass"
+ },
+ requires: "negative mass",
+ effect() {
+ tech.isNeutronium = true
+ tech.baseFx *= 0.8
+ tech.baseJumpForce *= 0.8
+ m.setMovement()
+ },
+ //also removed in m.setHoldDefaults() if player switches into a bad field
+ remove() {
+ tech.isNeutronium = false
+ if (!tech.isFreeWormHole) {
+ tech.baseFx = 0.08
+ tech.baseJumpForce = 10.5
+ m.setMovement()
+ }
+ }
+ },
+ {
+ name: "aerostat",
+ description: `
+88% damage while
off the
ground-22% damage while
on the
ground`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "negative mass"
+ },
+ requires: "negative mass",
+ effect() {
+ tech.isNoGroundDamage = true
+ },
+ remove() {
+ tech.isNoGroundDamage = false
+ }
+ },
+ {
+ name: "annihilation",
+ description: "after
colliding with non-boss mobs
they are
annihilated and
–33% energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "negative mass" && !tech.isEnergyHealth
+ },
+ requires: "negative mass, not mass-energy",
+ effect() {
+ tech.isAnnihilation = true
+ },
+ remove() {
+ tech.isAnnihilation = false;
+ }
+ },
+ {
+ name: "inertial mass",
+ description: "
negative mass is larger and
fasterblocks also move
horizontally with the field",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "negative mass"
+ },
+ requires: "negative mass",
+ effect() {
+ tech.isFlyFaster = true
+ },
+ remove() {
+ tech.isFlyFaster = false;
+ }
+ },
+ // {
+ // name: "Bose Einstein condensate",
+ // description: "use
energy to
freeze mobs in your
fieldpilot wave, negative mass, time dilation",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || (m.fieldUpgrades[m.fieldMode].name === "time dilation" && !tech.isRewindField)
+ // },
+ // requires: "pilot wave, negative mass, time dilation, not retrocausality",
+ // effect() {
+ // tech.isFreezeMobs = true
+ // },
+ // remove() {
+ // tech.isFreezeMobs = false
+ // }
+ // },
+ {
+ name: "bot manufacturing",
+ description: `use ${powerUps.orb.research(1)} to build
3 random
bots`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ isNonRefundable: true,
+ allowed() {
+ return powerUps.research.count > 0 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
+ },
+ requires: "molecular assembler, pilot wave",
+ effect() {
+ for (let i = 0; i < 1; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ m.energy = 0.01;
+ b.randomBot()
+ b.randomBot()
+ b.randomBot()
+ },
+ remove() { }
+ },
+ {
+ name: "bot prototypes",
+ description: `use ${powerUps.orb.research(2)}to build
2 random
botsand
upgrade all
bots to that type`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ isNonRefundable: true,
+ allowed() {
+ return powerUps.research.count > 1 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
+ },
+ requires: "molecular assembler, pilot wave",
+ effect() {
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ //fill array of available bots
+ const notUpgradedBots = []
+ const num = 2
+ notUpgradedBots.push(() => {
+ tech.giveTech("nail-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.nailBot()
+ tech.nailBotCount++;
}
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isForeverDrones = 0
- if (this.count && !tech.haveGunCheck("drones", false)) b.giveGuns("drones")
- if (this.count > 0) powerUps.research.changeRerolls(2)
- }
- },
- {
- name: "surfactant",
- description: `use ${powerUps.orb.research(2)}to trade your
foam gunfor
2 foam-bots and
foam-bot upgrade`,
- isGunTech: true,
- isRemoveGun: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- isNonRefundable: true,
- requires: "foam gun, not bot upgrades, fractionation, pressure vessel",
- allowed() {
- return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade() && !tech.isAmmoFoamSize && !tech.isFoamPressure && (build.isExperimentSelection || powerUps.research.count > 1)
- },
- effect() {
+ simulation.makeTextLog(`tech.isNailBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
tech.giveTech("foam-bot upgrade")
- for (let i = 0; i < 2; i++) {
+ for (let i = 0; i < num; i++) {
b.foamBot()
tech.foamBotCount++;
}
simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
- if (tech.haveGunCheck("foam", false)) b.removeGun("foam")
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("boom-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.boomBot()
+ tech.boomBotCount++;
+ }
+ simulation.makeTextLog(`tech.isBoomBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("laser-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.laserBot()
+ tech.laserBotCount++;
+ }
+ simulation.makeTextLog(`tech.isLaserBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("orbital-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.orbitBot()
+ tech.orbitBotCount++;
+ }
+ simulation.makeTextLog(`tech.isOrbitalBotUpgrade = true`)
+ })
+ for (let i = 0; i < 2; i++) { //double chance for dynamo-bot, since it's very good for assembler
+ notUpgradedBots.push(() => {
+ tech.giveTech("dynamo-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.dynamoBot()
+ tech.dynamoBotCount++;
+ }
+ simulation.makeTextLog(`tech.isDynamoBotUpgrade = true`)
+ })
+ }
+ notUpgradedBots[Math.floor(Math.random() * notUpgradedBots.length)]() //choose random function from the array and run it
+ },
+ remove() { }
+ },
+ // {
+ // name: "mycelium manufacturing",
+ // link: `
mycelium manufacturing`,
+ // // description: `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to grow
spores`,
+ // descriptionFunction() { return `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to grow ${b.guns[6].nameString('s')}` },
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
+ // },
+ // requires: "molecular assembler, no other manufacturing, no drone tech",
+ // effect() {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < 1; i++) {
+ // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ // }
+ // }
+ // tech.isSporeField = true;
+ // },
+ // remove() {
+ // tech.isSporeField = false;
+ // if (this.count > 0) powerUps.research.changeRerolls(1)
+ // }
+ // },
+ // {
+ // name: "missile manufacturing",
+ // link: `
missile manufacturing`,
+ // description: `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to construct
missiles`,
+ // // description: "use
3 research to repurpose
assemblerexcess
energy used to construct
missiles",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
+ // },
+ // requires: "molecular assembler, no other manufacturing, no drone tech",
+ // effect() {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < 1; i++) {
+ // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ // }
+ // }
+ // tech.isMissileField = true;
+ // },
+ // remove() {
+ // tech.isMissileField = false;
+ // if (this.count > 0) powerUps.research.changeRerolls(1)
+ // }
+ // },
+ // {
+ // name: "ice IX manufacturing",
+ // link: `
ice IX manufacturing`,
+ // description: `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to condense
ice IX`,
+ // // description: "use
3 research to repurpose
assemblerexcess
energy used to condense
ice IX",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
+ // },
+ // requires: "molecular assembler, no other manufacturing, no drone tech",
+ // effect() {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < 1; i++) {
+ // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ // }
+ // }
+ // tech.isIceField = true;
+ // },
+ // remove() {
+ // tech.isIceField = false;
+ // if (this.count > 0) powerUps.research.changeRerolls(1)
+ // }
+ // },
+ {
+ name: "pair production",
+ description: "after picking up a
power up+200 energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
+ },
+ requires: "molecular assembler, pilot wave, standing wave",
+ effect() {
+ tech.isMassEnergy = true // used in m.grabPowerUp
+ m.energy += 2
+ },
+ remove() {
+ tech.isMassEnergy = false;
+ }
+ },
+ {
+ name: "electric generator",
+ description: "after
deflecting mobs
molecular assembler generates
+50 energy",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
+ },
+ requires: "molecular assembler",
+ effect() {
+ tech.deflectEnergy += 0.5;
+ },
+ remove() {
+ tech.deflectEnergy = 0;
+ }
+ },
+ {
+ name: "combinatorial optimization",
+ description: "
+35% damage–35% fire rate",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
+ },
+ requires: "cloaking, molecular assembler, plasma torch, pilot wave",
+ damage: 1.35,
+ effect() {
+ tech.damage *= this.damage
+ tech.aimDamage = 1.35
+ b.setFireCD();
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.aimDamage = 1
+ b.setFireCD();
+ }
+ },
+ {
+ name: "tokamak",
+ description: "throwing a
block converts it into
energyand a pulsed fusion
explosion",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
+ },
+ requires: "plasma torch, molecular assembler",
+ effect() {
+ tech.isTokamak = true;
+ },
+ remove() {
+ tech.isTokamak = false;
+ }
+ },
+ {
+ name: "degenerate matter",
+ description: "if your
field is active
+75% defense",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
+ },
+ requires: "molecular assembler, plasma torch, perfect diamagnetism, pilot wave",
+ effect() {
+ tech.isHarmReduce = true
+ },
+ remove() {
+ tech.isHarmReduce = false;
+ }
+ },
+ {
+ name: "plasma-bot",
+ link: `
plasma-bot`,
+ description: `use ${powerUps.orb.research(2)}to trade your
fieldfor a
bot that uses
energy to emit
plasma`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall && !tech.isExtruder && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "plasma torch, not extruder, plasma ball",
+ effect() {
+ tech.plasmaBotCount++;
+ b.plasmaBot();
+ if (build.isExperimentSelection) {
+ document.getElementById("field-" + m.fieldMode).classList.remove("build-field-selected");
+ document.getElementById("field-0").classList.add("build-field-selected");
+ }
+ m.setField("field emitter")
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ if (this.count > 0) {
+ tech.plasmaBotCount = 0;
+ b.clearPermanentBots();
+ b.respawnBots();
+ if (m.fieldMode === 0) {
+ m.setField("plasma torch")
+ if (build.isExperimentSelection) {
+ document.getElementById("field-0").classList.remove("build-field-selected");
+ document.getElementById("field-" + m.fieldMode).classList.add("build-field-selected");
+ }
+ }
+ powerUps.research.changeRerolls(2)
+ }
+ }
+ },
+ {
+ name: "plasma jet",
+ link: `
plasma jet`,
+ description: `use ${powerUps.orb.research(2)}
+50% plasma torch range`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.plasmaBotCount || m.fieldUpgrades[m.fieldMode].name === "plasma torch") && (build.isExperimentSelection || powerUps.research.count > 1) && !tech.isPlasmaBall
+ },
+ requires: "plasma torch, not plasma ball",
+ effect() {
+ tech.isPlasmaRange += 0.5;
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isPlasmaRange = 1;
+ if (this.count > 0) powerUps.research.changeRerolls(this.count * 2)
+ }
+ },
+ {
+ name: "extruder",
+ description: "
extrude a thin hot wire of
plasmaincreases
damage and
energy drain",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall
+ },
+ requires: "plasma torch, not plasma ball",
+ effect() {
+ tech.isExtruder = true;
+ m.fieldUpgrades[m.fieldMode].set()
+ },
+ remove() {
+ tech.isExtruder = false;
+ if (this.count && m.fieldUpgrades[m.fieldMode].name === "plasma torch") m.fieldUpgrades[m.fieldMode].set()
+ }
+ },
+ {
+ name: "refractory metal",
+ description: "
extrude metals at a higher
temperatureincreases effective
radius and
damage",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isExtruder
+ },
+ requires: "extruder",
+ effect() {
+ tech.extruderRange += 55
+ },
+ remove() {
+ tech.extruderRange = 15
+ }
+ },
+ {
+ name: "plasma ball",
+ description: "
grow an expanding
ball of
plasmaincreases
damage and
energy drain",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isExtruder && tech.isPlasmaRange === 1
+ },
+ requires: "plasma torch, not extruder, plasma jet",
+ effect() {
+ tech.isPlasmaBall = true;
+ m.fieldUpgrades[m.fieldMode].set()
+ },
+ remove() {
+ tech.isPlasmaBall = false;
+ if (this.count && m.fieldUpgrades[m.fieldMode].name === "plasma torch") m.fieldUpgrades[m.fieldMode].set()
+ }
+ },
+ {
+ name: "corona discharge",
+ description: "increase the
range and
frequencyof
plasma ball's
electric arc ",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isPlasmaBall
+ },
+ requires: "plasma ball",
+ effect() {
+ tech.plasmaDischarge += 0.03
+ },
+ remove() {
+ tech.plasmaDischarge = 0.01 //default chance per cycle of a discharge
+ }
+ },
+ {
+ name: "retrocausality",
+ description: "
time dilation uses
energy to
rewind your
health,
velocity, and
position up to
10 seconds",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "time dilation" && !m.isShipMode && !tech.isRewindAvoidDeath && !tech.isTimeSkip
+ },
+ requires: "time dilation, not CPT symmetry",
+ effect() {
+ tech.isRewindField = true;
+ m.fieldUpgrades[m.fieldMode].set()
+ m.wakeCheck();
+ },
+ remove() {
+ tech.isRewindField = false;
+ if (this.count) m.fieldUpgrades[m.fieldMode].set()
+ }
+ },
+ {
+ name: "frame-dragging", //"non-inertial frame",
+ description: "when not
moving time dilation
stops time+33% defense",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "time dilation"
+ },
+ requires: "time dilation",
+ effect() {
+ tech.isTimeStop = true;
+ m.fieldHarmReduction = 0.66; //33% reduction
+ },
+ remove() {
+ tech.isTimeStop = false;
+ if (m.fieldUpgrades[m.fieldMode].name === "time dilation") m.fieldHarmReduction = 1;
+ }
+ },
+ {
+ name: "Lorentz transformation",
+ description: `use ${powerUps.orb.research(3)}
+50% movement,
jumping, and
fire rate`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "time dilation") && (build.isExperimentSelection || powerUps.research.count > 2)
+ },
+ requires: "time dilation",
+ effect() {
+ tech.isFastTime = true
+ m.setMovement();
+ b.setFireCD();
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isFastTime = false
+ m.setMovement();
+ b.setFireCD();
+ if (this.count > 0) powerUps.research.changeRerolls(3)
+ }
+ },
+ {
+ name: "time crystals",
+ description: "
+200% passive
energy generation",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isGroundState && (m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
+ },
+ requires: "time dilation or pilot wave, not ground state",
+ effect() {
+ tech.isTimeCrystals = true
+ m.setFieldRegen()
+ },
+ remove() {
+ tech.isTimeCrystals = false
+ m.setFieldRegen()
+ }
+ },
+ {
+ name: "no-cloning theorem",
+ // descriptionFunction() { return `
+45% chance to
duplicate spawned
power upsafter a mob
dies –2% duplication (${tech.duplicationChance()})` },
+ description: `
+45% chance to
duplicate spawned
power upsafter a mob
dies –2% duplication`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking") && !tech.isQuantumEraser
+ },
+ requires: "cloaking, time dilation, not quantum eraser",
+ effect() {
+ tech.cloakDuplication = 0.45
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
+ },
+ remove() {
+ tech.cloakDuplication = 0
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "quantum eraser",
+ descriptionFunction() {
+ return `
for each mob left alive after you exit a level
kill a mob as they spawn at +${100 - 1.6 * simulation.difficultyMode ** 2}% duplication`
+ },
+ // description: `
for each mob left alive after you exit a level
kill a mob as they spawn at 100% duplication`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "time dilation") && !tech.cloakDuplication
+ },
+ requires: "cloaking or time dilation",
+ effect() {
+ tech.quantumEraserCount = 0
+ tech.isQuantumEraserDuplication = 0
+ tech.isQuantumEraser = true
+ },
+ remove() {
+ tech.quantumEraserCount = 0
+ tech.isQuantumEraserDuplication = 0
+ tech.isQuantumEraser = false
+ }
+ },
+ {
+ name: "symbiosis",
+ descriptionFunction() {
+ return `after a
boss dies spawn ${powerUps.orb.research(3)}${powerUps.orb.heal(3)} and a
techafter a
mob dies –0.5 maximum ${tech.isEnergyHealth ? "
energy" : "
health"}`
+ },
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" //|| m.fieldUpgrades[m.fieldMode].name === "time dilation"
+ },
+ requires: "cloaking",
+ effect() {
+ tech.isAddRemoveMaxHealth = true
+ },
+ remove() {
+ tech.isAddRemoveMaxHealth = false
+ }
+ },
+ {
+ name: "boson composite",
+ link: `
boson composite`,
+ description: "while
cloaked you are
intangibleto
blocks and mobs, but
mobs drain
energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
+ },
+ requires: "metamaterial cloaking",
+ effect() {
+ tech.isIntangible = true;
+ },
+ remove() {
+ if (tech.isIntangible) {
+ tech.isIntangible = false;
+ player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions
+ }
+ }
+ },
+ {
+ name: "patch",
+ link: `
patch`,
+ description: "after
cloaking recover
75% of your
last
health loss using that much
energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" && !tech.lastHitDamage && !tech.isEnergyHealth
+ },
+ requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy",
+ effect() {
+ tech.isCloakHealLastHit = true;
+ },
+ remove() {
+ tech.isCloakHealLastHit = false;
+ }
+ },
+ {
+ name: "dazzler",
+ link: `
dazzler`,
+ description: "after
decloaking stun nearby mobs
and drain
–15 energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
+ },
+ requires: "metamaterial cloaking",
+ effect() {
+ tech.isCloakStun = true;
+ },
+ remove() {
+ tech.isCloakStun = false;
+ }
+ },
+ // {
+ // name: "ambush",
+ // description: "metamaterial cloaking field
damage effect
is increased from
333% to
555%",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
+ // },
+ // requires: "metamaterial cloaking",
+ // effect() {
+ // tech.sneakAttackDmg = 6.55 //555% + 100%
+ // },
+ // remove() {
+ // tech.sneakAttackDmg = 4.33 //333% + 100%
+ // }
+ // },
+ {
+ name: "dynamical systems",
+ description: `use ${powerUps.orb.research(2)}
+35% damage`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "cloaking, pilot wave, or plasma torch",
+ damage: 1.35,
+ effect() {
+ tech.damage *= this.damage
+ tech.isCloakingDamage = true
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isCloakingDamage = false
+ if (this.count > 0) {
+ tech.damage /= this.damage
+ powerUps.research.changeRerolls(2)
+ }
+ }
+ },
+ {
+ name: "WIMPs",
+ description: `at the end of each
level spawn ${powerUps.orb.research(4)}
and a dangerous particle that slowly
chases you`,
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation"
+ },
+ requires: "wormhole, pilot wave, time dilation",
+ effect() {
+ tech.wimpCount++
+ spawn.WIMP()
+ for (let j = 0, len = 4; j < len; j++) powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false)
+ },
+ remove() {
+ tech.wimpCount = 0
+ }
+ },
+ {
+ name: "vacuum fluctuation",
+ description: `use ${powerUps.orb.research(4)}to exploit your
field for a
+11% chance to
duplicate spawned
power ups`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "wormhole") && (build.isExperimentSelection || powerUps.research.count > 3)
+ },
+ requires: "wormhole, time dilation, negative mass, pilot wave",
+ effect() {
+ tech.fieldDuplicate = 0.11
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
+ for (let i = 0; i < 4; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.fieldDuplicate = 0
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ if (this.count > 0) powerUps.research.changeRerolls(4)
+ }
+ },
+ // {
+ // name: "Penrose process",
+ // description: "after a
block falls into a
wormhole+50 energy",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return m.fieldUpgrades[m.fieldMode].name === "wormhole"
+ // },
+ // requires: "wormhole",
+ // effect() {
+ // tech.isWormholeEnergy = true
+ // },
+ // remove() {
+ // tech.isWormholeEnergy = false
+ // }
+ // },
+ {
+ name: "transdimensional worms",
+ link: `
transdimensional worms`,
+ description: "after a
block falls into a
wormholespawn a
worm",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole"
+ },
+ requires: "wormhole",
+ effect() {
+ tech.isWormholeWorms = true
+ },
+ remove() {
+ tech.isWormholeWorms = false
+ }
+ },
+ {
+ name: "geodesics",
+ description: `your
bullets can traverse
wormholesspawn 2
guns and ${powerUps.orb.ammo(4)}`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole"
+ },
+ requires: "wormhole",
+ effect() {
+ tech.isWormHoleBullets = true
+ for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 200 * (Math.random() - 0.5), m.pos.y + 200 * (Math.random() - 0.5), "gun");
+ for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + 200 * (Math.random() - 0.5), m.pos.y + 200 * (Math.random() - 0.5), "ammo");
+ },
+ remove() {
+ if (tech.isWormHoleBullets) {
for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
}
- },
- remove() {
- // if (this.count) {
- // b.clearPermanentBots();
- // b.respawnBots();
- // if (!tech.haveGunCheck("foam")) b.giveGuns("foam")
+ tech.isWormHoleBullets = false;
+ }
+ }
+ },
+ {
+ name: "cosmic string",
+ description: "after
tunneling through mobs with a
wormholestun them and do
radioactive damage",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole"
+ },
+ requires: "wormhole",
+ effect() {
+ tech.isWormholeDamage = true
+ },
+ remove() {
+ tech.isWormholeDamage = false
+ }
+ },
+ {
+ name: "invariant",
+ description: "while placing your
wormholeuse
energy to
pause time",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole" && !tech.isNoDraftPause
+ },
+ requires: "wormhole, not eternalism",
+ effect() {
+ tech.isWormHolePause = true
+ },
+ remove() {
+ if (tech.isWormHolePause && m.isBodiesAsleep) m.wakeCheck();
+ tech.isWormHolePause = false
+ }
+ },
+ {
+ name: "charmed baryons",
+ description: `
–33% movement and
jumpingwormholes drain
zero energy`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole" && !tech.isWormholeMapIgnore
+ },
+ requires: "wormhole, not affine connection",
+ effect() {
+ tech.isFreeWormHole = true
+ tech.baseFx *= 0.66
+ tech.baseJumpForce *= 0.66
+ m.setMovement()
+ },
+ //also removed in m.setHoldDefaults() if player switches into a bad field
+ remove() {
+ tech.isFreeWormHole = false
+ if (!tech.isNeutronium) {
+ tech.baseFx = 0.08
+ tech.baseJumpForce = 10.5
+ m.setMovement()
+ }
+ }
+ },
+ {
+ name: "affine connection",
+ description: "
wormholes can tunnel through
anythingfor
+200% energy drain",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "wormhole" && !tech.isFreeWormHole
+ },
+ requires: "wormhole, not charmed baryons",
+ effect() {
+ tech.isWormholeMapIgnore = true
+ },
+ remove() {
+ tech.isWormholeMapIgnore = false
+ }
+ },
+ //**************************************************
+ //************************************************** experimental
+ //************************************************** modes
+ //**************************************************
+ // {
+ // name: "-ship-",
+ // description: "
experiment: fly around with no legs
aim with the keyboard",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection && !m.isShipMode && m.fieldUpgrades[m.fieldMode].name !== "negative mass"
+ // },
+ // requires: "",
+ // effect() {
+ // m.shipMode()
+ // },
+ // remove() {}
+ // },
+ // {
+ // name: "-quantum leap-",
+ // description: "
experiment: every 20 seconds
become an
alternate version of yourself",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // interval: undefined,
+ // effect() {
+ // this.interval = setInterval(() => {
+ // if (!build.isExperimentSelection) {
+ // m.switchWorlds()
+ // simulation.trails()
+ // }
+ // }, 20000); //every 20 seconds
+
+ // },
+ // remove() {
+ // if (this.count > 0) clearTimeout(this.interval);
+ // }
+ // },
+ // {
+ // name: "-shields-",
+ // description: "
experiment: every 5 seconds
all mobs gain a shield",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // effect() {
+ // this.interval = setInterval(() => {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (!mob[i].isShielded && !mob[i].shield && mob[i].isDropPowerUp) spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
+ // }
+ // }
+ // }, 5000); //every 5 seconds
+ // },
+ // interval: undefined,
+ // remove() {
+ // if (this.count > 0) clearTimeout(this.interval);
+ // }
+ // },
+ // {
+ // name: "-Fourier analysis-",
+ // description: "
experiment: your aiming is random",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection && !m.isShipMode
+ // },
+ // requires: "not ship",
+ // effect() {
+ // m.look = () => {
+ // m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03)
+ // const scale = 0.8;
+ // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ // m.transX += (m.transSmoothX - m.transX) * 0.07;
+ // m.transY += (m.transSmoothY - m.transY) * 0.07;
+ // }
+ // },
+ // remove() {
+ // if (this.count > 0) m.look = m.lookDefault()
+ // }
+ // },
+ // {
+ // name: "-panopticon-",
+ // description: "
experiment: mobs can always see you",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // effect() {
+ // this.interval = setInterval(() => {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (!mob[i].shield && mob[i].isDropPowerUp) {
+ // mob[i].locatePlayer()
+ // mob[i].seePlayer.yes = true;
+ // }
+ // }
+ // }
+ // }, 1000); //every 1 seconds
+ // },
+ // interval: undefined,
+ // remove() {
+ // if (this.count > 0) clearTimeout(this.interval);
+ // }
+ // },
+ // {
+ // name: "-decomposers-",
+ // description: "
experiment: after they die
mobs leave behind spawns",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // effect() {
+ // tech.deathSpawns = 0.2
+ // },
+ // remove() {
+ // tech.deathSpawns = 0
+ // }
+ // },
+
+
+
+ //**************************************************
+ //************************************************** JUNK
+ //************************************************** tech
+ //**************************************************
+ // {
+ // name: "junk",
+ // description: "",
+ // maxCount: 9,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+
+ // },
+ // remove() {}
+ // },
+ {
+ name: "swap meet",
+ description: "normal
tech become
JUNKand
JUNK become normal
tech",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ tech.tech[i].isJunk = !tech.tech[i].isJunk
+ if (tech.tech[i].isJunk) { } else { }
+
+ if (tech.tech[i].frequency > 0) {
+ tech.tech[i].frequency = 0
+ } else {
+ tech.tech[i].frequency = 2
+ }
+ }
+ },
+ remove() { }
+ },
+ // {
+ // name: "pocket dimension",
+ // description: "rotate tech descriptions into a higher spacial dimension",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // isNonRefundable: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // document.getElementById("choose-grid").classList.add("flipX");
+ // },
+ // remove() {}
+ // },
+ {
+ name: "random",
+ link: `
random`,
+ delay: 333,
+ descriptionFunction() {
+ const delay = 333
+ const loop = () => {
+ if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) {
+ const dmg = Math.floor(27 * Math.random()) * 0.01
+ this.text = `
+${(dmg * 100).toFixed(0).padStart(2, '0')}% damage`
+ this.damage = 1 + dmg
+ if (document.getElementById(`damage-JUNK-id${this.id}`)) document.getElementById(`damage-JUNK-id${this.id}`).innerHTML = this.text
+ setTimeout(() => {
+ loop()
+ }, delay);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, delay);
+ this.id++
+ return `
${this.text}`
+ },
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ isJunk: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ damage: 0,
+ effect() {
+ tech.damage *= this.damage
+ },
+ remove() {
+ if (this.count > 0) tech.damage /= this.damage
+ }
+ },
+ {
+ name: "boost",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() {
+ powerUps.spawnDelay("boost", this.spawnCount)
+ },
+ remove() { },
+ id: 0,
+ text: "",
+ delay: 100,
+ spawnCount: 0,
+ descriptionFunction() {
+ let count = 9999 * Math.random()
+ const loop = () => {
+ if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0) //simulation.paused ||
+ count += 4.5
+ const waves = 2 * Math.sin(count * 0.0133) + Math.sin(count * 0.013) + 0.5 * Math.sin(count * 0.031) + 0.33 * Math.sin(count * 0.03)
+ this.spawnCount = Math.floor(100 * Math.abs(waves))
+ this.text = `spawn
${this.spawnCount.toLocaleString(undefined, { minimumIntegerDigits: 3 })} ${powerUps.orb.boost(1)}
that give
+${(powerUps.boost.damage * 100).toFixed(0)}% damage for
${(powerUps.boost.duration / 60).toFixed(0)} seconds`
+ if (document.getElementById(`boost-JUNK-id${this.id}`)) document.getElementById(`boost-JUNK-id${this.id}`).innerHTML = this.text
+ setTimeout(() => {
+ loop()
+ }, this.delay);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, this.delay);
+ this.id++
+ return `
${this.text}`
+ },
+ },
+ {
+ name: "placebo",
+ description: "
+777% damage+777% defense",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ if (Math.random() < 0.1) tech.damage *= 8.77
+ },
+ remove() { }
+ },
+ {
+ name: "universal healthcare",
+ description: "make your
damage negative",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.damage *= -1
+ },
+ remove() { }
+ },
+ // {
+ // name: "synchrotron",
+ // descriptionFunction() {
+ // return `
power ups change into a different
flavor after a boss dies`
+ // },
+ // maxCount: 3,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // allowed: () => true,
+ // requires: "",
+ // effect() {
+ // },
+ // remove() {
+ // }
+ // },
+ {
+ name: "return",
+ description: "return to the introduction level
reduce combat
difficulty by
2 levels",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ level.difficultyDecrease(simulation.difficultyMode * 2)
+ level.onLevel = 0
+ simulation.clearNow = true //end current level
+ },
+ remove() { }
+ },
+ {
+ name: "panpsychism",
+ description: "awaken all
blocksblocks have a chance to spawn power ups",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ setInterval(() => {
+ for (let i = body.length - 1; i > -1; i--) {
+ if (!body[i].isNotHoldable) {
+ Matter.Composite.remove(engine.world, body[i]);
+ spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0);
+ if (!body[i].isAboutToBeRemoved) mob[mob.length - 1].isDropPowerUp = true
+ body.splice(i, 1);
+ }
+ }
+ }, 6000);
+ },
+ remove() { }
+ },
+ {
+ name: "meteor shower",
+ description: "take a shower, but meteors instead of water",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ setInterval(() => {
+
+ fireBlock = function (xPos, yPos) {
+ const index = body.length
+ spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random());
+ const bodyBullet = body[index]
+ Matter.Body.setVelocity(bodyBullet, {
+ x: 5 * (Math.random() - 0.5),
+ y: 10 * (Math.random() - 0.5)
+ });
+ bodyBullet.isAboutToBeRemoved = true
+ bodyBullet.collisionFilter.category = cat.body;
+ bodyBullet.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ bodyBullet.classType = "body";
+ Composite.add(engine.world, bodyBullet); //add to world
+ setTimeout(() => { //remove block
+ for (let i = 0; i < body.length; i++) {
+ if (body[i] === bodyBullet) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ }
+ }
+ }, 4000 + Math.floor(9000 * Math.random()));
+ }
+ fireBlock(player.position.x + 600 * (Math.random() - 0.5), player.position.y - 500 - 500 * Math.random());
+ // for (let i = 0, len = Math.random(); i < len; i++) {
// }
- // if (this.count > 0) powerUps.research.changeRerolls(2)
- }
+
+ }, 1000);
},
- {
- name: "electrostatic induction",
- description: "
foam bubbles are electrically charged
causing
attraction to nearby
mobs",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isBulletTeleport && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)
- },
- requires: "foam, not uncertainty",
- effect() {
- tech.isFoamAttract = true
- },
- remove() {
- tech.isFoamAttract = false
- }
- },
- {
- name: "uncertainty principle",
- description: "
foam and
wave positions are erratic
+53% foam and
wave damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (!tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)) || (tech.haveGunCheck("wave") && !tech.is360Longitudinal)
- },
- requires: "foam, wave, not isotropic, electrostatic induction",
- effect() {
- tech.isBulletTeleport = true
- },
- remove() {
- tech.isBulletTeleport = false;
- }
- },
- {
- name: "aerogel",
- description: "
–50% foam duration and
foam bubbles
float+180% foam damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
- },
- requires: "foam",
- effect() {
- tech.isFastFoam = true
- tech.foamGravity = -0.0003
- },
- remove() {
- tech.isFastFoam = false;
- tech.foamGravity = 0.00008
- }
- },
- {
- name: "surface tension",
- description: "
+43% foam damage",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
- },
- requires: "foam",
- effect() {
- tech.foamDamage += 0.011 * 0.43
- },
- remove() {
- tech.foamDamage = 0.011;
- }
- },
- {
- name: "foam fractionation",
- description: "if you have below
300 ammo+100% foam gun bubble
size",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("foam")
- },
- requires: "foam",
- effect() {
- tech.isAmmoFoamSize = true
- },
- remove() {
- tech.isAmmoFoamSize = false;
- }
- },
- {
- name: "ideal gas law",
- description: `remove
all current
foam ammo+1200% foam ammo per ${powerUps.orb.ammo(1)}`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("foam") && !tech.isEnergyNoAmmo
- },
- requires: "foam, not non-renewables",
- ammoLost: 0,
- effect() {
- b.guns[8].ammoPack = b.guns[8].ammoPack * 12;
- this.ammoLost = b.guns[8].ammo
- b.guns[8].ammo = 0
- simulation.updateGunHUD()
- },
- remove() {
- b.guns[8].ammoPack = 24
- if (this.count) {
- b.guns[8].ammo += this.ammoLost
- simulation.updateGunHUD()
- }
- }
- },
- {
- name: "pressure vessel",
- description: "build up
charge while firing
foam gunafter firing
discharge foam bubbles",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("foam")
- },
- requires: "foam",
- effect() {
- tech.isFoamPressure = true;
- b.guns[8].chooseFireMethod()
- },
- remove() {
- tech.isFoamPressure = false;
- b.guns[8].chooseFireMethod()
- }
- },
- {
- name: "capacitor bank",
- // description: "
charge effects build up almost
instantlythrowing blocks, foam, railgun, pulse, tokamak",
- descriptionFunction() {
- return `
charge effects build up almost
instantlythrowing, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isPlasmaBall ? "plasma ball" : "plasma ball"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.blockDamage > 0.075 || tech.isRailGun || (tech.haveGunCheck("foam") && tech.isFoamPressure) || tech.isTokamak || tech.isPulseLaser || tech.isPlasmaBall
- },
- requires: "mass driver, railgun, foam, pressure vessel, pulse, tokamak, plasma ball",
- effect() {
- tech.isCapacitor = true;
- },
- remove() {
- tech.isCapacitor = false;
- }
- },
- {
- name: "Bitter electromagnet",
- descriptionFunction() {
- return `
railgun charges
+33% slower
+100% harpoon density and
damage`
- },
- isGunTech: true,
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && tech.isRailGun
- },
- requires: "harpoon, railgun",
- effect() {
- tech.railChargeRate *= 1.06
- tech.harpoonDensity += 0.0065
- },
- remove() {
- tech.railChargeRate = 0.97;
- tech.harpoonDensity = 0.0065
- }
- },
- {
- name: "railgun",
- description: `hold fire to charge
harpoon and release to launch
harpoons can't
retract`,
- // description: `
+900% harpoon ammo, but it can't
retract+50% harpoon density and
damage`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple && !tech.isBoostReplaceAmmo
- },
- requires: "harpoon, not UHMWPE, induction furnace, grappling hook, quasiparticles",
- ammoBonus: 9,
- effect() {
- tech.isRailGun = true;
- b.guns[9].chooseFireMethod()
- b.guns[9].ammoPack = 5;
- b.guns[9].ammo = b.guns[9].ammo * 6;
- simulation.updateGunHUD();
- },
- remove() {
- if (tech.isRailGun) {
- tech.isRailGun = false;
- b.guns[9].chooseFireMethod()
- b.guns[9].ammoPack = 1.7;
- b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6);
- simulation.updateGunHUD();
- }
- }
- },
- {
- name: "grappling hook",
- description: `
harpoons attach to the
map and pull you
your
rope extends while holding
fire`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
- },
- requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism",
- effect() {
- tech.isGrapple = true;
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
- }
- },
- remove() {
- if (tech.isGrapple) {
- tech.isGrapple = false;
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
- }
- }
- }
- },
- {
- name: "bulk modulus",
- description: `while
grappling become
invulnerabledrain
energy`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy
- },
- requires: "grappling hook, not alternator",
- effect() {
- tech.isImmuneGrapple = true;
- },
- remove() {
- tech.isImmuneGrapple = false
- }
- },
- {
- name: "alternator",
- description: "
+90% harpoon energy efficiency",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isImmuneGrapple
- },
- requires: "harpoon, not bulk modulus",
- effect() {
- tech.isRailEnergy = true;
- },
- remove() {
- tech.isRailEnergy = false;
- }
- },
- {
- name: "Bessemer process",
- descriptionFunction() {
- return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}%
harpoon size and
damage(1/10 √ harpoon ammo)`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isShieldPierce
- },
- requires: "harpoon, not ceramics",
- effect() {
- tech.isLargeHarpoon = true;
- },
- remove() {
- tech.isLargeHarpoon = false;
- }
- },
- {
- name: "smelting",
- descriptionFunction() {
- return `forge
${this.removeAmmo()} ammo into a new harpoon
fire
+1 harpoon with each shot`
- },
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- ammoRemoved: 0,
- removeAmmo() {
- return (tech.isRailGun ? 5 : 1) * (2 + 2 * this.count)
- },
- allowed() {
- return tech.haveGunCheck("harpoon") && b.guns[9].ammo >= this.removeAmmo()
- },
- requires: "harpoon",
- effect() {
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "harpoon") {
- const removeAmmo = this.removeAmmo()
- this.ammoRemoved += removeAmmo
- b.guns[i].ammo -= removeAmmo
- if (b.guns[i].ammo < 0) b.guns[i].ammo = 0
- simulation.updateGunHUD();
- tech.extraHarpoons++;
- break
- }
- }
- },
- remove() {
- if (tech.extraHarpoons) {
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "harpoon") {
- b.guns[i].ammo += this.ammoRemoved
- simulation.updateGunHUD();
+ remove() { }
+ },
+ {
+ name: "startle response",
+ description: `if a threat is nearby, activate a ${powerUps.orb.boost(1)}
and lock your mouse until you press escape`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ // tech.damage *= 1.33
+ setInterval(() => {
+ if (powerUps.boost.endCycle < m.cycle && !simulation.paused && m.alive) {
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].distanceToPlayer2() < 400000) { //650
+ canvas.requestPointerLock();
+ powerUps.boost.effect();
break
}
}
}
- this.ammoRemoved = 0
- tech.extraHarpoons = 0;
- }
+ }, 2000);
},
- {
- name: "UHMWPE",
- descriptionFunction() {
- return `+${(b.guns[9].ammo*1.25).toFixed(0)}%
harpoon rope length(1/80 of harpoon ammo)`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
- },
- requires: "harpoon, not grappling hook, railgun",
- effect() {
- tech.isFilament = true;
- },
- remove() {
- tech.isFilament = false;
- }
- },
- {
- name: "induction furnace",
- description: "after using
harpoon to collect a
power up+600% harpoon damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
- },
- requires: "harpoon, not grappling hook, railgun",
- effect() {
- tech.isHarpoonPowerUp = true
- },
- remove() {
- tech.isHarpoonPowerUp = false
- }
- },
- {
- name: "quasiparticles",
- descriptionFunction() {
- return `convert current and future ${powerUps.orb.ammo(1)} into ${powerUps.orb.boost(1)} which
give
+${(powerUps.boost.damage*100).toFixed(0)}% damage for
${(powerUps.boost.duration/60).toFixed(0)} seconds`
- },
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return ((tech.haveGunCheck("wave") && !tech.isInfiniteWaveAmmo) || tech.haveGunCheck("laser") || (tech.haveGunCheck("harpoon") && !tech.isRailGun)) && !tech.isEnergyNoAmmo
- },
- requires: "harpoon, laser, wave, frequency, not railgun, non-renewables",
- effect() {
- tech.isBoostReplaceAmmo = true
- for (let i = powerUp.length - 1; i > -1; i--) {
- if (powerUp[i].name === "ammo") {
- powerUps.spawn(powerUp[i].position.x + 50 * (Math.random() - 0.5), powerUp[i].position.y + 50 * (Math.random() - 0.5), "boost");
- Matter.Composite.remove(engine.world, powerUp[i]);
- powerUp.splice(i, 1);
- }
- }
+ remove() { }
+ },
+ {
+ name: "closed timelike curve",
+ description: "spawn 5
field power ups, but every 12 seconds
teleport a second into your future or past",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
- },
- remove() {
- tech.isBoostReplaceAmmo = false
- }
- },
- {
- name: "optical amplifier",
- description: "gain
3 random
laser guntechlaser only turns
off if you have no
energy",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isNonRefundable: true,
- allowed() {
- return tech.haveGunCheck("laser") && !tech.isPulseLaser
- },
- requires: "laser gun, not pulse",
- effect() {
- 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"]
- //convert names into indexes
- const options = []
- for (let i = 0; i < names.length; i++) {
- for (let k = 0; k < tech.tech.length; k++) {
- if (tech.tech[k].name === names[i]) {
- options.push(k)
- break
+ function loop() {
+ if (!simulation.paused && m.alive) {
+ if (!(simulation.cycle % 720)) {
+ requestAnimationFrame(() => {
+ if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option
+ m.rewind(60)
+ m.energy += 0.4 //to make up for lost energy
+ } else {
+ simulation.timePlayerSkip(60)
}
- }
+ }); //wrapping in animation frame prevents errors, probably
}
- //remove options that don't meet requirements
- for (let i = options.length - 1; i > -1; i--) {
- const index = options[i]
- if (!(tech.tech[index].count < tech.tech[index].maxCount) || !tech.tech[index].allowed()) {
- options.splice(i, 1);
- }
- }
- //pick one option
- if (options.length) {
- const index = options[Math.floor(Math.random() * options.length)]
- simulation.makeTextLog(`
tech.giveTech("
${tech.tech[index].name}")
//optical amplifier`, 360);
- tech.giveTech(index)
- techGiven++
- }
- }
- if (techGiven > 0) {
- tech.isStuckOn = true
- } else { //eject if none found
- simulation.makeTextLog(`0
tech found
//optical amplifier`);
- const loop = () => {
- if (!simulation.paused && m.alive) {
- for (let i = 0; i < tech.tech.length; i++) {
- if (tech.tech[i].name === this.name) powerUps.ejectTech(i)
- }
- return
- }
- requestAnimationFrame(loop);
- }
- requestAnimationFrame(loop);
- }
- },
- remove() {
- tech.isStuckOn = false
- }
- },
- {
- name: "relativistic momentum",
- description: "
lasers push
mobs and
blocks",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade
- },
- requires: "laser, not pulse",
- effect() {
- tech.isLaserPush = true;
- },
- remove() {
- tech.isLaserPush = false;
- }
- },
- {
- name: "iridescence",
- // description: "if a
laser hits a mob at a low angle of illumination
+66% laser damage",
- description: "if
laser beams hit mobs near their
center+100% laser damage",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade || tech.isLaserMine
- },
- requires: "laser, not pulse",
- effect() {
- tech.laserCrit += 1;
- },
- remove() {
- tech.laserCrit = 0;
- }
- },
- {
- name: "lens",
- description: "
+150% laser gun damage if it passes
through a revolving
90° arc circular lens", //
π / 2
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("laser")
- },
- requires: "laser",
- effect() {
- tech.isLaserLens = true
- b.guns[11].chooseFireMethod()
- // if (this.count > 0) b.guns[11].lensDamageOn += 20 * Math.PI / 180
- // b.guns[11].arcRange = 0.78
- },
- remove() {
- tech.isLaserLens = false
- b.guns[11].chooseFireMethod()
- // b.guns[11].lensDamageOn = 2.5 // 100% + 150%
- // b.guns[11].arcRange = 0
- }
- },
- {
- name: "compound lens",
- description: "
+50% laser lens
damage+15° lens arc",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("laser") && tech.isLaserLens
- },
- requires: "lens",
- effect() {
- b.guns[11].arcRange += 15 * Math.PI / 180 / 2
- b.guns[11].lensDamageOn += 0.5
- },
- remove() {
- b.guns[11].arcRange = 90 * Math.PI / 180 / 2 //0.78 divded by 2 because of how it's drawn
- b.guns[11].lensDamageOn = 2.5
- }
- },
- {
- name: "specular reflection",
- description: "
+2 laser beam reflections",
- isGunTech: true,
- maxCount: 3,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade) && !tech.isWideLaser && !tech.isPulseLaser && !tech.historyLaser
- },
- requires: "laser, not diffuse beam, pulse, or slow light",
- effect() {
- tech.laserReflections += 2;
- },
- remove() {
- tech.laserReflections = 2;
- }
- },
- {
- name: "diffraction grating",
- description: `
+1 diverging
laser gun beam`,
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.historyLaser
- },
- requires: "laser gun, diffuse beam, or slow light",
- effect() {
- tech.beamSplitter++
- b.guns[11].chooseFireMethod()
- },
- remove() {
- if (tech.beamSplitter !== 0) {
- tech.beamSplitter = 0
- b.guns[11].chooseFireMethod()
- }
- }
- },
- {
- name: "diffuse beam",
- link: `
diffuse beam`,
- description: "
laser gun beam is
wider and doesn't
reflect+220% laser damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isPulseLaser && !tech.historyLaser
- },
- requires: "laser gun, not specular reflection, diffraction grating, slow light, pulse",
- effect() {
- if (tech.wideLaser === 0) tech.wideLaser = 3
- tech.isWideLaser = true;
- b.guns[11].chooseFireMethod()
- },
- remove() {
- if (tech.isWideLaser) {
- // tech.wideLaser = 0
- tech.isWideLaser = false;
- b.guns[11].chooseFireMethod()
- }
- }
- },
- {
- name: "output coupler",
- description: "
+30% laser gun beam
width+30% laser damage",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("laser") && tech.isWideLaser
- },
- requires: "laser gun, diffuse beam",
- effect() {
- tech.wideLaser += 2
- b.guns[11].chooseFireMethod()
- },
- remove() {
- if (tech.isWideLaser) {
- tech.wideLaser = 3
- } else {
- tech.wideLaser = 0
- }
- b.guns[11].chooseFireMethod()
- }
- },
- {
- name: "slow light",
- description: "
laser gun beam is
spread into your recent
past+300% total beam
damage",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isWideLaser
- },
- requires: "laser gun, not specular reflection, diffraction grating, diffuse beam",
- effect() {
- // this.description = `add 5 more
laser beams into into your past`
- tech.historyLaser++
- b.guns[11].chooseFireMethod()
- },
- remove() {
- if (tech.historyLaser) {
- tech.historyLaser = 0
- b.guns[11].chooseFireMethod()
- }
- }
- },
- {
- name: "infrared diode",
- description: "
+60% laser energy efficiency
infrared light is outside visual perception",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && !tech.isPulseLaser && tech.laserDrain === 0.0018
- },
- requires: "laser, not free-electron, pulse",
- effect() {
- tech.laserDrain *= 0.4; //100%-50%
- tech.laserColor = "transparent" //"rgb(255,0,20,0.02)"
- // tech.laserColorAlpha = "rgba(255,0,20,0.05)"
- },
- remove() {
- tech.laserDrain = 0.0018;
- tech.laserColor = "#f02"
- tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
- }
- },
- {
- name: "dye laser",
- description: "
+25% laser energy efficiency
+25% laser damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade) && !tech.isPulseLaser && tech.laserDrain === 0.0018
- },
- requires: "laser, not pulse, infrared diode",
- effect() {
- tech.laserDrain *= 0.75
- tech.laserDamage *= 1.25
- tech.laserColor = "rgb(0, 11, 255)"
- tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
- },
- remove() {
- tech.laserDrain = 0.0018;
- tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
- tech.laserColor = "#f00"
- tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
- }
- },
- {
- name: "free-electron laser",
- description: "
–250% laser energy efficiency
+200% laser damage",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade) && !tech.isPulseLaser && tech.laserDrain === 0.0018
- },
- requires: "laser, not pulse, infrared diode",
- effect() {
- tech.laserDrain *= 1 + 2.5 //250% more drain
- tech.laserDamage *= 1 + 2 //190% more damage
- tech.laserColor = "#83f"
- tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
- },
- remove() {
- tech.laserDrain = 0.0018;
- tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
- tech.laserColor = "#f00"
- tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
- }
- },
- {
- name: "pulse",
- description: "charge your
energy and release it as a
laser pulse that initiates an
explosion cluster",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDrain === 0.0018 && !tech.isStuckOn
- },
- requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
- effect() {
- tech.isPulseLaser = true;
- b.guns[11].chooseFireMethod()
- },
- remove() {
- if (tech.isPulseLaser) {
- tech.isPulseLaser = false;
- b.guns[11].chooseFireMethod()
- }
- }
- },
- //**************************************************
- //************************************************** field
- //************************************************** tech
- //**************************************************
- {
- name: "zero point energy",
- description: `use ${powerUps.orb.research(2)}
+100 maximum
energy`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation") && (build.isExperimentSelection || powerUps.research.count > 1)
- },
- requires: "standing wave, pilot wave, time dilation",
- effect() {
- tech.harmonicEnergy = 1
- m.setMaxEnergy()
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.harmonicEnergy = 0;
- m.setMaxEnergy()
- if (this.count > 0) powerUps.research.changeRerolls(2)
- }
- },
- {
- name: "spherical harmonics",
- description: "
+40% standing wave deflection efficiency
no longer deactivates on mob
shields", //
standing wave oscillates in a 3rd dimension
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "standing wave"
- },
- requires: "standing wave",
- effect() {
- tech.harmonics++
- m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.6) * Math.pow(0.6, (tech.harmonics - 2))
- m.harmonicShield = m.harmonicAtomic
- },
- remove() {
- tech.harmonics = 2
- m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.6) * Math.pow(0.6, (tech.harmonics - 2))
- m.harmonicShield = m.harmonic3Phase
- }
- },
- {
- name: "expansion",
- description: "
+50% standing wave deflection efficiency
using
standing wave field
expands its
radius",
- // description: "use
energy to
expand standing wavethe field slowly
contracts when not used",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "standing wave"
- },
- requires: "standing wave",
- effect() {
- tech.isStandingWaveExpand = true
- m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.3) * Math.pow(0.6, (tech.harmonics - 2))
- },
- remove() {
- tech.isStandingWaveExpand = false
- m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.3) * Math.pow(0.6, (tech.harmonics - 2))
- m.harmonicRadius = 1
- }
- },
- {
- name: "triple point",
- descriptionFunction() {
- return `
+1.5 second
ice IX freeze effect
spawn ${powerUps.orb.coupling(10)} that each give
+0.1 coupling${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per
coupling"}`
- },
- isFieldTech: true,
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
- },
- requires: "standing wave, perfect diamagnetism",
- effect() {
- tech.iceIXFreezeTime += 90
- powerUps.spawnDelay("coupling", 10)
- },
- remove() {
- tech.iceIXFreezeTime = 150
- if (this.count) {
- m.couplingChange(-this.count)
- }
- }
- },
- {
- name: "bremsstrahlung",
- description: "
deflecting and thrown
blocksdo braking
damage to mobs",
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
- },
- requires: "standing wave, perfect diamagnetism, pilot wave",
- effect() {
- tech.blockDmg += 3 //if you change this value also update the for loop in the electricity graphics in m.pushMass
- },
- remove() {
- tech.blockDmg = 0;
- }
- },
- {
- name: "cherenkov radiation", //
deflecting and
blocks
- description: "bremsstrahlung's effects are
radioactive+300% damage over
6 seconds",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && tech.blockDmg
- },
- requires: "bremsstrahlung",
- effect() {
- tech.isBlockRadiation = true
- },
- remove() {
- tech.isBlockRadiation = false;
- }
- },
- {
- name: "flux pinning",
- description: "after
deflecting a mob
it is
stunned for up to
4 seconds",
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
- },
- requires: "a field that can block",
- effect() {
- tech.isStunField += 240;
- },
- remove() {
- tech.isStunField = 0;
- }
- },
- {
- name: "eddy current brake",
- description: "perfect diamagnetism
slows nearby mobs
effect
radius scales with stored
energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
- },
- requires: "perfect diamagnetism",
- effect() {
- tech.isPerfectBrake = true;
- },
- remove() {
- tech.isPerfectBrake = false;
- }
- },
- {
- name: "Meissner effect",
- description: "
+55% perfect diamagnetism
radius+22° perfect diamagnetism circular
arc",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
- },
- requires: "perfect diamagnetism",
- effect() {
- tech.isBigField = true;
- },
- remove() {
- tech.isBigField = false;
- }
- },
- {
- name: "tessellation",
- description: `use ${powerUps.orb.research(2)}
+50% defense`,
- // description: "use
4 researchreduce
defense by
50%",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "negative mass") && (build.isExperimentSelection || powerUps.research.count > 3)
- },
- requires: "perfect diamagnetism, negative mass, pilot wave",
- effect() {
- tech.isFieldHarmReduction = true
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isFieldHarmReduction = false
- if (this.count > 0) powerUps.research.changeRerolls(2)
- }
- },
- {
- name: "radiative equilibrium",
- description: "after losing
health+200% damage for
10 seconds",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass"
- },
- requires: "negative mass, pilot wave",
- effect() {
- tech.isHarmDamage = true;
- },
- remove() {
- tech.isHarmDamage = false;
- }
- },
- {
- name: "dynamic equilibrium",
- descriptionFunction() {
- return `increase
damage by your
defense and
5% of your last ${tech.isEnergyHealth ? "
energy" : "
health"} loss
(+${(100*Math.max(5,tech.lastHitDamage) * m.lastHit * (2 - m.defense())).toFixed(0)}% damage)`
- }, // =
+${10*m.defense()}%
- // descriptionFunction() { return `increase
damage by your last ${tech.isEnergyHealth ? "
energy" : "
health"} loss
(${(tech.lastHitDamage).toFixed(0)}%)(${(100*m.lastHit).toFixed(0)} ${tech.isEnergyHealth ? "energy" : "health"})(${2 - m.defense()} defense) = ${(100*tech.lastHitDamage * m.lastHit * (2 - m.defense())).toFixed(0)}% damage ` }, // =
+${10*m.defense()}%
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "standing wave") && !tech.isCloakHealLastHit
- },
- requires: "negative mass, pilot wave, standing wave, not patch",
- effect() {
- tech.lastHitDamage += 5;
- },
- remove() {
- tech.lastHitDamage = 0;
- }
- },
- {
- name: "neutronium",
- description: `
move and
jump 20% slowerif your
field is active
+90% defense`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "negative mass"
- },
- requires: "negative mass",
- effect() {
- tech.isNeutronium = true
- tech.baseFx *= 0.8
- tech.baseJumpForce *= 0.8
- m.setMovement()
- },
- //also removed in m.setHoldDefaults() if player switches into a bad field
- remove() {
- tech.isNeutronium = false
- if (!tech.isFreeWormHole) {
- tech.baseFx = 0.08
- tech.baseJumpForce = 10.5
- m.setMovement()
- }
- }
- },
- {
- name: "aerostat",
- description: `
+88% damage while
off the
ground-22% damage while
on the
ground`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "negative mass"
- },
- requires: "negative mass",
- effect() {
- tech.isNoGroundDamage = true
- },
- remove() {
- tech.isNoGroundDamage = false
- }
- },
- {
- name: "annihilation",
- description: "after
colliding with non-boss mobs
they are
annihilated and
–33% energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "negative mass" && !tech.isEnergyHealth
- },
- requires: "negative mass, not mass-energy",
- effect() {
- tech.isAnnihilation = true
- },
- remove() {
- tech.isAnnihilation = false;
- }
- },
- {
- name: "inertial mass",
- description: "
negative mass is larger and
fasterblocks also move
horizontally with the field",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "negative mass"
- },
- requires: "negative mass",
- effect() {
- tech.isFlyFaster = true
- },
- remove() {
- tech.isFlyFaster = false;
- }
- },
- // {
- // name: "Bose Einstein condensate",
- // description: "use
energy to
freeze mobs in your
fieldpilot wave, negative mass, time dilation",
- // isFieldTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 2,
- // frequencyDefault: 2,
- // allowed() {
- // return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || (m.fieldUpgrades[m.fieldMode].name === "time dilation" && !tech.isRewindField)
- // },
- // requires: "pilot wave, negative mass, time dilation, not retrocausality",
- // effect() {
- // tech.isFreezeMobs = true
- // },
- // remove() {
- // tech.isFreezeMobs = false
- // }
- // },
- {
- name: "bot manufacturing",
- description: `use ${powerUps.orb.research(1)} to build
3 random
bots`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBotTech: true,
- isNonRefundable: true,
- allowed() {
- return powerUps.research.count > 0 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
- },
- requires: "molecular assembler, pilot wave",
- effect() {
- for (let i = 0; i < 1; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- m.energy = 0.01;
- b.randomBot()
- b.randomBot()
- b.randomBot()
- },
- remove() {}
- },
- {
- name: "bot prototypes",
- description: `use ${powerUps.orb.research(2)}to build
2 random
botsand
upgrade all
bots to that type`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBotTech: true,
- isNonRefundable: true,
- allowed() {
- return powerUps.research.count > 1 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
- },
- requires: "molecular assembler, pilot wave",
- effect() {
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- //fill array of available bots
- const notUpgradedBots = []
- const num = 2
- notUpgradedBots.push(() => {
- tech.giveTech("nail-bot upgrade")
- for (let i = 0; i < num; i++) {
- b.nailBot()
- tech.nailBotCount++;
- }
- simulation.makeTextLog(`tech.isNailBotUpgrade = true`)
- })
- notUpgradedBots.push(() => {
- tech.giveTech("foam-bot upgrade")
- for (let i = 0; i < num; i++) {
- b.foamBot()
- tech.foamBotCount++;
- }
- simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
- })
- notUpgradedBots.push(() => {
- tech.giveTech("boom-bot upgrade")
- for (let i = 0; i < num; i++) {
- b.boomBot()
- tech.boomBotCount++;
- }
- simulation.makeTextLog(`tech.isBoomBotUpgrade = true`)
- })
- notUpgradedBots.push(() => {
- tech.giveTech("laser-bot upgrade")
- for (let i = 0; i < num; i++) {
- b.laserBot()
- tech.laserBotCount++;
- }
- simulation.makeTextLog(`tech.isLaserBotUpgrade = true`)
- })
- notUpgradedBots.push(() => {
- tech.giveTech("orbital-bot upgrade")
- for (let i = 0; i < num; i++) {
- b.orbitBot()
- tech.orbitBotCount++;
- }
- simulation.makeTextLog(`tech.isOrbitalBotUpgrade = true`)
- })
- for (let i = 0; i < 2; i++) { //double chance for dynamo-bot, since it's very good for assembler
- notUpgradedBots.push(() => {
- tech.giveTech("dynamo-bot upgrade")
- for (let i = 0; i < num; i++) {
- b.dynamoBot()
- tech.dynamoBotCount++;
- }
- simulation.makeTextLog(`tech.isDynamoBotUpgrade = true`)
- })
- }
- notUpgradedBots[Math.floor(Math.random() * notUpgradedBots.length)]() //choose random function from the array and run it
- },
- remove() {}
- },
- // {
- // name: "mycelium manufacturing",
- // link: `
mycelium manufacturing`,
- // // description: `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to grow
spores`,
- // descriptionFunction() { return `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to grow ${b.guns[6].nameString('s')}` },
- // isFieldTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 3,
- // frequencyDefault: 3,
- // allowed() {
- // return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
- // },
- // requires: "molecular assembler, no other manufacturing, no drone tech",
- // effect() {
- // if (!build.isExperimentSelection) {
- // for (let i = 0; i < 1; i++) {
- // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- // }
- // }
- // tech.isSporeField = true;
- // },
- // remove() {
- // tech.isSporeField = false;
- // if (this.count > 0) powerUps.research.changeRerolls(1)
- // }
- // },
- // {
- // name: "missile manufacturing",
- // link: `
missile manufacturing`,
- // description: `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to construct
missiles`,
- // // description: "use
3 research to repurpose
assemblerexcess
energy used to construct
missiles",
- // isFieldTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 3,
- // frequencyDefault: 3,
- // allowed() {
- // return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
- // },
- // requires: "molecular assembler, no other manufacturing, no drone tech",
- // effect() {
- // if (!build.isExperimentSelection) {
- // for (let i = 0; i < 1; i++) {
- // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- // }
- // }
- // tech.isMissileField = true;
- // },
- // remove() {
- // tech.isMissileField = false;
- // if (this.count > 0) powerUps.research.changeRerolls(1)
- // }
- // },
- // {
- // name: "ice IX manufacturing",
- // link: `
ice IX manufacturing`,
- // description: `use ${powerUps.orb.research(1)}to repurpose
molecular assemblerexcess
energy used to condense
ice IX`,
- // // description: "use
3 research to repurpose
assemblerexcess
energy used to condense
ice IX",
- // isFieldTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 3,
- // frequencyDefault: 3,
- // allowed() {
- // return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
- // },
- // requires: "molecular assembler, no other manufacturing, no drone tech",
- // effect() {
- // if (!build.isExperimentSelection) {
- // for (let i = 0; i < 1; i++) {
- // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- // }
- // }
- // tech.isIceField = true;
- // },
- // remove() {
- // tech.isIceField = false;
- // if (this.count > 0) powerUps.research.changeRerolls(1)
- // }
- // },
- {
- name: "pair production",
- description: "after picking up a
power up+200 energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
- },
- requires: "molecular assembler, pilot wave, standing wave",
- effect() {
- tech.isMassEnergy = true // used in m.grabPowerUp
- m.energy += 2
- },
- remove() {
- tech.isMassEnergy = false;
- }
- },
- {
- name: "electric generator",
- description: "after
deflecting mobs
molecular assembler generates
+50 energy",
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
- },
- requires: "molecular assembler",
- effect() {
- tech.deflectEnergy += 0.5;
- },
- remove() {
- tech.deflectEnergy = 0;
- }
- },
- {
- name: "combinatorial optimization",
- description: "
+35% damage–35% fire rate",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
- },
- requires: "cloaking, molecular assembler, plasma torch, pilot wave",
- damage: 1.35,
- effect() {
- tech.damage *= this.damage
- tech.aimDamage = 1.35
- b.setFireCD();
- },
- remove() {
- if (this.count) tech.damage /= this.damage
- tech.aimDamage = 1
- b.setFireCD();
- }
- },
- {
- name: "tokamak",
- description: "throwing a
block converts it into
energyand a pulsed fusion
explosion",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler"
- },
- requires: "plasma torch, molecular assembler",
- effect() {
- tech.isTokamak = true;
- },
- remove() {
- tech.isTokamak = false;
- }
- },
- {
- name: "degenerate matter",
- description: "if your
field is active
+75% defense",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
- },
- requires: "molecular assembler, plasma torch, perfect diamagnetism, pilot wave",
- effect() {
- tech.isHarmReduce = true
- },
- remove() {
- tech.isHarmReduce = false;
- }
- },
- {
- name: "plasma-bot",
- link: `
plasma-bot`,
- description: `use ${powerUps.orb.research(2)}to trade your
fieldfor a
bot that uses
energy to emit
plasma`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- isBot: true,
- isBotTech: true,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall && !tech.isExtruder && (build.isExperimentSelection || powerUps.research.count > 1)
- },
- requires: "plasma torch, not extruder, plasma ball",
- effect() {
- tech.plasmaBotCount++;
- b.plasmaBot();
- if (build.isExperimentSelection) {
- document.getElementById("field-" + m.fieldMode).classList.remove("build-field-selected");
- document.getElementById("field-0").classList.add("build-field-selected");
- }
- m.setField("field emitter")
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- if (this.count > 0) {
- tech.plasmaBotCount = 0;
- b.clearPermanentBots();
- b.respawnBots();
- if (m.fieldMode === 0) {
- m.setField("plasma torch")
- if (build.isExperimentSelection) {
- document.getElementById("field-0").classList.remove("build-field-selected");
- document.getElementById("field-" + m.fieldMode).classList.add("build-field-selected");
- }
- }
- powerUps.research.changeRerolls(2)
- }
- }
- },
- {
- name: "plasma jet",
- link: `
plasma jet`,
- description: `use ${powerUps.orb.research(2)}
+50% plasma torch range`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (tech.plasmaBotCount || m.fieldUpgrades[m.fieldMode].name === "plasma torch") && (build.isExperimentSelection || powerUps.research.count > 1) && !tech.isPlasmaBall
- },
- requires: "plasma torch, not plasma ball",
- effect() {
- tech.isPlasmaRange += 0.5;
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isPlasmaRange = 1;
- if (this.count > 0) powerUps.research.changeRerolls(this.count * 2)
- }
- },
- {
- name: "extruder",
- description: "
extrude a thin hot wire of
plasmaincreases
damage and
energy drain",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall
- },
- requires: "plasma torch, not plasma ball",
- effect() {
- tech.isExtruder = true;
- m.fieldUpgrades[m.fieldMode].set()
- },
- remove() {
- tech.isExtruder = false;
- if (this.count && m.fieldUpgrades[m.fieldMode].name === "plasma torch") m.fieldUpgrades[m.fieldMode].set()
- }
- },
- {
- name: "refractory metal",
- description: "
extrude metals at a higher
temperatureincreases effective
radius and
damage",
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isExtruder
- },
- requires: "extruder",
- effect() {
- tech.extruderRange += 55
- },
- remove() {
- tech.extruderRange = 15
- }
- },
- {
- name: "plasma ball",
- description: "
grow an expanding
ball of
plasmaincreases
damage and
energy drain",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isExtruder && tech.isPlasmaRange === 1
- },
- requires: "plasma torch, not extruder, plasma jet",
- effect() {
- tech.isPlasmaBall = true;
- m.fieldUpgrades[m.fieldMode].set()
- },
- remove() {
- tech.isPlasmaBall = false;
- if (this.count && m.fieldUpgrades[m.fieldMode].name === "plasma torch") m.fieldUpgrades[m.fieldMode].set()
- }
- },
- {
- name: "corona discharge",
- description: "increase the
range and
frequencyof
plasma ball's
electric arc ",
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isPlasmaBall
- },
- requires: "plasma ball",
- effect() {
- tech.plasmaDischarge += 0.03
- },
- remove() {
- tech.plasmaDischarge = 0.01 //default chance per cycle of a discharge
- }
- },
- {
- name: "retrocausality",
- description: "
time dilation uses
energy to
rewind your
health,
velocity, and
position up to
10 seconds",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "time dilation" && !m.isShipMode && !tech.isRewindAvoidDeath && !tech.isTimeSkip
- },
- requires: "time dilation, not CPT symmetry",
- effect() {
- tech.isRewindField = true;
- m.fieldUpgrades[m.fieldMode].set()
- m.wakeCheck();
- },
- remove() {
- tech.isRewindField = false;
- if (this.count) m.fieldUpgrades[m.fieldMode].set()
- }
- },
- {
- name: "frame-dragging", //"non-inertial frame",
- description: "when not
moving time dilation
stops time+33% defense",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "time dilation"
- },
- requires: "time dilation",
- effect() {
- tech.isTimeStop = true;
- m.fieldHarmReduction = 0.66; //33% reduction
- },
- remove() {
- tech.isTimeStop = false;
- if (m.fieldUpgrades[m.fieldMode].name === "time dilation") m.fieldHarmReduction = 1;
- }
- },
- {
- name: "Lorentz transformation",
- description: `use ${powerUps.orb.research(3)}
+50% movement,
jumping, and
fire rate`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "time dilation") && (build.isExperimentSelection || powerUps.research.count > 2)
- },
- requires: "time dilation",
- effect() {
- tech.isFastTime = true
- m.setMovement();
- b.setFireCD();
- for (let i = 0; i < 3; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isFastTime = false
- m.setMovement();
- b.setFireCD();
- if (this.count > 0) powerUps.research.changeRerolls(3)
- }
- },
- {
- name: "time crystals",
- description: "
+200% passive
energy generation",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isGroundState && (m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "pilot wave")
- },
- requires: "time dilation or pilot wave, not ground state",
- effect() {
- tech.isTimeCrystals = true
- m.setFieldRegen()
- },
- remove() {
- tech.isTimeCrystals = false
- m.setFieldRegen()
- }
- },
- {
- name: "no-cloning theorem",
- // descriptionFunction() { return `
+45% chance to
duplicate spawned
power upsafter a mob
dies –2% duplication (${tech.duplicationChance()})` },
- description: `
+45% chance to
duplicate spawned
power upsafter a mob
dies –2% duplication`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking") && !tech.isQuantumEraser
- },
- requires: "cloaking, time dilation, not quantum eraser",
- effect() {
- tech.cloakDuplication = 0.45
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
- },
- remove() {
- tech.cloakDuplication = 0
- powerUps.setDupChance(); //needed after adjusting duplication chance
- }
- },
- {
- name: "quantum eraser",
- descriptionFunction() {
- return `
for each mob left alive after you exit a level
kill a mob as they spawn at +${100-1.6*simulation.difficultyMode**2}% duplication`
- },
- // description: `
for each mob left alive after you exit a level
kill a mob as they spawn at 100% duplication`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "time dilation") && !tech.cloakDuplication
- },
- requires: "cloaking or time dilation",
- effect() {
- tech.quantumEraserCount = 0
- tech.isQuantumEraserDuplication = 0
- tech.isQuantumEraser = true
- },
- remove() {
- tech.quantumEraserCount = 0
- tech.isQuantumEraserDuplication = 0
- tech.isQuantumEraser = false
- }
- },
- {
- name: "symbiosis",
- descriptionFunction() {
- return `after a
boss dies spawn ${powerUps.orb.research(3)}${powerUps.orb.heal(3)} and a
techafter a
mob dies –0.5 maximum ${tech.isEnergyHealth ? "
energy" : "
health"}`
- },
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" //|| m.fieldUpgrades[m.fieldMode].name === "time dilation"
- },
- requires: "cloaking",
- effect() {
- tech.isAddRemoveMaxHealth = true
- },
- remove() {
- tech.isAddRemoveMaxHealth = false
- }
- },
- {
- name: "boson composite",
- link: `
boson composite`,
- description: "while
cloaked you are
intangibleto
blocks and mobs, but
mobs drain
energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
- },
- requires: "metamaterial cloaking",
- effect() {
- tech.isIntangible = true;
- },
- remove() {
- if (tech.isIntangible) {
- tech.isIntangible = false;
- player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions
- }
- }
- },
- {
- name: "patch",
- link: `
patch`,
- description: "after
cloaking recover
75% of your
last
health loss using that much
energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" && !tech.lastHitDamage && !tech.isEnergyHealth
- },
- requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy",
- effect() {
- tech.isCloakHealLastHit = true;
- },
- remove() {
- tech.isCloakHealLastHit = false;
- }
- },
- {
- name: "dazzler",
- link: `
dazzler`,
- description: "after
decloaking stun nearby mobs
and drain
–15 energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
- },
- requires: "metamaterial cloaking",
- effect() {
- tech.isCloakStun = true;
- },
- remove() {
- tech.isCloakStun = false;
- }
- },
- // {
- // name: "ambush",
- // description: "metamaterial cloaking field
damage effect
is increased from
333% to
555%",
- // isFieldTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 2,
- // frequencyDefault: 2,
- // allowed() {
- // return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
- // },
- // requires: "metamaterial cloaking",
- // effect() {
- // tech.sneakAttackDmg = 6.55 //555% + 100%
- // },
- // remove() {
- // tech.sneakAttackDmg = 4.33 //333% + 100%
- // }
- // },
- {
- name: "dynamical systems",
- description: `use ${powerUps.orb.research(2)}
+35% damage`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && (build.isExperimentSelection || powerUps.research.count > 1)
- },
- requires: "cloaking, pilot wave, or plasma torch",
- damage: 1.35,
- effect() {
- tech.damage *= this.damage
- tech.isCloakingDamage = true
- for (let i = 0; i < 2; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isCloakingDamage = false
- if (this.count > 0) {
- tech.damage /= this.damage
- powerUps.research.changeRerolls(2)
- }
- }
- },
- {
- name: "WIMPs",
- description: `at the end of each
level spawn ${powerUps.orb.research(4)}
and a dangerous particle that slowly
chases you`,
- isFieldTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation"
- },
- requires: "wormhole, pilot wave, time dilation",
- effect() {
- tech.wimpCount++
- spawn.WIMP()
- for (let j = 0, len = 4; j < len; j++) powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false)
- },
- remove() {
- tech.wimpCount = 0
- }
- },
- {
- name: "vacuum fluctuation",
- description: `use ${powerUps.orb.research(4)}to exploit your
field for a
+11% chance to
duplicate spawned
power ups`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 3,
- frequencyDefault: 3,
- allowed() {
- return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "wormhole") && (build.isExperimentSelection || powerUps.research.count > 3)
- },
- requires: "wormhole, time dilation, negative mass, pilot wave",
- effect() {
- tech.fieldDuplicate = 0.11
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
- for (let i = 0; i < 4; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.fieldDuplicate = 0
- powerUps.setDupChance(); //needed after adjusting duplication chance
- if (this.count > 0) powerUps.research.changeRerolls(4)
- }
- },
- // {
- // name: "Penrose process",
- // description: "after a
block falls into a
wormhole+50 energy",
- // isFieldTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 2,
- // frequencyDefault: 2,
- // allowed() {
- // return m.fieldUpgrades[m.fieldMode].name === "wormhole"
- // },
- // requires: "wormhole",
- // effect() {
- // tech.isWormholeEnergy = true
- // },
- // remove() {
- // tech.isWormholeEnergy = false
- // }
- // },
- {
- name: "transdimensional worms",
- link: `
transdimensional worms`,
- description: "after a
block falls into a
wormholespawn a
worm",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole"
- },
- requires: "wormhole",
- effect() {
- tech.isWormholeWorms = true
- },
- remove() {
- tech.isWormholeWorms = false
- }
- },
- {
- name: "geodesics",
- description: `your
bullets can traverse
wormholesspawn 2
guns and ${powerUps.orb.ammo(4)}`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole"
- },
- requires: "wormhole",
- effect() {
- tech.isWormHoleBullets = true
- for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 200 * (Math.random() - 0.5), m.pos.y + 200 * (Math.random() - 0.5), "gun");
- for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + 200 * (Math.random() - 0.5), m.pos.y + 200 * (Math.random() - 0.5), "ammo");
- },
- remove() {
- if (tech.isWormHoleBullets) {
- for (let i = 0; i < 2; i++) {
- if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
- }
- tech.isWormHoleBullets = false;
- }
- }
- },
- {
- name: "cosmic string",
- description: "after
tunneling through mobs with a
wormholestun them and do
radioactive damage",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole"
- },
- requires: "wormhole",
- effect() {
- tech.isWormholeDamage = true
- },
- remove() {
- tech.isWormholeDamage = false
- }
- },
- {
- name: "invariant",
- description: "while placing your
wormholeuse
energy to
pause time",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole" && !tech.isNoDraftPause
- },
- requires: "wormhole, not eternalism",
- effect() {
- tech.isWormHolePause = true
- },
- remove() {
- if (tech.isWormHolePause && m.isBodiesAsleep) m.wakeCheck();
- tech.isWormHolePause = false
- }
- },
- {
- name: "charmed baryons",
- description: `
–33% movement and
jumpingwormholes drain
zero energy`,
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole" && !tech.isWormholeMapIgnore
- },
- requires: "wormhole, not affine connection",
- effect() {
- tech.isFreeWormHole = true
- tech.baseFx *= 0.66
- tech.baseJumpForce *= 0.66
- m.setMovement()
- },
- //also removed in m.setHoldDefaults() if player switches into a bad field
- remove() {
- tech.isFreeWormHole = false
- if (!tech.isNeutronium) {
- tech.baseFx = 0.08
- tech.baseJumpForce = 10.5
- m.setMovement()
- }
- }
- },
- {
- name: "affine connection",
- description: "
wormholes can tunnel through
anythingfor
+200% energy drain",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "wormhole" && !tech.isFreeWormHole
- },
- requires: "wormhole, not charmed baryons",
- effect() {
- tech.isWormholeMapIgnore = true
- },
- remove() {
- tech.isWormholeMapIgnore = false
- }
- },
- //**************************************************
- //************************************************** experimental
- //************************************************** modes
- //**************************************************
- // {
- // name: "-ship-",
- // description: "
experiment: fly around with no legs
aim with the keyboard",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isNonRefundable: true,
- // isBadRandomOption: true,
- // isExperimentalMode: true,
- // allowed() {
- // return build.isExperimentSelection && !m.isShipMode && m.fieldUpgrades[m.fieldMode].name !== "negative mass"
- // },
- // requires: "",
- // effect() {
- // m.shipMode()
- // },
- // remove() {}
- // },
- // {
- // name: "-quantum leap-",
- // description: "
experiment: every 20 seconds
become an
alternate version of yourself",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isBadRandomOption: true,
- // isExperimentalMode: true,
- // allowed() {
- // return build.isExperimentSelection
- // },
- // requires: "",
- // interval: undefined,
- // effect() {
- // this.interval = setInterval(() => {
- // if (!build.isExperimentSelection) {
- // m.switchWorlds()
- // simulation.trails()
- // }
- // }, 20000); //every 20 seconds
-
- // },
- // remove() {
- // if (this.count > 0) clearTimeout(this.interval);
- // }
- // },
- // {
- // name: "-shields-",
- // description: "
experiment: every 5 seconds
all mobs gain a shield",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isBadRandomOption: true,
- // isExperimentalMode: true,
- // allowed() {
- // return build.isExperimentSelection
- // },
- // requires: "",
- // effect() {
- // this.interval = setInterval(() => {
- // if (!build.isExperimentSelection) {
- // for (let i = 0; i < mob.length; i++) {
- // if (!mob[i].isShielded && !mob[i].shield && mob[i].isDropPowerUp) spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
- // }
- // }
- // }, 5000); //every 5 seconds
- // },
- // interval: undefined,
- // remove() {
- // if (this.count > 0) clearTimeout(this.interval);
- // }
- // },
- // {
- // name: "-Fourier analysis-",
- // description: "
experiment: your aiming is random",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isBadRandomOption: true,
- // isExperimentalMode: true,
- // allowed() {
- // return build.isExperimentSelection && !m.isShipMode
- // },
- // requires: "not ship",
- // effect() {
- // m.look = () => {
- // m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03)
- // const scale = 0.8;
- // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
- // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
- // m.transX += (m.transSmoothX - m.transX) * 0.07;
- // m.transY += (m.transSmoothY - m.transY) * 0.07;
- // }
- // },
- // remove() {
- // if (this.count > 0) m.look = m.lookDefault()
- // }
- // },
- // {
- // name: "-panopticon-",
- // description: "
experiment: mobs can always see you",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isBadRandomOption: true,
- // isExperimentalMode: true,
- // allowed() {
- // return build.isExperimentSelection
- // },
- // requires: "",
- // effect() {
- // this.interval = setInterval(() => {
- // if (!build.isExperimentSelection) {
- // for (let i = 0; i < mob.length; i++) {
- // if (!mob[i].shield && mob[i].isDropPowerUp) {
- // mob[i].locatePlayer()
- // mob[i].seePlayer.yes = true;
- // }
- // }
- // }
- // }, 1000); //every 1 seconds
- // },
- // interval: undefined,
- // remove() {
- // if (this.count > 0) clearTimeout(this.interval);
- // }
- // },
- // {
- // name: "-decomposers-",
- // description: "
experiment: after they die
mobs leave behind spawns",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isBadRandomOption: true,
- // isExperimentalMode: true,
- // allowed() {
- // return build.isExperimentSelection
- // },
- // requires: "",
- // effect() {
- // tech.deathSpawns = 0.2
- // },
- // remove() {
- // tech.deathSpawns = 0
- // }
- // },
-
-
-
- //**************************************************
- //************************************************** JUNK
- //************************************************** tech
- //**************************************************
- // {
- // name: "junk",
- // description: "",
- // maxCount: 9,
- // count: 0,
- // frequency: 0,
- // isNonRefundable: true,
- // isJunk: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {
-
- // },
- // remove() {}
- // },
- {
- name: "swap meet",
- description: "normal
tech become
JUNKand
JUNK become normal
tech",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- tech.tech[i].isJunk = !tech.tech[i].isJunk
- if (tech.tech[i].isJunk) {} else {}
-
- if (tech.tech[i].frequency > 0) {
- tech.tech[i].frequency = 0
- } else {
- tech.tech[i].frequency = 2
- }
- }
- },
- remove() {}
- },
- // {
- // name: "pocket dimension",
- // description: "rotate tech descriptions into a higher spacial dimension",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isJunk: true,
- // isNonRefundable: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {
- // document.getElementById("choose-grid").classList.add("flipX");
- // },
- // remove() {}
- // },
- {
- name: "random",
- link: `
random`,
- delay: 333,
- descriptionFunction() {
- const delay = 333
- const loop = () => {
- if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) {
- const dmg = Math.floor(27 * Math.random()) * 0.01
- this.text = `
+${(dmg*100).toFixed(0).padStart(2, '0')}% damage`
- this.damage = 1 + dmg
- if (document.getElementById(`damage-JUNK-id${this.id}`)) document.getElementById(`damage-JUNK-id${this.id}`).innerHTML = this.text
- setTimeout(() => {
- loop()
- }, delay);
- }
- }
- setTimeout(() => {
- loop()
- }, delay);
- this.id++
- return `
${this.text}`
- },
- maxCount: 3,
- count: 0,
- frequency: 1,
- isJunk: true,
- allowed() {
- return !build.isExperimentSelection
- },
- requires: "NOT EXPERIMENT MODE",
- damage: 0,
- effect() {
- tech.damage *= this.damage
- },
- remove() {
- if (this.count > 0) tech.damage /= this.damage
- }
- },
- {
- name: "boost",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return !build.isExperimentSelection
- },
- requires: "NOT EXPERIMENT MODE",
- effect() {
- powerUps.spawnDelay("boost", this.spawnCount)
- },
- remove() {},
- id: 0,
- text: "",
- delay: 100,
- spawnCount: 0,
- descriptionFunction() {
- let count = 9999 * Math.random()
- const loop = () => {
- if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0) //simulation.paused ||
- count += 4.5
- const waves = 2 * Math.sin(count * 0.0133) + Math.sin(count * 0.013) + 0.5 * Math.sin(count * 0.031) + 0.33 * Math.sin(count * 0.03)
- this.spawnCount = Math.floor(100 * Math.abs(waves))
- this.text = `spawn
${this.spawnCount.toLocaleString(undefined, {minimumIntegerDigits:3})} ${powerUps.orb.boost(1)}
that give
+${(powerUps.boost.damage*100).toFixed(0)}% damage for
${(powerUps.boost.duration/60).toFixed(0)} seconds`
- if (document.getElementById(`boost-JUNK-id${this.id}`)) document.getElementById(`boost-JUNK-id${this.id}`).innerHTML = this.text
- setTimeout(() => {
- loop()
- }, this.delay);
- }
- }
- setTimeout(() => {
- loop()
- }, this.delay);
- this.id++
- return `
${this.text}`
- },
- },
- {
- name: "placebo",
- description: "
+777% damage+777% defense",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed: () => true,
- requires: "",
- effect() {
- if (Math.random() < 0.1) tech.damage *= 8.77
- },
- remove() {}
- },
- {
- name: "universal healthcare",
- description: "make your
damage negative",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed: () => true,
- requires: "",
- effect() {
- tech.damage *= -1
- },
- remove() {}
- },
- // {
- // name: "synchrotron",
- // descriptionFunction() {
- // return `
power ups change into a different
flavor after a boss dies`
- // },
- // maxCount: 3,
- // count: 0,
- // frequency: 1,
- // frequencyDefault: 1,
- // allowed: () => true,
- // requires: "",
- // effect() {
- // },
- // remove() {
- // }
- // },
- {
- name: "return",
- description: "return to the introduction level
reduce combat
difficulty by
2 levels",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- level.difficultyDecrease(simulation.difficultyMode * 2)
- level.onLevel = 0
- simulation.clearNow = true //end current level
- },
- remove() {}
- },
- {
- name: "panpsychism",
- description: "awaken all
blocksblocks have a chance to spawn power ups",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- setInterval(() => {
- for (let i = body.length - 1; i > -1; i--) {
- if (!body[i].isNotHoldable) {
- Matter.Composite.remove(engine.world, body[i]);
- spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0);
- if (!body[i].isAboutToBeRemoved) mob[mob.length - 1].isDropPowerUp = true
- body.splice(i, 1);
- }
- }
- }, 6000);
- },
- remove() {}
- },
- {
- name: "meteor shower",
- description: "take a shower, but meteors instead of water",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- setInterval(() => {
-
- fireBlock = function(xPos, yPos) {
- const index = body.length
- spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random());
- const bodyBullet = body[index]
- Matter.Body.setVelocity(bodyBullet, {
- x: 5 * (Math.random() - 0.5),
- y: 10 * (Math.random() - 0.5)
- });
- bodyBullet.isAboutToBeRemoved = true
- bodyBullet.collisionFilter.category = cat.body;
- bodyBullet.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
- bodyBullet.classType = "body";
- Composite.add(engine.world, bodyBullet); //add to world
- setTimeout(() => { //remove block
- for (let i = 0; i < body.length; i++) {
- if (body[i] === bodyBullet) {
- Matter.Composite.remove(engine.world, body[i]);
- body.splice(i, 1);
- }
- }
- }, 4000 + Math.floor(9000 * Math.random()));
- }
- fireBlock(player.position.x + 600 * (Math.random() - 0.5), player.position.y - 500 - 500 * Math.random());
- // for (let i = 0, len = Math.random(); i < len; i++) {
- // }
-
- }, 1000);
- },
- remove() {}
- },
- {
- name: "startle response",
- description: `if a threat is nearby, activate a ${powerUps.orb.boost(1)}
and lock your mouse until you press escape`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- // tech.damage *= 1.33
- setInterval(() => {
- if (powerUps.boost.endCycle < m.cycle && !simulation.paused && m.alive) {
- for (let i = 0; i < mob.length; i++) {
- if (mob[i].distanceToPlayer2() < 400000) { //650
- canvas.requestPointerLock();
- powerUps.boost.effect();
- break
- }
- }
- }
- }, 2000);
- },
- remove() {}
- },
- {
- name: "closed timelike curve",
- description: "spawn 5
field power ups, but every 12 seconds
teleport a second into your future or past",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
-
- function loop() {
- if (!simulation.paused && m.alive) {
- if (!(simulation.cycle % 720)) {
- requestAnimationFrame(() => {
- if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option
- m.rewind(60)
- m.energy += 0.4 //to make up for lost energy
- } else {
- simulation.timePlayerSkip(60)
- }
- }); //wrapping in animation frame prevents errors, probably
- }
- }
- requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
- },
- remove() {}
+ }
+ requestAnimationFrame(loop);
},
- // {
- // name: "translate",
- // description: "translate n-gon into a random language",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isJunk: true,
- // isNonRefundable: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {
- // // generate a container
- // const gtElem = document.createElement('div')
- // gtElem.id = "gtElem"
- // gtElem.style.visibility = 'hidden' // make it invisible
- // document.body.append(gtElem)
+ remove() { }
+ },
+ // {
+ // name: "translate",
+ // description: "translate n-gon into a random language",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // isNonRefundable: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // // generate a container
+ // const gtElem = document.createElement('div')
+ // gtElem.id = "gtElem"
+ // gtElem.style.visibility = 'hidden' // make it invisible
+ // document.body.append(gtElem)
- // // generate a script to run after creation
- // function initGT() {
- // // create a new translate element
- // new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem')
- // // ok now since it's loaded perform a funny hack to make it work
- // const langSelect = document.getElementsByClassName("goog-te-combo")[0]
- // // select a random language. It takes a second for all langauges to load, so wait a second.
- // setTimeout(() => {
- // langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random())
- // // simulate a click
- // langSelect.dispatchEvent(new Event('change'))
- // // now make it go away
- // const bar = document.getElementById(':1.container')
- // bar.style.display = 'none'
- // bar.style.visibility = 'hidden'
- // }, 1000)
+ // // generate a script to run after creation
+ // function initGT() {
+ // // create a new translate element
+ // new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem')
+ // // ok now since it's loaded perform a funny hack to make it work
+ // const langSelect = document.getElementsByClassName("goog-te-combo")[0]
+ // // select a random language. It takes a second for all langauges to load, so wait a second.
+ // setTimeout(() => {
+ // langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random())
+ // // simulate a click
+ // langSelect.dispatchEvent(new Event('change'))
+ // // now make it go away
+ // const bar = document.getElementById(':1.container')
+ // bar.style.display = 'none'
+ // bar.style.visibility = 'hidden'
+ // }, 1000)
- // }
+ // }
- // // add the google translate script
- // const translateScript = document.createElement('script')
- // translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT'
- // document.body.append(translateScript)
- // },
- // remove() {}
- // },
- {
- name: "discount",
- description: "get 3 random
JUNKtech for the price of 1!",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- tech.giveRandomJUNK()
- tech.giveRandomJUNK()
- tech.giveRandomJUNK()
- },
- remove() {}
+ // // add the google translate script
+ // const translateScript = document.createElement('script')
+ // translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT'
+ // document.body.append(translateScript)
+ // },
+ // remove() {}
+ // },
+ {
+ name: "discount",
+ description: "get 3 random
JUNKtech for the price of 1!",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.giveRandomJUNK()
+ tech.giveRandomJUNK()
+ tech.giveRandomJUNK()
},
- // {
- // name: "hi",
- // description: `spawn to seed
616 `,
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isNonRefundable: true,
- // isJunk: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {
- // document.getElementById("seed").placeholder = Math.initialSeed = String(616)
- // Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
- // },
- // remove() {}
- // },
- {
- name: "Higgs phase transition",
- description: "instantly spawn 5
tech, but add a chance to
remove everything with a 5 minute
half-life",
- maxCount: 1,
- count: 0,
- frequency: 0,
- frequencyDefault: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- powerUps.spawn(m.pos.x, m.pos.y, "tech");
- powerUps.spawn(m.pos.x + 30, m.pos.y, "tech");
- powerUps.spawn(m.pos.x + 60, m.pos.y, "tech");
- powerUps.spawn(m.pos.x, m.pos.y - 30, "tech");
- powerUps.spawn(m.pos.x + 30, m.pos.y - 60, "tech");
+ remove() { }
+ },
+ // {
+ // name: "hi",
+ // description: `spawn to seed
616 `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // document.getElementById("seed").placeholder = Math.initialSeed = String(616)
+ // Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
+ // },
+ // remove() {}
+ // },
+ {
+ name: "Higgs phase transition",
+ description: "instantly spawn 5
tech, but add a chance to
remove everything with a 5 minute
half-life",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ powerUps.spawn(m.pos.x + 30, m.pos.y, "tech");
+ powerUps.spawn(m.pos.x + 60, m.pos.y, "tech");
+ powerUps.spawn(m.pos.x, m.pos.y - 30, "tech");
+ powerUps.spawn(m.pos.x + 30, m.pos.y - 60, "tech");
- function loop() {
- // (1-X)^cycles = chance to be removed //Math.random() < 0.000019 10 min
- if (!simulation.paused && m.alive) {
- if (Math.random() < 0.000038) {
- // m.death();
- simulation.clearMap();
- simulation.draw.setPaths();
- return
- }
+ function loop() {
+ // (1-X)^cycles = chance to be removed //Math.random() < 0.000019 10 min
+ if (!simulation.paused && m.alive) {
+ if (Math.random() < 0.000038) {
+ // m.death();
+ simulation.clearMap();
+ simulation.draw.setPaths();
+ return
}
- requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
- },
- remove() {}
+ }
+ requestAnimationFrame(loop);
},
- {
- name: "harvest",
- description: "convert all the mobs on this level into
ammo",
- maxCount: 1,
- count: 0,
- frequency: 0,
- frequencyDefault: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- for (let i = 0, len = mob.length; i < len; i++) {
- if (mob[i].isDropPowerUp) {
- powerUps.directSpawn(mob[i].position.x, mob[i].position.y, "ammo");
- mob[i].death();
- }
+ remove() { }
+ },
+ {
+ name: "harvest",
+ description: "convert all the mobs on this level into
ammo",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isDropPowerUp) {
+ powerUps.directSpawn(mob[i].position.x, mob[i].position.y, "ammo");
+ mob[i].death();
}
- // for (let i = powerUp.length - 1; i > -1; i--) {
- // if (powerUp[i].name !== "ammo") {
- // Matter.Composite.remove(engine.world, powerUp[i]);
- // powerUp.splice(i, 1);
- // }
- // }
- },
- remove() {}
+ }
+ // for (let i = powerUp.length - 1; i > -1; i--) {
+ // if (powerUp[i].name !== "ammo") {
+ // Matter.Composite.remove(engine.world, powerUp[i]);
+ // powerUp.splice(i, 1);
+ // }
+ // }
},
- {
- name: "brainstorm",
- description: "the
tech choice menu
randomizesevery
0.5 seconds for
10 seconds",
- maxCount: 1,
- count: 0,
- frequency: 0,
- frequencyDefault: 0,
- isJunk: true,
- allowed: () => true,
- requires: "",
- effect() {
- tech.isBrainstorm = true
- tech.isBrainstormActive = false
- tech.brainStormDelay = 500
- },
- remove() {
- tech.isBrainstorm = false
- tech.isBrainstormActive = false
+ remove() { }
+ },
+ {
+ name: "brainstorm",
+ description: "the
tech choice menu
randomizesevery
0.5 seconds for
10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isBrainstorm = true
+ tech.isBrainstormActive = false
+ tech.brainStormDelay = 500
+ },
+ remove() {
+ tech.isBrainstorm = false
+ tech.isBrainstormActive = false
+ }
+ },
+ {
+ name: "catabolysis",
+ description: `set your maximum
health to
1double your current
ammo 10 times`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth
+ },
+ requires: "not quenching, tungsten carbide, mass-energy",
+ effect() {
+ m.baseHealth = 0.01
+ m.setMaxHealth();
+ for (let i = 0; i < b.guns.length; i++) b.guns[i].ammo = b.guns[i].ammo * Math.pow(2, 10)
+ simulation.updateGunHUD();
+ },
+ remove() { }
+ },
+ {
+ name: "palantír",
+ description: `see far away lands`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ // isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.look = () => {
+ //always on mouse look
+ m.angle = Math.atan2(
+ simulation.mouseInGame.y - m.pos.y,
+ simulation.mouseInGame.x - m.pos.x
+ );
+ //smoothed mouse look translations
+ const scale = 2;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
}
},
- {
- name: "catabolysis",
- description: `set your maximum
health to
1double your current
ammo 10 times`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth
- },
- requires: "not quenching, tungsten carbide, mass-energy",
- effect() {
- m.baseHealth = 0.01
- m.setMaxHealth();
- for (let i = 0; i < b.guns.length; i++) b.guns[i].ammo = b.guns[i].ammo * Math.pow(2, 10)
- simulation.updateGunHUD();
- },
- remove() {}
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "motion sickness",
+ description: `disable camera smoothing`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ // isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
},
- {
- name: "palantír",
- description: `see far away lands`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- // isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- m.look = () => {
- //always on mouse look
- m.angle = Math.atan2(
- simulation.mouseInGame.y - m.pos.y,
- simulation.mouseInGame.x - m.pos.x
- );
- //smoothed mouse look translations
- const scale = 2;
- m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
- m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
- m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
- m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
- }
- },
- remove() {
- if (this.count) m.look = m.lookDefault
+ requires: "",
+ effect() {
+ m.look = () => {
+ //always on mouse look
+ m.angle = Math.atan2(
+ simulation.mouseInGame.y - m.pos.y,
+ simulation.mouseInGame.x - m.pos.x
+ );
+ //smoothed mouse look translations
+ const scale = 1.2;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ // m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ // m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
}
},
- {
- name: "motion sickness",
- description: `disable camera smoothing`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- // isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- m.look = () => {
- //always on mouse look
- m.angle = Math.atan2(
- simulation.mouseInGame.y - m.pos.y,
- simulation.mouseInGame.x - m.pos.x
- );
- //smoothed mouse look translations
- const scale = 1.2;
- m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
- m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
- m.transX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
- m.transY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
- // m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
- // m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
- }
- },
- remove() {
- if (this.count) m.look = m.lookDefault
- }
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "facsimile",
+ description: `inserts a copy of your current level into the level list`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
},
- {
- name: "facsimile",
- description: `inserts a copy of your current level into the level list`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- const index = Math.min(level.levels.length - 1, level.onLevel)
- level.levels.splice(index, 0, level.levels[index]);
- },
- remove() {}
+ requires: "",
+ effect() {
+ const index = Math.min(level.levels.length - 1, level.onLevel)
+ level.levels.splice(index, 0, level.levels[index]);
},
- {
- name: "negative friction",
- description: "when you touch walls you speed up instead of slowing down. It's kinda fun.",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- player.friction = -0.4
- },
- remove() {
- if (this.count) player.friction = 0.002
- }
+ remove() { }
+ },
+ {
+ name: "negative friction",
+ description: "when you touch walls you speed up instead of slowing down. It's kinda fun.",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
},
- {
- name: "bounce",
- description: "you bounce off things. It's annoying, but not that bad.",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- player.restitution = 0.9
- },
- remove() {
- if (this.count) player.restitution = 0
- }
+ requires: "",
+ effect() {
+ player.friction = -0.4
},
- {
- name: "mouth",
- description: "mobs have a non functional mouth",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- mobs.draw = () => {
- ctx.lineWidth = 2;
- let i = mob.length;
- while (i--) {
- ctx.beginPath();
- const vertices = mob[i].vertices;
- ctx.moveTo(vertices[0].x, vertices[0].y);
- for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
- ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
- ctx.fillStyle = mob[i].fill;
- ctx.strokeStyle = mob[i].stroke;
- ctx.fill();
- ctx.stroke();
- }
- }
- },
- remove() {
- mobs.draw = () => {
- ctx.lineWidth = 2;
- let i = mob.length;
- while (i--) {
- ctx.beginPath();
- const vertices = mob[i].vertices;
- ctx.moveTo(vertices[0].x, vertices[0].y);
- for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
- ctx.lineTo(vertices[0].x, vertices[0].y);
- ctx.fillStyle = mob[i].fill;
- ctx.strokeStyle = mob[i].stroke;
- ctx.fill();
- ctx.stroke();
- }
+ remove() {
+ if (this.count) player.friction = 0.002
+ }
+ },
+ {
+ name: "bounce",
+ description: "you bounce off things. It's annoying, but not that bad.",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ player.restitution = 0.9
+ },
+ remove() {
+ if (this.count) player.restitution = 0
+ }
+ },
+ {
+ name: "mouth",
+ description: "mobs have a non functional mouth",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ mobs.draw = () => {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
}
}
},
- {
- name: "all-stars",
- description: "make all mobs look like stars",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- mobs.draw = () => {
- ctx.lineWidth = 2;
- let i = mob.length;
- while (i--) {
- ctx.beginPath();
- const vertices = mob[i].vertices;
- ctx.moveTo(vertices[0].x, vertices[0].y);
- for (let j = 1, len = vertices.length; j < len; ++j) ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y);
- ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
- ctx.fillStyle = mob[i].fill;
- ctx.strokeStyle = mob[i].stroke;
- ctx.fill();
- ctx.stroke();
- }
+ remove() {
+ mobs.draw = () => {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
}
- },
- remove() {
- mobs.draw = () => {
- ctx.lineWidth = 2;
- let i = mob.length;
- while (i--) {
- ctx.beginPath();
- const vertices = mob[i].vertices;
- ctx.moveTo(vertices[0].x, vertices[0].y);
- for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
- ctx.lineTo(vertices[0].x, vertices[0].y);
- ctx.fillStyle = mob[i].fill;
- ctx.strokeStyle = mob[i].stroke;
- ctx.fill();
- ctx.stroke();
- }
+ }
+ }
+ },
+ {
+ name: "all-stars",
+ description: "make all mobs look like stars",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ mobs.draw = () => {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y);
+ ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
}
}
},
- // draw() {
- // ctx.lineWidth = 2;
- // let i = mob.length;
- // while (i--) {
- // ctx.beginPath();
- // const vertices = mob[i].vertices;
- // ctx.moveTo(vertices[0].x, vertices[0].y);
- // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
- // ctx.lineTo(vertices[0].x, vertices[0].y);
- // ctx.fillStyle = mob[i].fill;
- // ctx.strokeStyle = mob[i].stroke;
- // ctx.fill();
- // ctx.stroke();
- // }
- // },
- {
- name: "true colors",
- description: `set all power ups to their real world colors`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- // const colors = shuffle(["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"])
- const colors = shuffle([powerUps.research.color, powerUps.heal.color, powerUps.ammo.color, powerUps.ammo.color, powerUps.field.color, powerUps.gun.color])
- powerUps.research.color = colors[0]
- powerUps.heal.color = colors[1]
- powerUps.ammo.color = colors[2]
- powerUps.field.color = colors[3]
- powerUps.tech.color = colors[4]
- powerUps.gun.color = colors[5]
- for (let i = 0; i < powerUp.length; i++) {
- switch (powerUp[i].name) {
- case "research":
- powerUp[i].color = colors[0]
- break;
- case "heal":
- powerUp[i].color = colors[1]
- break;
- case "ammo":
- powerUp[i].color = colors[2]
- break;
- case "field":
- powerUp[i].color = colors[3]
- break;
- case "tech":
- powerUp[i].color = colors[4]
- break;
- case "gun":
- powerUp[i].color = colors[5]
- break;
- }
+ remove() {
+ mobs.draw = () => {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
+ }
+ }
+ }
+ },
+ // draw() {
+ // ctx.lineWidth = 2;
+ // let i = mob.length;
+ // while (i--) {
+ // ctx.beginPath();
+ // const vertices = mob[i].vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.fillStyle = mob[i].fill;
+ // ctx.strokeStyle = mob[i].stroke;
+ // ctx.fill();
+ // ctx.stroke();
+ // }
+ // },
+ {
+ name: "true colors",
+ description: `set all power ups to their real world colors`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ // const colors = shuffle(["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"])
+ const colors = shuffle([powerUps.research.color, powerUps.heal.color, powerUps.ammo.color, powerUps.ammo.color, powerUps.field.color, powerUps.gun.color])
+ powerUps.research.color = colors[0]
+ powerUps.heal.color = colors[1]
+ powerUps.ammo.color = colors[2]
+ powerUps.field.color = colors[3]
+ powerUps.tech.color = colors[4]
+ powerUps.gun.color = colors[5]
+ for (let i = 0; i < powerUp.length; i++) {
+ switch (powerUp[i].name) {
+ case "research":
+ powerUp[i].color = colors[0]
+ break;
+ case "heal":
+ powerUp[i].color = colors[1]
+ break;
+ case "ammo":
+ powerUp[i].color = colors[2]
+ break;
+ case "field":
+ powerUp[i].color = colors[3]
+ break;
+ case "tech":
+ powerUp[i].color = colors[4]
+ break;
+ case "gun":
+ powerUp[i].color = colors[5]
+ break;
}
- },
- remove() {
- // const colors = ["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"] //no shuffle
- // powerUps.research.color = colors[0]
- // powerUps.heal.color = colors[1]
- // powerUps.ammo.color = colors[2]
- // powerUps.field.color = colors[3]
- // powerUps.tech.color = colors[4]
- // powerUps.gun.color = colors[5]
- // for (let i = 0; i < powerUp.length; i++) {
- // switch (powerUp[i].name) {
- // case "research":
- // powerUp[i].color = colors[0]
- // break;
- // case "heal":
- // powerUp[i].color = colors[1]
- // break;
- // case "ammo":
- // powerUp[i].color = colors[2]
- // break;
- // case "field":
- // powerUp[i].color = colors[3]
- // break;
- // case "tech":
- // powerUp[i].color = colors[4]
- // break;
- // case "gun":
- // powerUp[i].color = colors[5]
- // break;
- // }
- // }
}
},
- {
- name: "emergency broadcasting",
- description: "emit 2 sine waveforms at 853 Hz and 960 Hz
lower your volume",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return true
- },
- requires: "",
- effect: () => {
- //setup audio context
- function tone(frequency) {
- const audioCtx = new(window.AudioContext || window.webkitAudioContext)();
- const oscillator1 = audioCtx.createOscillator();
- const gainNode1 = audioCtx.createGain();
- gainNode1.gain.value = 0.5; //controls volume
- oscillator1.connect(gainNode1);
- gainNode1.connect(audioCtx.destination);
- oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
- oscillator1.frequency.value = frequency; // value in hertz
- oscillator1.start();
- return audioCtx
- }
- // let sound = tone(1050)
+ remove() {
+ // const colors = ["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"] //no shuffle
+ // powerUps.research.color = colors[0]
+ // powerUps.heal.color = colors[1]
+ // powerUps.ammo.color = colors[2]
+ // powerUps.field.color = colors[3]
+ // powerUps.tech.color = colors[4]
+ // powerUps.gun.color = colors[5]
+ // for (let i = 0; i < powerUp.length; i++) {
+ // switch (powerUp[i].name) {
+ // case "research":
+ // powerUp[i].color = colors[0]
+ // break;
+ // case "heal":
+ // powerUp[i].color = colors[1]
+ // break;
+ // case "ammo":
+ // powerUp[i].color = colors[2]
+ // break;
+ // case "field":
+ // powerUp[i].color = colors[3]
+ // break;
+ // case "tech":
+ // powerUp[i].color = colors[4]
+ // break;
+ // case "gun":
+ // powerUp[i].color = colors[5]
+ // break;
+ // }
+ // }
+ }
+ },
+ {
+ name: "emergency broadcasting",
+ description: "emit 2 sine waveforms at 853 Hz and 960 Hz
lower your volume",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect: () => {
+ //setup audio context
+ function tone(frequency) {
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+ const oscillator1 = audioCtx.createOscillator();
+ const gainNode1 = audioCtx.createGain();
+ gainNode1.gain.value = 0.5; //controls volume
+ oscillator1.connect(gainNode1);
+ gainNode1.connect(audioCtx.destination);
+ oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator1.frequency.value = frequency; // value in hertz
+ oscillator1.start();
+ return audioCtx
+ }
+ // let sound = tone(1050)
- function EBS() {
- const audioCtx = new(window.AudioContext || window.webkitAudioContext)();
+ function EBS() {
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
- const oscillator1 = audioCtx.createOscillator();
- const gainNode1 = audioCtx.createGain();
- gainNode1.gain.value = 0.3; //controls volume
- oscillator1.connect(gainNode1);
- gainNode1.connect(audioCtx.destination);
- oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
- oscillator1.frequency.value = 850; // value in hertz
- oscillator1.start();
+ const oscillator1 = audioCtx.createOscillator();
+ const gainNode1 = audioCtx.createGain();
+ gainNode1.gain.value = 0.3; //controls volume
+ oscillator1.connect(gainNode1);
+ gainNode1.connect(audioCtx.destination);
+ oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator1.frequency.value = 850; // value in hertz
+ oscillator1.start();
- const oscillator2 = audioCtx.createOscillator();
- const gainNode2 = audioCtx.createGain();
- gainNode2.gain.value = 0.3; //controls volume
- oscillator2.connect(gainNode2);
- gainNode2.connect(audioCtx.destination);
- oscillator2.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
- oscillator2.frequency.value = 957; // value in hertz
- oscillator2.start();
- return audioCtx
- }
- let sound = EBS()
+ const oscillator2 = audioCtx.createOscillator();
+ const gainNode2 = audioCtx.createGain();
+ gainNode2.gain.value = 0.3; //controls volume
+ oscillator2.connect(gainNode2);
+ gainNode2.connect(audioCtx.destination);
+ oscillator2.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator2.frequency.value = 957; // value in hertz
+ oscillator2.start();
+ return audioCtx
+ }
+ let sound = EBS()
- delay = 1000
+ delay = 1000
+ setTimeout(() => {
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
- sound.suspend()
- powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ sound.resume()
setTimeout(() => {
- sound.resume()
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
- sound.suspend()
- powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ sound.resume()
setTimeout(() => {
- sound.resume()
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
- sound.suspend()
- powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ sound.resume()
setTimeout(() => {
- sound.resume()
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
- sound.suspend()
- powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ sound.resume()
setTimeout(() => {
- sound.resume()
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
- sound.suspend()
- powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ sound.resume()
setTimeout(() => {
- sound.resume()
- setTimeout(() => {
- sound.suspend()
- sound.close()
- powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
- }, delay);
+ sound.suspend()
+ sound.close()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
}, delay);
}, delay);
}, delay);
@@ -9473,1567 +9472,1568 @@ const tech = {
}, delay);
}, delay);
}, delay);
- },
- remove() {}
+ }, delay);
},
- {
- name: "automatic",
- description: "you can't fire when moving
always
fire when at
rest",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return !tech.isFireMoveLock
- },
- requires: "not Higgs mechanism",
- effect() {
- tech.isAlwaysFire = true;
+ remove() { }
+ },
+ {
+ name: "automatic",
+ description: "you can't fire when moving
always
fire when at
rest",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !tech.isFireMoveLock
+ },
+ requires: "not Higgs mechanism",
+ effect() {
+ tech.isAlwaysFire = true;
+ b.setFireMethod();
+ },
+ remove() {
+ if (tech.isAlwaysFire) {
+ tech.isAlwaysFire = false
b.setFireMethod();
- },
- remove() {
- if (tech.isAlwaysFire) {
- tech.isAlwaysFire = false
- b.setFireMethod();
- }
- }
- },
- {
- name: "hidden variable",
- descriptionFunction() {
- return `spawn ${powerUps.orb.heal(20)}
but hide your
health bar`
- },
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- document.getElementById("health").style.display = "none"
- document.getElementById("health-bg").style.display = "none"
- document.getElementById("defense-bar").style.display = "none"
- for (let i = 0; i < 20; i++) powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
- },
- remove() {}
- },
- {
- name: "not a bug",
- description: "initiate a totally safe game crash for 10 seconds",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- const savedfunction = simulation.drawCircle
- simulation.drawCircle = () => {
- const a = mob[Infinity].position //crashed the game in a visually interesting way, because of the ctx.translate command is never reverted in the main game loop
- }
- setTimeout(() => {
- simulation.drawCircle = savedfunction
- canvas.width = canvas.width //clears the canvas // works on chrome at least
- powerUps.spawn(m.pos.x, m.pos.y, "tech");
- }, 10000);
-
- // for (;;) {} //freezes the tab
- },
- remove() {}
- },
- {
- name: "spinor",
- description: "the direction you aim is determined by your position",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.look = function() {
- //always on mouse look
- m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI
- //smoothed mouse look translations
- const scale = 0.8;
- m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
- m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
-
- m.transX += (m.transSmoothX - m.transX) * 0.07;
- m.transY += (m.transSmoothY - m.transY) * 0.07;
- }
- },
- remove() {
- if (this.count) m.look = m.lookDefault
- }
- },
- {
- name: "p-zombie",
- description: "set your
health to
1all mobs, not bosses, die and
resurrect as zombies",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() { return true },
- requires: "",
- effect() {
- m.health = 0.01 //set health to 1
- m.displayHealth();
- for (let i = mob.length - 1; i > -1; i--) { //replace mobs with zombies
- if (mob[i].isDropPowerUp && !mob[i].isBoss && mob[i].alive) {
- mob[i].isSoonZombie = true
- mob[i].death()
- }
- }
- },
- remove() {}
- },
- {
- name: "decomposers",
- description: "after they die
mobs leave behind
spawns",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return tech.deathSpawns === 0
- },
- requires: "",
- effect() {
- tech.deathSpawns = 0.2
- },
- remove() {
- tech.deathSpawns = 0
- }
- },
- {
- name: "panopticon",
- description: "
mobs can always see you",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- for (let i = 0; i < mob.length; i++) {
- if (!mob[i].shield && mob[i].isDropPowerUp) {
- mob[i].locatePlayer()
- mob[i].seePlayer.yes = true;
- }
- }
- }, 1000); //every 1 seconds
- },
- remove() {}
- },
- // {
- // name: "inverted mouse",
- // description: "your mouse is scrambled
it's fine, just rotate it 90 degrees",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isExperimentHide: true,
- // isNonRefundable: true,
- // isJunk: true,
- // allowed() {
- // return !m.isShipMode
- // },
- // requires: "not ship",
- // effect() {
- // document.body.addEventListener("mousemove", (e) => {
- // const ratio = window.innerWidth / window.innerHeight
- // simulation.mouse.x = e.clientY * ratio
- // simulation.mouse.y = e.clientX / ratio;
- // });
- // },
- // remove() {
- // // m.look = m.lookDefault
- // }
- // },
- {
- name: "Fourier analysis",
- description: "your aiming is now controlled by this equation:
2sin(0.0133t) + sin(0.013t) + 0.5sin(0.031t)+ 0.33sin(0.03t)",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "not ship",
- effect() {
- m.look = () => {
- m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03)
- const scale = 0.8;
- simulation.mouse.y
- m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
- m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
- m.transX += (m.transSmoothX - m.transX) * 0.07;
- m.transY += (m.transSmoothY - m.transY) * 0.07;
- }
- },
- remove() {
- if (this.count) m.look = m.lookDefault
- }
- },
- {
- name: "disintegrated armament",
- description: "spawn a
gunremove your active
gun",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return b.inventory.length > 0
- },
- requires: "at least 1 gun",
- effect() {
- if (b.inventory.length > 0) b.removeGun(b.guns[b.activeGun].name)
- simulation.makeGunHUD()
- powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
- },
- remove() {}
- },
- {
- name: "probability",
- description: "increase the
frequencyof one random
tech by
100",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- let options = []; //find what tech I could get
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (
- tech.tech[i].count < tech.tech[i].maxCount &&
- tech.tech[i].allowed() &&
- !tech.tech[i].isJunk &&
- !tech.tech.isLore
- ) {
- options.push(i);
- }
- }
- if (options.length) {
- const index = options[Math.floor(Math.random() * options.length)]
- tech.tech[index].frequency = 100
- }
- },
- remove() {}
- },
- {
- name: "encryption",
- description: "secure
tech information",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- String.prototype.shuffle = function() {
- var a = this.split(""),
- n = a.length;
-
- for (var i = n - 1; i > 0; i--) {
- var j = Math.floor(Math.random() * (i + 1));
- var tmp = a[i];
- a[i] = a[j];
- a[j] = tmp;
- }
- return a.join("");
- }
-
- for (let i = 0, len = tech.tech.length; i < len; i++) tech.tech[i].name = tech.tech[i].name.shuffle()
- },
- remove() {}
- },
- {
- name: "quantum leap",
- description: "become an
alternate version of yourself
every
20 seconds",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- m.switchWorlds()
- simulation.trails()
- }, 20000); //every 30 seconds
- },
- remove() {}
- },
- {
- name: "score",
- description: "Add a score to n-gon!",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- let score = Math.ceil(1000 * Math.random() * Math.random() * Math.random() * Math.random() * Math.random())
- simulation.makeTextLog(`simulation.score
= ${score.toFixed(0)}`);
- }, 10000); //every 10 seconds
- },
- remove() {}
- },
- {
- name: "pop-ups",
- description: "sign up to learn endless easy ways to win n-gon
that Landgreen doesn't want you to know!!!1!!",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- alert(`The best combo is ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name} with ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name}!`);
- }, 30000); //every 30 seconds
- },
- remove() {}
- },
- {
- name: "music",
- description: "add music to n-gon",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- window.open('https://www.youtube.com/watch?v=lEbHeSdmS-k&list=PL9Z5wjoBiPKEDhwCW2RN-VZoCpmhIojdn', '_blank')
- },
- remove() {}
- },
- {
- name: "performance",
- description: "display performance stats to n-gon",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- (function() {
- var script = document.createElement('script');
- script.onload = function() {
- var stats = new Stats();
- document.body.appendChild(stats.dom);
- requestAnimationFrame(function loop() {
- stats.update();
- requestAnimationFrame(loop)
- });
- };
- script.src = 'https://unpkg.com/stats.js@0.17.0/build/stats.min.js';
- document.head.appendChild(script);
- })()
- //move health to the right
- document.getElementById("health").style.left = "86px"
- document.getElementById("health-bg").style.left = "86px"
- document.getElementById("defense-bar").style.left = "86px"
- document.getElementById("damage-bar").style.left = "86px"
- },
- remove() {}
- },
- {
- name: "repartitioning",
- description: "set the
frequency of finding normal
tech to
0spawn 5
tech",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0, len = tech.tech.length; i < len; i++) {
- if (tech.tech[i].isJunk) {
- tech.tech[i].frequency = 2
- } else {
- tech.tech[i].frequency = 0
- }
- }
- for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech");
- },
- remove() {}
- },
- {
- name: "defragment",
- description: "set the
frequency of finding
JUNKtech to zero",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = tech.tech.length - 1; i > 0; i--) {
- if (tech.tech[i].isJunk) tech.tech[i].frequency = 0
- }
- },
- remove() {}
- },
- // {
- // name: "lubrication",
- // description: "reduce block density and friction for this level",
- // maxCount: 9,
- // count: 0,
- // frequency: 0,
- // isNonRefundable: true,
- // isExperimentHide: true,
- // isJunk: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {
- // for (let i = 0; i < body.length; i++) {
- // Matter.Body.setDensity(body[i], 0.0001) // 0.001 is normal
- // body[i].friction = 0.01
- // }
- // },
- // remove() {}
- // },
- {
- name: "pitch",
- description: "oscillate the pitch of your world",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01))
- }, 16);
- },
- remove() {}
- },
- {
- name: "umbra",
- description: "produce a blue glow around everything
and probably some simulation lag",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- ctx.shadowColor = '#06f';
- ctx.shadowBlur = 25;
- },
- remove() {}
- },
- {
- name: "lighter",
- description: `ctx.globalCompositeOperation = "lighter"`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name !== "negative mass"
- },
- requires: "",
- effect() {
- ctx.globalCompositeOperation = "lighter";
- },
- remove() {}
- },
- {
- name: "rewind",
- description: "every 10 seconds
rewind 2 seconds",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- m.rewind(120)
- m.energy += 0.4
- }, 10000);
- // for (let i = 0; i < 24; i++) {
- // setTimeout(() => { m.rewind(120) }, i * 5000);
- // }
- },
- remove() {}
- },
- {
- name: "undo",
- description: "every 4 seconds
rewind 1/2 a second",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- m.rewind(30)
- m.energy += 0.2
- }, 4000);
- },
- remove() {}
- },
- {
- name: "energy to mass conversion",
- description: "convert your
energy into
blocks",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0, len = 40; i < len; i++) {
- setTimeout(() => {
- m.energy -= 1 / len
- const index = body.length
- where = Vector.add(m.pos, {
- x: 400 * (Math.random() - 0.5),
- y: 400 * (Math.random() - 0.5)
- })
- spawn.bodyRect(where.x, where.y, Math.floor(15 + 100 * Math.random()), Math.floor(15 + 100 * Math.random()));
- body[index].collisionFilter.category = cat.body;
- body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
- body[index].classType = "body";
- Composite.add(engine.world, body[index]); //add to world
- }, i * 100);
- }
-
- },
- remove() {}
- },
- {
- name: "level.nextLevel()",
- description: "advance to the next level",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- level.nextLevel();
- },
- remove() {}
- },
- {
- name: "reincarnation",
- description: "kill all mobs and spawn new ones
(also spawn a few extra mobs for fun)",
- maxCount: 3,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- spawn.setSpawnList();
- spawn.setSpawnList();
- for (let i = 0, len = mob.length; i < len; i++) {
- if (mob[i].alive && !mob[i].shield && !mob[i].isBadTarget) {
- const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
- spawn[pick](mob[i].position.x, mob[i].position.y);
- if (Math.random() < 0.5) spawn[pick](mob[i].position.x, mob[i].position.y);
- mob[i].death();
- }
- }
- },
- remove() {}
- },
- {
- name: "expert system",
- description: "spawn a
tech power up
+64% JUNK to
tech pool",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- powerUps.spawn(m.pos.x, m.pos.y, "tech");
- tech.addJunkTechToPool(0.64)
- },
- remove() {}
- },
- {
- name: "energy investment",
- description: "every 10 seconds drain your
energyreturn it doubled 5 seconds later",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- if (!simulation.paused) {
- const energy = m.energy
- m.energy = 0
- setTimeout(() => { //return energy
- m.energy += 2 * energy
- }, 5000);
- }
- }, 10000);
- },
- remove() {}
- },
- {
- name: "missile launching system",
- description: "fire missiles for the next 120 seconds",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0; i < 120; i++) {
- setTimeout(() => {
- const where = {
- x: m.pos.x,
- y: m.pos.y - 40
- }
- b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2)
- }, i * 1000);
- }
- },
- remove() {}
- },
- {
- name: "grenade production",
- description: "drop a grenade every 2 seconds",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- setInterval(() => {
- if (!simulation.paused && document.visibilityState !== "hidden") {
- b.grenade(Vector.add(m.pos, {
- x: 10 * (Math.random() - 0.5),
- y: 10 * (Math.random() - 0.5)
- }), -Math.PI / 2) //fire different angles for each grenade
- const who = bullet[bullet.length - 1]
- Matter.Body.setVelocity(who, {
- x: who.velocity.x * 0.1,
- y: who.velocity.y * 0.1
- });
- }
- }, 2000);
- },
- remove() {}
- },
- {
- name: "stubs",
- description: "no knees or toes are drawn on the player
you can wall climb though",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isSkin: true,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.skin.stubs()
- Matter.Body.scale(player.parts[3], 2, 2);
- },
- remove() {
- // if (this.count) m.resetSkin();
- }
- },
- {
- name: "Sleipnir",
- description: "grow more legs",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isSkin: true,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.skin.Sleipnir()
- },
- remove() {
- if (this.count) m.resetSkin();
- }
- },
- {
- name: "diegesis",
- description: "indicate fire cooldown
through a rotation of your head",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isSkin: true,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.skin.diegesis()
- },
- remove() {
- if (this.count) m.resetSkin();
- }
- },
- {
- name: "🐱",
- description: "🐈",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isSkin: true,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.skin.cat();
- },
- remove() {
- if (this.count) m.resetSkin();
- }
- },
- {
- name: "n-gone",
- description: "become invisible to yourself
mobs can still see you",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isSkin: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- m.draw = () => {}
- },
- remove() {
- if (this.count) m.resetSkin();
- }
- },
- {
- name: "pareidolia",
- description: "don't",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isSkin: true,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.skin.pareidolia()
- },
- remove() {
- if (this.count) m.resetSkin();
- }
- },
- {
- name: "posture",
- description: "stand a bit taller",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- m.yOffWhen.stand = 70
- },
- remove() {
- m.yOffWhen.stand = 49
- }
- },
- {
- name: "rhythm",
- description: "you oscillate up and down",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return !m.isShipMode
- },
- requires: "",
- effect() {
- setInterval(() => {
- m.yOffWhen.stand = 53 + 28 * Math.sin(simulation.cycle * 0.2)
- if (m.onGround && !m.crouch) m.yOffGoal = m.yOffWhen.stand
- }, 100);
- },
- remove() {}
- },
- {
- name: "prism",
- description: "you cycle through different
colors",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- m.color = {
- hue: 0,
- sat: 100,
- light: 50
- }
- setInterval(function() {
- m.color.hue++
- m.setFillColors()
- }, 10);
- },
- remove() {}
- },
- // {
- // name: "microtransactions",
- // description: `when you choose a
tech you can
use ${powerUps.orb.research(1)} to buy a free in game
skin`,
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isJunk: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {
- // tech.isMicroTransactions = true
- // },
- // remove() {
- // tech.isMicroTransactions = false
- // }
- // },
- {
- name: "ship",
- description: "fly around with no legs
reduce combat
difficulty by
1 level",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return !m.isShipMode && !m.isAltSkin && m.fieldUpgrades[m.fieldMode].name !== "negative mass"
- },
- requires: "",
- effect() {
- m.isAltSkin = true
- m.shipMode()
- level.difficultyDecrease(simulation.difficultyMode)
- //unlock relativistic rotation
- for (let i = 0; i < tech.tech.length; i++) {
- if (tech.tech[i].name === "relativistic rotation") tech.tech[i].frequency = 10
- }
- },
- remove() {}
- },
- {
- name: "circular symmetry",
- description: "turning the ship rotates the universe instead
+200% damage",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return m.isShipMode
- },
- requires: "",
- effect() {
- tech.damage *= 3
-
- m.look = () => {
- // const scale = 0;
- m.transSmoothX = canvas.width2 - m.pos.x // - (simulation.mouse.x - canvas.width2) * scale;
- m.transSmoothY = canvas.height2 - m.pos.y // - (simulation.mouse.y - canvas.height2) * scale;
- m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
- m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
- ctx.restore();
- ctx.save();
- ctx.translate(canvas.width2, canvas.height2); //center
- ctx.rotate(-m.angle)
- ctx.translate(-canvas.width2, -canvas.height2); //center
- }
- },
- remove() {}
- },
- {
- name: "assimilation",
- description: "all your
bots are converted to the
same random model",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isBotTech: true,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return b.totalBots() > 2
- },
- requires: "at least 3 bots",
- effect() {
- const total = b.totalBots();
- tech.dynamoBotCount = 0;
- tech.nailBotCount = 0;
- tech.laserBotCount = 0;
- tech.orbitBotCount = 0;
- tech.foamBotCount = 0;
- tech.boomBotCount = 0;
- tech.plasmaBotCount = 0;
- tech.missileBotCount = 0;
- for (let i = 0; i < bullet.length; i++) {
- if (bullet[i].botType) bullet[i].endCycle = 0
- }
-
- const bots = [
- () => {
- b.nailBot();
- tech.nailBotCount++;
- },
- () => {
- b.foamBot();
- tech.foamBotCount++;
- },
- () => {
- b.boomBot();
- tech.boomBotCount++;
- },
- () => {
- b.laserBot();
- tech.laserBotCount++;
- },
- () => {
- b.orbitBot();
- tech.orbitBotCount++
- },
- () => {
- b.dynamoBot();
- tech.dynamoBotCount++
- }
- ]
- const index = Math.floor(Math.random() * bots.length)
- for (let i = 0; i < total; i++) bots[index]()
- },
- remove() {}
- },
- {
- name: "growth hacking",
- description: "increase combat
difficulty by
1 level",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- level.difficultyIncrease(simulation.difficultyMode)
- },
- remove() {}
- },
- {
- name: "stun",
- description: "
stun all mobs for up to
8 seconds",
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480)
- },
- remove() {}
- },
- {
- name: "translucent",
- description: "spawn
3 gun power ups
your
bullets and bots are transparent",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
-
- // //removes guns and ammo
- // b.inventory = [];
- // b.activeGun = null;
- // b.inventoryGun = 0;
- // for (let i = 0, len = b.guns.length; i < len; ++i) {
- // b.guns[i].have = false;
- // if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0;
- // }
- // simulation.makeGunHUD(); //update gun HUD
- b.bulletDraw = () => {}; //make bullets invisible
- },
- remove() {}
- },
- {
- name: "re-research",
- description: `
eject all your ${powerUps.orb.research(1)}`,
- maxCount: 9,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return powerUps.research.count > 3
- },
- requires: "at least 4 research",
- effect() {
- powerUps.spawnDelay("research", powerUps.research.count);
- powerUps.research.count = 0
- },
- remove() {}
- },
- {
- name: "black hole",
- description: `use your
energy and ${powerUps.orb.research(4)} to
spawninside the event horizon of a huge
black hole`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return powerUps.research.count > 3
- },
- requires: "at least 4 research",
- effect() {
- m.energy = 0
- spawn.suckerBoss(m.pos.x, m.pos.y - 700)
- powerUps.research.changeRerolls(-4)
- simulation.makeTextLog(`
m.
research --${powerUps.research.count}`)
- },
- remove() {}
- },
- {
- name: "black hole cluster",
- description: `spawn
30 nearby
black holes`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- const unit = {
- x: 1,
- y: 0
- }
- for (let i = 0; i < 30; i++) {
- const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random()))
- spawn.sucker(where.x, where.y, 140)
- const who = mob[mob.length - 1]
- who.locatePlayer()
- // who.damageReduction = 0.2
- }
- },
- remove() {}
- },
- {
- name: "rule 30",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return !build.isExperimentSelection
- },
- requires: "NOT EXPERIMENT MODE",
- effect() {},
- remove() {},
- state: [
- [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false]
- ],
- rule(state, a, b, c) {
- //30
- if (state[a] && state[b] && state[c]) return false; // TTT => F
- if (state[a] && state[b] && !state[c]) return false; // TTF => F
- if (state[a] && !state[b] && state[c]) return false; //TFT => F
- if (state[a] && !state[b] && !state[c]) return true; //TFF => T
- if (!state[a] && state[b] && state[c]) return true; //FTT => T
- if (!state[a] && state[b] && !state[c]) return true; //FTF => T
- if (!state[a] && !state[b] && state[c]) return true; //FFT => T
- if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
- },
- id: 0,
- researchSpawned: 0,
- descriptionFunction() {
- const loop = () => {
- if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
- let b = []; //produce next row
- b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
- for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
- b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
- }
- b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
- this.state.push(b)
- if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
- if (this.count && this.researchSpawned < 12 && !(this.state.length % 10)) {
- this.researchSpawned++
- powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
- }
- setTimeout(() => {
- loop()
- }, 300 + 5 * this.state.length);
- }
- }
- setTimeout(() => {
- loop()
- }, 300);
- this.id++
- return `
${this.outputText()}`
- },
- outputText() {
- let text = "
"
- for (let j = 0; j < this.state.length; j++) {
- // text += ""
- text += "
"
- for (let i = 0; i < this.state[j].length; i++) {
- if (this.state[j][i]) {
- text += "■" //"☻" //"⬛" //"█" //"■"
- } else {
- text += " " //"□" //"☺" //"⬜" //" " //"□"
- }
- }
- text += "
"
- }
- text += ""
- return text
- },
- },
- {
- name: "rule 90",
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- allowed() {
- return !build.isExperimentSelection
- },
- requires: "NOT EXPERIMENT MODE",
- effect() {},
- remove() {},
- state: [
- [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false]
- ],
- rule(state, a, b, c) { //90
- if (state[a] && state[b] && state[c]) return false; // TTT => F
- if (state[a] && state[b] && !state[c]) return true; // TTF => T
- if (state[a] && !state[b] && state[c]) return false; //TFT => F
- if (state[a] && !state[b] && !state[c]) return true; //TFF => T
- if (!state[a] && state[b] && state[c]) return true; //FTT => T
- if (!state[a] && state[b] && !state[c]) return false; //FTF => F
- if (!state[a] && !state[b] && state[c]) return true; //FFT => T
- if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
- },
- id: 90,
- researchSpawned: 0,
- descriptionFunction() {
- const loop = () => {
- if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
- let b = []; //produce next row
- b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
- for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
- b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
- }
- b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
- this.state.push(b)
- if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
- if (this.count && this.researchSpawned < 12 && !(this.state.length % 10)) {
- this.researchSpawned++
- powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
- }
- setTimeout(() => {
- loop()
- }, 300 + 5 * this.state.length);
- }
- }
- setTimeout(() => {
- loop()
- }, 300);
- this.id++
- return `
${this.outputText()}`
- },
- outputText() {
- let text = "
"
- for (let j = 0; j < this.state.length; j++) {
- // text += ""
- text += "
"
- for (let i = 0; i < this.state[j].length; i++) {
- if (this.state[j][i]) {
- text += "■" //"☻" //"⬛" //"█" //"■"
- } else {
- text += " " //"□" //"☺" //"⬜" //" " //"□"
- }
- }
- text += "
"
- }
- text += ""
- return text
- },
- },
- {
- name: "cosmogonic myth",
- description: `
open a portal to a primordial version of reality
in 5 minutes close the portal, spawn 1 of each power up`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- const urls = ["https://scratch.mit.edu/projects/14005697/fullscreen/", "https://scratch.mit.edu/projects/22573757/fullscreen/", "https://scratch.mit.edu/projects/41429974/fullscreen/", "https://scratch.mit.edu/projects/43690666/fullscreen/", "https://codepen.io/lilgreenland/full/ozXNWZ", "https://codepen.io/lilgreenland/full/wzARJY", "classic/7-1-2017/", "classic/4-15-2018/", "classic/7-11-2019/", "classic/9-8-2019/", "classic/7-15-2020/", "classic/6-1-2021/"]
- const choose = urls[Math.floor(Math.random() * urls.length)]
- console.log(`opening new tab" ${choose}`)
- let tab = window.open(choose, "_blank");
- setTimeout(() => {
- tab.close();
- powerUps.spawn(m.pos.x, m.pos.y, "gun");
- setTimeout(() => {
- powerUps.spawn(m.pos.x, m.pos.y - 50, "ammo")
- }, 250);
- setTimeout(() => {
- powerUps.spawn(m.pos.x + 50, m.pos.y, "field");
- }, 500);
- setTimeout(() => {
- powerUps.spawn(m.pos.x + 50, m.pos.y - 50, "heal");
- }, 750);
- setTimeout(() => {
- powerUps.spawn(m.pos.x - 50, m.pos.y, "tech");
- }, 1000);
- setTimeout(() => {
- powerUps.spawn(m.pos.x - 50, m.pos.y - 50, "research");
- }, 1250);
- }, 1000 * 5 * 60);
- },
- remove() {}
- },
- {
- name: "planetesimals",
- description: `play
planetesimals (an asteroids-like game)clear
levels in
planetesimals to spawn
techif you
die in
planetesimals you
die in
n-gon`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() {
- return true
- },
- requires: "",
- effect() {
- window.open('../../planetesimals/index.html', '_blank')
- // powerUps.spawn(m.pos.x, m.pos.y, "tech");
-
- // for communicating to other tabs, like planetesimals
- // Connection to a broadcast channel
- const bc = new BroadcastChannel('planetesimals');
- bc.activated = false
-
- bc.onmessage = function(ev) {
- if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
- if (ev.data === 'death') {
- m.death()
- bc.close(); //end session
- }
- if (ev.data === 'ready' && !bc.activated) {
- bc.activated = true //prevents n-gon from activating multiple copies of planetesimals
- bc.postMessage("activate");
- }
- }
- },
- remove() {}
- },
- {
- name: "tinker",
- description: "
permanently unlock
JUNKtech in experiment mode
this effect is stored for future visits",
- maxCount: 1,
- count: 0,
- frequency: 0,
- frequencyDefault: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed() {
- return !localSettings.isJunkExperiment
- },
- requires: "",
- effect() {
- localSettings.isJunkExperiment = true
- if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
- },
- remove() {}
- },
- {
- name: "NFT",
- descriptionFunction() {
- return `buy your current game seed:
${Math.initialSeed}no one is allowed to use your seeds
if they use them they are gonna get in troubleyour seeds:
${localSettings.personalSeeds.join(", ")}`
- },
- maxCount: 1,
- count: 0,
- frequency: 0,
- isJunk: true,
- isNonRefundable: true,
- allowed: () => true,
- requires: "",
- effect() {
- localSettings.personalSeeds.push(Math.initialSeed)
- if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
- },
- remove() {}
- },
- // {
- // name: "rule 90",
- // maxCount: 1,
- // count: 0,
- // frequency: 0,
- // isJunk: true,
- // allowed() {
- // return true
- // },
- // requires: "",
- // effect() {},
- // remove() {},
- // state: [
- // [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false]
- // ],
- // rule(state, a, b, c) {
- // if (state[a] && state[b] && state[c]) return false; // TTT => F
- // if (state[a] && state[b] && !state[c]) return true; // TTF => T
- // if (state[a] && !state[b] && state[c]) return false; //TFT => F
- // if (state[a] && !state[b] && !state[c]) return true; //TFF => T
- // if (!state[a] && state[b] && state[c]) return true; //FTT => T
- // if (!state[a] && state[b] && !state[c]) return false; //FTF => F
- // if (!state[a] && !state[b] && state[c]) return true; //FFT => T
- // if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
- // },
- // id: 0,
- // descriptionFunction() {
- // const loop = () => {
- // if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
- // let b = []; //produce next row
- // b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
- // for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
- // b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
- // }
- // b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
- // this.state.push(b)
- // if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
- // if (this.count && this.state.length < 120 && !(this.state.length % 10)) powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
- // setTimeout(() => { loop() }, 400);
- // }
- // }
- // setTimeout(() => { loop() }, 400);
- // // if (this.id === 0) {
- // // for (let i = 0; i < 29; i++) this.state[0][i] = Math.random() < 0.5 //randomize seed
- // // }
- // this.id++
- // return `
${this.outputText()}`
- // },
- // outputText() {
- // let text = ""
- // for (let j = 0; j < this.state.length; j++) {
- // text += "
"
- // for (let i = 0; i < this.state[j].length; i++) {
- // if (this.state[j][i]) {
- // text += "⬛" //"█" //"■"
- // } else {
- // text += "⬜" //" " //"□"
- // }
- // }
- // text += "
"
- // }
- // return text
- // },
- // },
-
- //**************************************************
- //************************************************** undefined / lore
- //************************************************** tech
- //**************************************************
- {
- name: `undefined`,
- description: `
this `,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isLore: true,
- // isExperimentHide: true,
- allowed() {
- return !build.isExperimentSelection
- },
- requires: "NOT EXPERIMENT MODE",
- effect() {
- if (localSettings.loreCount > lore.conversation.length - 1) { //reward for people done with lore chapters (or on the final chapter)
- for (let i = mob.length - 1; i > -1; i--) { //replace mobs with starters
- if (!mob[i].isBoss && mob[i].isDropPowerUp && mob[i].alive) {
- spawn.starter(mob[i].position.x, mob[i].position.y)
- mob[i].leaveBody = false
- mob[i].isDropPowerUp = false
- mob[i].death()
-
- //spawn a random power up
- // if (Math.random() < 1 / 5) {
- // powerUps.spawn(mob[i].position.x, mob[i].position.y, "research")
- // } else
- if (Math.random() < 1 / 4) {
- powerUps.spawn(mob[i].position.x, mob[i].position.y, "ammo")
- } else if (Math.random() < 1 / 3) {
- powerUps.spawn(mob[i].position.x, mob[i].position.y, "heal")
- } else if (Math.random() < 1 / 2) {
- powerUps.spawn(mob[i].position.x, mob[i].position.y, "boost")
- } else {
- powerUps.spawn(mob[i].position.x, mob[i].position.y, "coupling")
- }
- }
- }
- }
-
- setTimeout(() => { //a short delay, I can't remember why
- lore.techCount++
- if (lore.techCount === lore.techGoal) {
- // tech.removeLoreTechFromPool();
- this.frequency = 0;
- this.description = `
null is open at level.final()
`
- } else {
- this.frequency += lore.techGoal * 2
- // for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech
- // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech[i].description = `${lore.techCount+1}/${lore.techGoal}
add copies of this to the potential tech pool`
- // }
- // for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool()
- this.description = `
uncaught error:${Math.max(0, lore.techGoal - lore.techCount)} more required for access to
null`
- }
- }, 1);
- },
- remove() {
- lore.techCount = 0;
- this.maxCount = lore.techGoal;
- this.description = `
this `
}
}
+ },
+ {
+ name: "hidden variable",
+ descriptionFunction() {
+ return `spawn ${powerUps.orb.heal(20)}
but hide your
health bar`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ for (let i = 0; i < 20; i++) powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ },
+ remove() { }
+ },
+ {
+ name: "not a bug",
+ description: "initiate a totally safe game crash for 10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const savedfunction = simulation.drawCircle
+ simulation.drawCircle = () => {
+ const a = mob[Infinity].position //crashed the game in a visually interesting way, because of the ctx.translate command is never reverted in the main game loop
+ }
+ setTimeout(() => {
+ simulation.drawCircle = savedfunction
+ canvas.width = canvas.width //clears the canvas // works on chrome at least
+ powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ }, 10000);
+
+ // for (;;) {} //freezes the tab
+ },
+ remove() { }
+ },
+ {
+ name: "spinor",
+ description: "the direction you aim is determined by your position",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.look = function () {
+ //always on mouse look
+ m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI
+ //smoothed mouse look translations
+ const scale = 0.8;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+
+ m.transX += (m.transSmoothX - m.transX) * 0.07;
+ m.transY += (m.transSmoothY - m.transY) * 0.07;
+ }
+ },
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "p-zombie",
+ description: "set your
health to
1all mobs, not bosses, die and
resurrect as zombies",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ m.health = 0.01 //set health to 1
+ m.displayHealth();
+ for (let i = mob.length - 1; i > -1; i--) { //replace mobs with zombies
+ if (mob[i].isDropPowerUp && !mob[i].isBoss && mob[i].alive) {
+ mob[i].isSoonZombie = true
+ mob[i].death()
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "decomposers",
+ description: "after they die
mobs leave behind
spawns",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return tech.deathSpawns === 0
+ },
+ requires: "",
+ effect() {
+ tech.deathSpawns = 0.2
+ },
+ remove() {
+ tech.deathSpawns = 0
+ }
+ },
+ {
+ name: "panopticon",
+ description: "
mobs can always see you",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ for (let i = 0; i < mob.length; i++) {
+ if (!mob[i].shield && mob[i].isDropPowerUp) {
+ mob[i].locatePlayer()
+ mob[i].seePlayer.yes = true;
+ }
+ }
+ }, 1000); //every 1 seconds
+ },
+ remove() { }
+ },
+ // {
+ // name: "inverted mouse",
+ // description: "your mouse is scrambled
it's fine, just rotate it 90 degrees",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isExperimentHide: true,
+ // isNonRefundable: true,
+ // isJunk: true,
+ // allowed() {
+ // return !m.isShipMode
+ // },
+ // requires: "not ship",
+ // effect() {
+ // document.body.addEventListener("mousemove", (e) => {
+ // const ratio = window.innerWidth / window.innerHeight
+ // simulation.mouse.x = e.clientY * ratio
+ // simulation.mouse.y = e.clientX / ratio;
+ // });
+ // },
+ // remove() {
+ // // m.look = m.lookDefault
+ // }
+ // },
+ {
+ name: "Fourier analysis",
+ description: "your aiming is now controlled by this equation:
2sin(0.0133t) + sin(0.013t) + 0.5sin(0.031t)+ 0.33sin(0.03t)",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "not ship",
+ effect() {
+ m.look = () => {
+ m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03)
+ const scale = 0.8;
+ simulation.mouse.y
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * 0.07;
+ m.transY += (m.transSmoothY - m.transY) * 0.07;
+ }
+ },
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "disintegrated armament",
+ description: "spawn a
gunremove your active
gun",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return b.inventory.length > 0
+ },
+ requires: "at least 1 gun",
+ effect() {
+ if (b.inventory.length > 0) b.removeGun(b.guns[b.activeGun].name)
+ simulation.makeGunHUD()
+ powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
+ },
+ remove() { }
+ },
+ {
+ name: "probability",
+ description: "increase the
frequencyof one random
tech by
100",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ let options = []; //find what tech I could get
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (
+ tech.tech[i].count < tech.tech[i].maxCount &&
+ tech.tech[i].allowed() &&
+ !tech.tech[i].isJunk &&
+ !tech.tech.isLore
+ ) {
+ options.push(i);
+ }
+ }
+ if (options.length) {
+ const index = options[Math.floor(Math.random() * options.length)]
+ tech.tech[index].frequency = 100
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "encryption",
+ description: "secure
tech information",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ String.prototype.shuffle = function () {
+ var a = this.split(""),
+ n = a.length;
+
+ for (var i = n - 1; i > 0; i--) {
+ var j = Math.floor(Math.random() * (i + 1));
+ var tmp = a[i];
+ a[i] = a[j];
+ a[j] = tmp;
+ }
+ return a.join("");
+ }
+
+ for (let i = 0, len = tech.tech.length; i < len; i++) tech.tech[i].name = tech.tech[i].name.shuffle()
+ },
+ remove() { }
+ },
+ {
+ name: "quantum leap",
+ description: "become an
alternate version of yourself
every
20 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.switchWorlds()
+ simulation.trails()
+ }, 20000); //every 30 seconds
+ },
+ remove() { }
+ },
+ {
+ name: "score",
+ description: "Add a score to n-gon!",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ let score = Math.ceil(1000 * Math.random() * Math.random() * Math.random() * Math.random() * Math.random())
+ simulation.makeTextLog(`simulation.score
= ${score.toFixed(0)}`);
+ }, 10000); //every 10 seconds
+ },
+ remove() { }
+ },
+ {
+ name: "pop-ups",
+ description: "sign up to learn endless easy ways to win n-gon
that Landgreen doesn't want you to know!!!1!!",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ alert(`The best combo is ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name} with ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name}!`);
+ }, 30000); //every 30 seconds
+ },
+ remove() { }
+ },
+ {
+ name: "music",
+ description: "add music to n-gon",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ window.open('https://www.youtube.com/watch?v=lEbHeSdmS-k&list=PL9Z5wjoBiPKEDhwCW2RN-VZoCpmhIojdn', '_blank')
+ },
+ remove() { }
+ },
+ {
+ name: "performance",
+ description: "display performance stats to n-gon",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ (function () {
+ var script = document.createElement('script');
+ script.onload = function () {
+ var stats = new Stats();
+ document.body.appendChild(stats.dom);
+ requestAnimationFrame(function loop() {
+ stats.update();
+ requestAnimationFrame(loop)
+ });
+ };
+ script.src = 'https://unpkg.com/stats.js@0.17.0/build/stats.min.js';
+ document.head.appendChild(script);
+ })()
+ //move health to the right
+ document.getElementById("health").style.left = "86px"
+ document.getElementById("health-bg").style.left = "86px"
+ document.getElementById("defense-bar").style.left = "86px"
+ document.getElementById("damage-bar").style.left = "86px"
+ },
+ remove() { }
+ },
+ {
+ name: "repartitioning",
+ description: "set the
frequency of finding normal
tech to
0spawn 5
tech",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isJunk) {
+ tech.tech[i].frequency = 2
+ } else {
+ tech.tech[i].frequency = 0
+ }
+ }
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ },
+ remove() { }
+ },
+ {
+ name: "defragment",
+ description: "set the
frequency of finding
JUNKtech to zero",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = tech.tech.length - 1; i > 0; i--) {
+ if (tech.tech[i].isJunk) tech.tech[i].frequency = 0
+ }
+ },
+ remove() { }
+ },
+ // {
+ // name: "lubrication",
+ // description: "reduce block density and friction for this level",
+ // maxCount: 9,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isExperimentHide: true,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // for (let i = 0; i < body.length; i++) {
+ // Matter.Body.setDensity(body[i], 0.0001) // 0.001 is normal
+ // body[i].friction = 0.01
+ // }
+ // },
+ // remove() {}
+ // },
+ {
+ name: "pitch",
+ description: "oscillate the pitch of your world",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01))
+ }, 16);
+ },
+ remove() { }
+ },
+ {
+ name: "umbra",
+ description: "produce a blue glow around everything
and probably some simulation lag",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ ctx.shadowColor = '#06f';
+ ctx.shadowBlur = 25;
+ },
+ remove() { }
+ },
+ {
+ name: "lighter",
+ description: `ctx.globalCompositeOperation = "lighter"`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name !== "negative mass"
+ },
+ requires: "",
+ effect() {
+ ctx.globalCompositeOperation = "lighter";
+ },
+ remove() { }
+ },
+ {
+ name: "rewind",
+ description: "every 10 seconds
rewind 2 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.rewind(120)
+ m.energy += 0.4
+ }, 10000);
+ // for (let i = 0; i < 24; i++) {
+ // setTimeout(() => { m.rewind(120) }, i * 5000);
+ // }
+ },
+ remove() { }
+ },
+ {
+ name: "undo",
+ description: "every 4 seconds
rewind 1/2 a second",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.rewind(30)
+ m.energy += 0.2
+ }, 4000);
+ },
+ remove() { }
+ },
+ {
+ name: "energy to mass conversion",
+ description: "convert your
energy into
blocks",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0, len = 40; i < len; i++) {
+ setTimeout(() => {
+ m.energy -= 1 / len
+ const index = body.length
+ where = Vector.add(m.pos, {
+ x: 400 * (Math.random() - 0.5),
+ y: 400 * (Math.random() - 0.5)
+ })
+ spawn.bodyRect(where.x, where.y, Math.floor(15 + 100 * Math.random()), Math.floor(15 + 100 * Math.random()));
+ body[index].collisionFilter.category = cat.body;
+ body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ body[index].classType = "body";
+ Composite.add(engine.world, body[index]); //add to world
+ }, i * 100);
+ }
+
+ },
+ remove() { }
+ },
+ {
+ name: "level.nextLevel()",
+ description: "advance to the next level",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ level.nextLevel();
+ },
+ remove() { }
+ },
+ {
+ name: "reincarnation",
+ description: "kill all mobs and spawn new ones
(also spawn a few extra mobs for fun)",
+ maxCount: 3,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ spawn.setSpawnList();
+ spawn.setSpawnList();
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].alive && !mob[i].shield && !mob[i].isBadTarget) {
+ const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](mob[i].position.x, mob[i].position.y);
+ if (Math.random() < 0.5) spawn[pick](mob[i].position.x, mob[i].position.y);
+ mob[i].death();
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "expert system",
+ description: "spawn a
tech power up
+64% JUNK to
tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ tech.addJunkTechToPool(0.64)
+ },
+ remove() { }
+ },
+ {
+ name: "energy investment",
+ description: "every 10 seconds drain your
energyreturn it doubled 5 seconds later",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ if (!simulation.paused) {
+ const energy = m.energy
+ m.energy = 0
+ setTimeout(() => { //return energy
+ m.energy += 2 * energy
+ }, 5000);
+ }
+ }, 10000);
+ },
+ remove() { }
+ },
+ {
+ name: "missile launching system",
+ description: "fire missiles for the next 120 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < 120; i++) {
+ setTimeout(() => {
+ const where = {
+ x: m.pos.x,
+ y: m.pos.y - 40
+ }
+ b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2)
+ }, i * 1000);
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "grenade production",
+ description: "drop a grenade every 2 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ if (!simulation.paused && document.visibilityState !== "hidden") {
+ b.grenade(Vector.add(m.pos, {
+ x: 10 * (Math.random() - 0.5),
+ y: 10 * (Math.random() - 0.5)
+ }), -Math.PI / 2) //fire different angles for each grenade
+ const who = bullet[bullet.length - 1]
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.1,
+ y: who.velocity.y * 0.1
+ });
+ }
+ }, 2000);
+ },
+ remove() { }
+ },
+ {
+ name: "stubs",
+ description: "no knees or toes are drawn on the player
you can wall climb though",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isSkin: true,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.stubs()
+ Matter.Body.scale(player.parts[3], 2, 2);
+ },
+ remove() {
+ // if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "Sleipnir",
+ description: "grow more legs",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isSkin: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.Sleipnir()
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "diegesis",
+ description: "indicate fire cooldown
through a rotation of your head",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isSkin: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.diegesis()
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "🐱",
+ description: "🐈",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isSkin: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.cat();
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "n-gone",
+ description: "become invisible to yourself
mobs can still see you",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isSkin: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.draw = () => { }
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "pareidolia",
+ description: "don't",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isSkin: true,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.pareidolia()
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "posture",
+ description: "stand a bit taller",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.yOffWhen.stand = 70
+ },
+ remove() {
+ m.yOffWhen.stand = 49
+ }
+ },
+ {
+ name: "rhythm",
+ description: "you oscillate up and down",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.yOffWhen.stand = 53 + 28 * Math.sin(simulation.cycle * 0.2)
+ if (m.onGround && !m.crouch) m.yOffGoal = m.yOffWhen.stand
+ }, 100);
+ },
+ remove() { }
+ },
+ {
+ name: "prism",
+ description: "you cycle through different
colors",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.color = {
+ hue: 0,
+ sat: 100,
+ light: 50
+ }
+ setInterval(function () {
+ m.color.hue++
+ m.setFillColors()
+ }, 10);
+ },
+ remove() { }
+ },
+ // {
+ // name: "microtransactions",
+ // description: `when you choose a
tech you can
use ${powerUps.orb.research(1)} to buy a free in game
skin`,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // tech.isMicroTransactions = true
+ // },
+ // remove() {
+ // tech.isMicroTransactions = false
+ // }
+ // },
+ {
+ name: "ship",
+ description: "fly around with no legs
reduce combat
difficulty by
1 level",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode && !m.isAltSkin && m.fieldUpgrades[m.fieldMode].name !== "negative mass"
+ },
+ requires: "",
+ effect() {
+ m.isAltSkin = true
+ m.shipMode()
+ level.difficultyDecrease(simulation.difficultyMode)
+ //unlock relativistic rotation
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].name === "relativistic rotation") tech.tech[i].frequency = 10
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "circular symmetry",
+ description: "turning the ship rotates the universe instead
+200% damage",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return m.isShipMode
+ },
+ requires: "",
+ effect() {
+ tech.damage *= 3
+
+ m.look = () => {
+ // const scale = 0;
+ m.transSmoothX = canvas.width2 - m.pos.x // - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y // - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
+ ctx.restore();
+ ctx.save();
+ ctx.translate(canvas.width2, canvas.height2); //center
+ ctx.rotate(-m.angle)
+ ctx.translate(-canvas.width2, -canvas.height2); //center
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "assimilation",
+ description: "all your
bots are converted to the
same random model",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isBotTech: true,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return b.totalBots() > 2
+ },
+ requires: "at least 3 bots",
+ effect() {
+ const total = b.totalBots();
+ tech.dynamoBotCount = 0;
+ tech.nailBotCount = 0;
+ tech.laserBotCount = 0;
+ tech.orbitBotCount = 0;
+ tech.foamBotCount = 0;
+ tech.boomBotCount = 0;
+ tech.plasmaBotCount = 0;
+ tech.missileBotCount = 0;
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) bullet[i].endCycle = 0
+ }
+
+ const bots = [
+ () => {
+ b.nailBot();
+ tech.nailBotCount++;
+ },
+ () => {
+ b.foamBot();
+ tech.foamBotCount++;
+ },
+ () => {
+ b.boomBot();
+ tech.boomBotCount++;
+ },
+ () => {
+ b.laserBot();
+ tech.laserBotCount++;
+ },
+ () => {
+ b.orbitBot();
+ tech.orbitBotCount++
+ },
+ () => {
+ b.dynamoBot();
+ tech.dynamoBotCount++
+ }
+ ]
+ const index = Math.floor(Math.random() * bots.length)
+ for (let i = 0; i < total; i++) bots[index]()
+ },
+ remove() { }
+ },
+ {
+ name: "growth hacking",
+ description: "increase combat
difficulty by
1 level",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ level.difficultyIncrease(simulation.difficultyMode)
+ },
+ remove() { }
+ },
+ {
+ name: "stun",
+ description: "
stun all mobs for up to
8 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480)
+ },
+ remove() { }
+ },
+ {
+ name: "translucent",
+ description: "spawn
3 gun power ups
your
bullets and bots are transparent",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
+
+ // //removes guns and ammo
+ // b.inventory = [];
+ // b.activeGun = null;
+ // b.inventoryGun = 0;
+ // for (let i = 0, len = b.guns.length; i < len; ++i) {
+ // b.guns[i].have = false;
+ // if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0;
+ // }
+ // simulation.makeGunHUD(); //update gun HUD
+ b.bulletDraw = () => { }; //make bullets invisible
+ },
+ remove() { }
+ },
+ {
+ name: "re-research",
+ description: `
eject all your ${powerUps.orb.research(1)}`,
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return powerUps.research.count > 3
+ },
+ requires: "at least 4 research",
+ effect() {
+ powerUps.spawnDelay("research", powerUps.research.count);
+ powerUps.research.count = 0
+ },
+ remove() { }
+ },
+ {
+ name: "black hole",
+ description: `use your
energy and ${powerUps.orb.research(4)} to
spawninside the event horizon of a huge
black hole`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return powerUps.research.count > 3
+ },
+ requires: "at least 4 research",
+ effect() {
+ m.energy = 0
+ spawn.suckerBoss(m.pos.x, m.pos.y - 700)
+ powerUps.research.changeRerolls(-4)
+ simulation.makeTextLog(`
m.
research --${powerUps.research.count}`)
+ },
+ remove() { }
+ },
+ {
+ name: "black hole cluster",
+ description: `spawn
30 nearby
black holes`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const unit = {
+ x: 1,
+ y: 0
+ }
+ for (let i = 0; i < 30; i++) {
+ const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random()))
+ spawn.sucker(where.x, where.y, 140)
+ const who = mob[mob.length - 1]
+ who.locatePlayer()
+ // who.damageReduction = 0.2
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "rule 30",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() { },
+ remove() { },
+ state: [
+ [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false]
+ ],
+ rule(state, a, b, c) {
+ //30
+ if (state[a] && state[b] && state[c]) return false; // TTT => F
+ if (state[a] && state[b] && !state[c]) return false; // TTF => F
+ if (state[a] && !state[b] && state[c]) return false; //TFT => F
+ if (state[a] && !state[b] && !state[c]) return true; //TFF => T
+ if (!state[a] && state[b] && state[c]) return true; //FTT => T
+ if (!state[a] && state[b] && !state[c]) return true; //FTF => T
+ if (!state[a] && !state[b] && state[c]) return true; //FFT => T
+ if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
+ },
+ id: 0,
+ researchSpawned: 0,
+ descriptionFunction() {
+ const loop = () => {
+ if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
+ let b = []; //produce next row
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
+ for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
+ b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
+ }
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
+ this.state.push(b)
+ if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
+ if (this.count && this.researchSpawned < 12 && !(this.state.length % 10)) {
+ this.researchSpawned++
+ powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ }
+ setTimeout(() => {
+ loop()
+ }, 300 + 5 * this.state.length);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, 300);
+ this.id++
+ return `
${this.outputText()}`
+ },
+ outputText() {
+ let text = "
"
+ for (let j = 0; j < this.state.length; j++) {
+ // text += ""
+ text += "
"
+ for (let i = 0; i < this.state[j].length; i++) {
+ if (this.state[j][i]) {
+ text += "■" //"☻" //"⬛" //"█" //"■"
+ } else {
+ text += " " //"□" //"☺" //"⬜" //" " //"□"
+ }
+ }
+ text += "
"
+ }
+ text += ""
+ return text
+ },
+ },
+ {
+ name: "rule 90",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() { },
+ remove() { },
+ state: [
+ [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false]
+ ],
+ rule(state, a, b, c) { //90
+ if (state[a] && state[b] && state[c]) return false; // TTT => F
+ if (state[a] && state[b] && !state[c]) return true; // TTF => T
+ if (state[a] && !state[b] && state[c]) return false; //TFT => F
+ if (state[a] && !state[b] && !state[c]) return true; //TFF => T
+ if (!state[a] && state[b] && state[c]) return true; //FTT => T
+ if (!state[a] && state[b] && !state[c]) return false; //FTF => F
+ if (!state[a] && !state[b] && state[c]) return true; //FFT => T
+ if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
+ },
+ id: 90,
+ researchSpawned: 0,
+ descriptionFunction() {
+ const loop = () => {
+ if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
+ let b = []; //produce next row
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
+ for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
+ b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
+ }
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
+ this.state.push(b)
+ if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
+ if (this.count && this.researchSpawned < 12 && !(this.state.length % 10)) {
+ this.researchSpawned++
+ powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ }
+ setTimeout(() => {
+ loop()
+ }, 300 + 5 * this.state.length);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, 300);
+ this.id++
+ return `
${this.outputText()}`
+ },
+ outputText() {
+ let text = "
"
+ for (let j = 0; j < this.state.length; j++) {
+ // text += ""
+ text += "
"
+ for (let i = 0; i < this.state[j].length; i++) {
+ if (this.state[j][i]) {
+ text += "■" //"☻" //"⬛" //"█" //"■"
+ } else {
+ text += " " //"□" //"☺" //"⬜" //" " //"□"
+ }
+ }
+ text += "
"
+ }
+ text += ""
+ return text
+ },
+ },
+ {
+ name: "cosmogonic myth",
+ description: `
open a portal to a primordial version of reality
in 5 minutes close the portal, spawn 1 of each power up`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const urls = ["https://scratch.mit.edu/projects/14005697/fullscreen/", "https://scratch.mit.edu/projects/22573757/fullscreen/", "https://scratch.mit.edu/projects/41429974/fullscreen/", "https://scratch.mit.edu/projects/43690666/fullscreen/", "https://codepen.io/lilgreenland/full/ozXNWZ", "https://codepen.io/lilgreenland/full/wzARJY", "classic/7-1-2017/", "classic/4-15-2018/", "classic/7-11-2019/", "classic/9-8-2019/", "classic/7-15-2020/", "classic/6-1-2021/"]
+ const choose = urls[Math.floor(Math.random() * urls.length)]
+ console.log(`opening new tab" ${choose}`)
+ let tab = window.open(choose, "_blank");
+ setTimeout(() => {
+ tab.close();
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x, m.pos.y - 50, "ammo")
+ }, 250);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x + 50, m.pos.y, "field");
+ }, 500);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x + 50, m.pos.y - 50, "heal");
+ }, 750);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x - 50, m.pos.y, "tech");
+ }, 1000);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x - 50, m.pos.y - 50, "research");
+ }, 1250);
+ }, 1000 * 5 * 60);
+ },
+ remove() { }
+ },
+ {
+ name: "planetesimals",
+ description: `play
planetesimals (an asteroids-like game)clear
levels in
planetesimals to spawn
techif you
die in
planetesimals you
die in
n-gon`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ window.open('../../planetesimals/index.html', '_blank')
+ // powerUps.spawn(m.pos.x, m.pos.y, "tech");
+
+ // for communicating to other tabs, like planetesimals
+ // Connection to a broadcast channel
+ const bc = new BroadcastChannel('planetesimals');
+ bc.activated = false
+
+ bc.onmessage = function (ev) {
+ if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ if (ev.data === 'death') {
+ m.death()
+ bc.close(); //end session
+ }
+ if (ev.data === 'ready' && !bc.activated) {
+ bc.activated = true //prevents n-gon from activating multiple copies of planetesimals
+ bc.postMessage("activate");
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "tinker",
+ description: "
permanently unlock
JUNKtech in experiment mode
this effect is stored for future visits",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !localSettings.isJunkExperiment
+ },
+ requires: "",
+ effect() {
+ localSettings.isJunkExperiment = true
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ },
+ remove() { }
+ },
+ {
+ name: "NFT",
+ descriptionFunction() {
+ return `buy your current game seed:
${Math.initialSeed}no one is allowed to use your seeds
if they use them they are gonna get in troubleyour seeds:
${localSettings.personalSeeds.join(", ")}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ localSettings.personalSeeds.push(Math.initialSeed)
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ },
+ remove() { }
+ },
+ // {
+ // name: "rule 90",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {},
+ // remove() {},
+ // state: [
+ // [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false]
+ // ],
+ // rule(state, a, b, c) {
+ // if (state[a] && state[b] && state[c]) return false; // TTT => F
+ // if (state[a] && state[b] && !state[c]) return true; // TTF => T
+ // if (state[a] && !state[b] && state[c]) return false; //TFT => F
+ // if (state[a] && !state[b] && !state[c]) return true; //TFF => T
+ // if (!state[a] && state[b] && state[c]) return true; //FTT => T
+ // if (!state[a] && state[b] && !state[c]) return false; //FTF => F
+ // if (!state[a] && !state[b] && state[c]) return true; //FFT => T
+ // if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
+ // },
+ // id: 0,
+ // descriptionFunction() {
+ // const loop = () => {
+ // if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
+ // let b = []; //produce next row
+ // b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
+ // for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
+ // b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
+ // }
+ // b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
+ // this.state.push(b)
+ // if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
+ // if (this.count && this.state.length < 120 && !(this.state.length % 10)) powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ // setTimeout(() => { loop() }, 400);
+ // }
+ // }
+ // setTimeout(() => { loop() }, 400);
+ // // if (this.id === 0) {
+ // // for (let i = 0; i < 29; i++) this.state[0][i] = Math.random() < 0.5 //randomize seed
+ // // }
+ // this.id++
+ // return `
${this.outputText()}`
+ // },
+ // outputText() {
+ // let text = ""
+ // for (let j = 0; j < this.state.length; j++) {
+ // text += "
"
+ // for (let i = 0; i < this.state[j].length; i++) {
+ // if (this.state[j][i]) {
+ // text += "⬛" //"█" //"■"
+ // } else {
+ // text += "⬜" //" " //"□"
+ // }
+ // }
+ // text += "
"
+ // }
+ // return text
+ // },
+ // },
+
+ //**************************************************
+ //************************************************** undefined / lore
+ //************************************************** tech
+ //**************************************************
+ {
+ name: `undefined`,
+ description: `
this `,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isLore: true,
+ // isExperimentHide: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() {
+ if (localSettings.loreCount > lore.conversation.length - 1) { //reward for people done with lore chapters (or on the final chapter)
+ for (let i = mob.length - 1; i > -1; i--) { //replace mobs with starters
+ if (!mob[i].isBoss && mob[i].isDropPowerUp && mob[i].alive) {
+ spawn.starter(mob[i].position.x, mob[i].position.y)
+ mob[i].leaveBody = false
+ mob[i].isDropPowerUp = false
+ mob[i].death()
+
+ //spawn a random power up
+ // if (Math.random() < 1 / 5) {
+ // powerUps.spawn(mob[i].position.x, mob[i].position.y, "research")
+ // } else
+ if (Math.random() < 1 / 4) {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "ammo")
+ } else if (Math.random() < 1 / 3) {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "heal")
+ } else if (Math.random() < 1 / 2) {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "boost")
+ } else {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "coupling")
+ }
+ }
+ }
+ }
+
+ setTimeout(() => { //a short delay, I can't remember why
+ lore.techCount++
+ if (lore.techCount === lore.techGoal) {
+ // tech.removeLoreTechFromPool();
+ this.frequency = 0;
+ this.description = `
null is open at level.final()
`
+ } else {
+ this.frequency += lore.techGoal * 2
+ // for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech
+ // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech[i].description = `${lore.techCount+1}/${lore.techGoal}
add copies of this to the potential tech pool`
+ // }
+ // for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool()
+ this.description = `
uncaught error:${Math.max(0, lore.techGoal - lore.techCount)} more required for access to
null`
+ }
+ }, 1);
+ },
+ remove() {
+ lore.techCount = 0;
+ this.maxCount = lore.techGoal;
+ this.description = `
this `
+ }
+ }
],
// addLoreTechToPool() { //adds lore tech to tech pool
// if (!simulation.isCheating) {
diff --git a/style.css b/style.css
index 05cee67..5b2150c 100644
--- a/style.css
+++ b/style.css
@@ -161,7 +161,7 @@ summary {
height: 100%;
}
-#choose-grid {
+.choose-grid {
position: absolute;
top: 50%;
left: 50%;
@@ -180,9 +180,34 @@ summary {
transition: opacity 0.25s linear;
overflow: auto;
-ms-overflow-style: none;
- /* IE and Edge */
scrollbar-width: none;
- /* Firefox */
+}
+
+.choose-grid-no-images {
+ border-radius: 12px;
+ border: 10px solid #444;
+ gap: 10px;
+ background-color: #444;
+ /* padding: 10px 1px; */
+
+
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ margin: 0px;
+ z-index: 12;
+ max-height: 99vh;
+ font-size: 1.3em;
+ display: grid;
+ grid-template-columns: 384px;
+ align-items: stretch;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.25s linear;
+ overflow: auto;
+ -ms-overflow-style: none;
+ scrollbar-width: none;
}
#choose-grid::-webkit-scrollbar {
@@ -356,6 +381,7 @@ summary {
margin-right: -1px;
font-size: 0.92em;
min-height: 88px;
+ /* border-radius: 5px; */
}
.cancel-card {
@@ -390,19 +416,31 @@ summary {
background-color: var(--hover-card-color);
}
+.research-cancel {
+ display: flex;
+ gap: 10px;
+ line-height: 160%;
+ /* background-color: var(--card-color); */
+ font-size: 1em;
+}
/* keeps 5 columns at 1440px */
@media (min-width: 1710px) and (max-width: 1950px) {
.experiment-grid-module,
.choose-grid-module,
- .pause-grid-module {
+ .pause-grid-module,
+ .research-cancel {
line-height: 143%;
font-size: 0.68em;
}
+ .research-cancel {
+ font-size: 0.9em;
+ }
+
#experiment-grid,
- #choose-grid,
+ .choose-grid,
.pause-grid {
grid-template-columns: repeat(auto-fit, 340px);
}
@@ -426,8 +464,12 @@ summary {
font-size: 0.58em;
}
+ .research-cancel {
+ font-size: 0.8em;
+ }
+
#experiment-grid,
- #choose-grid,
+ .choose-grid,
.pause-grid {
grid-template-columns: repeat(auto-fit, 285px);
}
@@ -512,7 +554,7 @@ summary {
}
.experiment-grid-disabled[data-descr]:hover::after {
- content: '\a \00a0 \00a0 \00a0 REQUIRES:\a \00a0 \00a0 \00a0 'attr(data-descr);
+ content: '\a \00a0 \00a0 \00a0 REQUIRES:\a \00a0 \00a0 \00a0 ' attr(data-descr);
white-space: pre-wrap;
position: absolute;
left: 0;
@@ -564,7 +606,7 @@ summary {
right: 4px;
height: 0px;
width: 7px;
- transition: height 0.15s linear;
+ transition: height 0.25s linear;
opacity: 1;
z-index: 2;
pointer-events: none;
@@ -580,7 +622,7 @@ summary {
left: 15px;
height: 7px;
width: 0px;
- transition: width 0.3s linear;
+ transition: width 0.25s linear;
opacity: 1;
z-index: 2;
pointer-events: none;
@@ -588,18 +630,21 @@ summary {
border-right: 1.5px solid #777;
display: none;
}
+
#health {
position: absolute;
top: 15px;
left: 15px;
height: 20px;
width: 0px;
- transition: width 1s ease-out; z-index: 2;
+ transition: width 1s ease-out;
+ z-index: 2;
pointer-events: none;
background-color: rgb(9, 245, 166);
border-right: 2px solid rgb(51, 162, 125);
display: none;
}
+
#health-bg {
position: absolute;
top: 15px;
diff --git a/todo.txt b/todo.txt
index dd001bb..bb66de3 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,13 +1,23 @@
******************************************************** NEXT PATCH **************************************************
-added defense bar to HUD
-new community map commandeer by Desboot
+mob damage difficulty setting is lower
+recycling now flashes green when it heals
+
+merged cancel and research bars for single column selection
+added some dark grey borders for no images selection mode
+
+new images with midJourney V5
+ spores, pilot wave, standing wave
bug fixes
*********************************************************** TODO *****************************************************
-switch to prettier formatter or remove beautify
+wormhole tech - teleport away mobs with mass below 3 when they get too near the player
+ short CD, small energy cost, only mobs below a mass
+
+foam gun could have a knock back effect
+ maybe with pressure vessel?
extend brainstorming animation timers to fps cap?
will it be smoother or choppier?
@@ -22,59 +32,12 @@ level element - mover, transport
extend uncertainty to superballs
maybe make aiming them more random?
-live updating defense and damage HUD?
- makes more sense for defense
- for damage many effects only apply to one type of damage so it would show up
- update frequency
- per s
- every cycle? (only if canvas)
- don't include difficulty effects
- draw in canvas or html?
- add border for readability
- a number
- bars
- horizontal
- vertical
- circles
- defense
- color: grey, white
- scales from 0-1
- wrapped around health bar like armor
- what about mass-energy which has no health bar
- at defense = 1 outlines health bar fully
- health bar
- color: keep red (green?)
- red is the same as mob health bars
- damage
- color: red if not used for health
- scales from 1-infinity maps to 0->1
- 1-1/(1+damage)
-diagetic UI Elements
- ammo number?
- doesn't text look choppy when camera moves?
- health bar could be rendered similarly to energy bar
- what about 2 bezier curves on left and right of player head that looks like 1/3 circleRadiusScale
- rotate the curves as the head rotates
- what about 2 bezier both above player
- as the total energy and health increases the curses could asymptotically approach a maximum length as max energy/health goes to infinity
-
-
-foam gun could have a knock back effect
- maybe with pressure vessel?
-
perfect diamagnatism could bounce on mobs, or even map elements?
could work like a rocket jump?
-field tech: negative mass, wormhole?
- tech: do 60% damage when not touching ground
- tech: 50% defense when not touching ground
-
Tech: Von Neuman probes - Drones will consume blocks to replicate themselves
it's a little too similar to the drone repair tech, but I kinda like it better. drones that eat blocks and spit out more drones is cool
-when gaining ammo have the ammo test quickly count up by Math.floor(1/20x) of the total ammo given
- maybe bold, flash the text for a second after
-
tech: parry - immune to harm for 0.25-0.5 seconds after pressing field button
needs a 5 second CD?
@@ -95,7 +58,6 @@ tech - after standing wave runs out of energy from blocking, gain a buff
aoe damage like railgun
push mobs away
-
level: lock
should there be something in the top part of the map?
add alt versions of left and right sides
@@ -1242,14 +1204,16 @@ if pause is pressed while selecting power ups, display pause menu on top of sele
metamaterial cloaking - Scientific photography by Miki Asai, by Bruce Munro
molecular assembler - by Laurie Greasley 16-bit Isometric
wormhole - by Tim White
+ pilot wave -
nail gun - Screenprint
shotgun - blueprint by Dan McPharlin
grenades, missiles, explosions - by Victo Ngai
- spores - by Ernst Haeckel
+ spores - turquoise black spores on a white background full color scientific anatomy by Ernst Haeckel
drones - tilt-shift photography
super balls - By Akari Toriyama
wave - sound wave oscilloscope by Paul Catherall, concentric circles by Paul Catherall
+ Barbara Takenaga's painting depicting a clean sound wave on aoscilloscope device --ar 3:2 --v 5
foam - black blobs Ink doodle
harpoon - by Eiichiro Oda
mine - by Dan McPharlin