field tech: patch - after cloaking recover 75% of last health lost using that much energy
  taking damage now forces decloaking
field tech: dynamic equilibrium - increase damage by 5% the value of your last health loss

foam has less velocity after a mob it's stuck to dies
snakeBoss becomes vulnerable if you remove any of the first 3 body segments
  body segments have more health

bug fix: quantum eraser now removes mobs in a more random order
  it used to have a too low chance to remove bosses
This commit is contained in:
landgreen
2022-07-26 08:26:05 -07:00
parent cf3ba7d5f2
commit 3e8f07ab04
9 changed files with 288 additions and 161 deletions

View File

@@ -1450,7 +1450,7 @@ const b = {
}
if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 2 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
}
@@ -1732,7 +1732,7 @@ const b = {
if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 2 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
}
@@ -3707,6 +3707,10 @@ const b = {
}
}
this.targetVertex = bestVertex
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
}
},
onEnd() {},
@@ -3778,6 +3782,10 @@ const b = {
} else if (this.target !== null) { //look for a new target
this.collisionFilter.category = cat.bullet;
this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
Matter.Body.setVelocity(this, {
x: this.target.velocity.x,
y: this.target.velocity.y
});
if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) {
let targets = []
for (let i = 0, len = mob.length; i < len; i++) {
@@ -5645,7 +5653,8 @@ const b = {
}
if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
// const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 6 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
}
@@ -5693,7 +5702,7 @@ const b = {
}
if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 6 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
}
@@ -5745,7 +5754,7 @@ const b = {
}
if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 6 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
}

View File

@@ -224,10 +224,6 @@ window.onresize = () => {
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (!tech.tech[i].link) tech.tech[i].link = `<a target="_blank" href='https://en.wikipedia.org/w/index.php?search=${encodeURIComponent(tech.tech[i].name).replace(/'/g, '%27')}&title=Special:Search' class="link">${tech.tech[i].name}</a>`
}
//<br>effective <strong class='color-defense'>defense</strong>: ${(1-simulation.dmgScale*m.harmReduction()).toPrecision(3)}
//<br>effective <strong class='color-d'>damage</strong>: ${(tech.damageFromTech() * m.dmgScale).toPrecision(3)}
const build = {
pauseGrid() {
//left side

View File

@@ -16,7 +16,7 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(8 * 4) //30 is near max on hard //60 is near max on why
// level.difficultyIncrease(4 * 4) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true
// m.maxHealth = m.health = 100
// powerUps.research.changeRerolls(100000)
@@ -24,19 +24,19 @@ const level = {
// powerUps.research.changeRerolls(100)
// tech.tech[297].frequency = 100
// b.guns[0].ammo = 10000
// m.setField("metamaterial cloaking") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole
// b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// tech.giveTech("robotics")
// tech.giveTech("CPT symmetry");
// tech.giveTech("lens");
// tech.giveTech("robotics")
// m.setField("metamaterial cloaking") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass
// b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// tech.giveTech("dynamic equilibrium")
// tech.giveTech("quantum eraser");
// tech.giveTech("patch");
// tech.giveTech("polyurethane foam")
// for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot")
// for (let i = 0; i < 1; ++i) tech.giveTech("electric generator")
// for (let i = 0; i < 9; i++) tech.giveTech("compound lens")
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research");
// spawn.starter(1900, -500)
// spawn.laserTargetingBoss(1900, -500)
// spawn.starter(1900, -500, 100)
// spawn.snakeBoss(1900, -500)
// for (let i = 0; i < 10; ++i) spawn.grower(1900, -500)
// level.testing(); //not in rotation, used for testing
// for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research");

View File

@@ -363,11 +363,8 @@ const m = {
m.health = m.health * (1 + 0.5 * (Math.random() - 0.5))
if (m.health > 1) m.health = 1;
m.displayHealth();
//randomize field
m.setField(Math.ceil(Math.random() * (m.fieldUpgrades.length - 1)))
//removes guns and ammo
b.inventory = [];
b.activeGun = null;
@@ -726,7 +723,11 @@ const m = {
document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4);
}
if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding
if (dmg > 0.03) {
m.lastHit = dmg;
if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding // m.holdingMassScale = 0.5 for most fields
if (m.isCloak) m.fireCDcycle = m.cycle //forced exit cloak
}
const normalFPS = function() {
if (m.defaultFPSCycle < m.cycle) { //back to default values
simulation.fpsCap = simulation.fpsCapDefault
@@ -908,6 +909,7 @@ const m = {
fieldShieldingScale: 1,
// fieldDamage: 1,
isSneakAttack: false,
lastHit: 0, //stores value of last damage player took above a threshold, in m.damage
sneakAttackCycle: 0,
enterCloakCycle: 0,
duplicateChance: 0,
@@ -950,6 +952,7 @@ const m = {
m.fieldShieldingScale = 1;
m.fieldBlockCD = 10;
m.fieldHarmReduction = 1;
m.lastHit = 0
m.isSneakAttack = false
m.duplicateChance = 0
powerUps.setDupChance();
@@ -1015,7 +1018,7 @@ const m = {
m.regenEnergy();
const xOff = m.pos.x - m.radius * m.maxEnergy
const yOff = m.pos.y - 50
ctx.fillStyle = "rgba(0, 0, 0, 0.3)" //
ctx.fillStyle = "rgba(0, 0, 0, 0.2)" //
ctx.fillRect(xOff, yOff, 60 * m.maxEnergy, 10);
ctx.fillStyle = "#fff" //m.cycle > m.lastKillCycle + 300 ? "#000" : "#fff" //"#fff";
ctx.fillRect(xOff, yOff, 60 * m.energy, 10);
@@ -2750,39 +2753,27 @@ const m = {
m.fieldFire = true;
m.fieldMeterColor = "#333";
m.eyeFillColor = m.fieldMeterColor
// m.eyeFillColor = '#333'
m.fieldPhase = 0;
m.isCloak = false
// m.fieldDamage = 2.46 // 1 + 146/100
m.fieldDrawRadius = 0
m.isSneakAttack = true;
// m.sneakAttackCharge = 0;
m.sneakAttackCycle = 0;
m.enterCloakCycle = 0;
const drawRadius = 800
m.drawCloak = function() {
m.fieldPhase += 0.007
const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5)
ctx.beginPath();
ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
// if (m.fireCDcycle > m.cycle && (input.field)) {}
ctx.fillStyle = "#fff"
ctx.lineWidth = 2;
ctx.strokeStyle = "#000"
ctx.stroke()
// ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*m.energy})`;
ctx.globalCompositeOperation = "destination-in";
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.clip();
}
m.hold = function() {
// if (m.isCloak) {
// if (m.sneakAttackCharge < 120) m.sneakAttackCharge += 0.5
// } else {
// if (m.sneakAttackCharge > 0) m.sneakAttackCharge--
// }
if (m.isHolding) {
m.drawHold(m.holdingTarget);
m.holding();
@@ -2801,7 +2792,31 @@ const m = {
if (!m.isCloak) {
m.isCloak = true //enter cloak
m.enterCloakCycle = m.cycle
// console.log(m.enterCloakCycle)
if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy)
m.energy -= heal
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
radius: Math.sqrt(heal) * 200,
color: "rgba(0,255,200,0.6)",
time: 16
});
m.addHealth(heal); //heal from last hit
// if (tech.isEnergyHealth) {
// simulation.drawList.push({ //add dmg to draw queue
// x: m.pos.x,
// y: m.pos.y,
// radius: Math.sqrt(heal) * 200,
// color: "#0ad", //simulation.mobDmgColor
// time: 16
// });
// m.energy += heal
// } else {
// }
m.lastHit = 0
// simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(heal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
}
if (tech.isIntangible) {
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType && bullet[i].botType !== "orbit") bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield
@@ -2841,12 +2856,12 @@ const m = {
}
}
if (m.isCloak) {
this.fieldRange = this.fieldRange * 0.9 + 0.1 * drawRadius
m.fieldDrawRadius = this.fieldRange * 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.fieldRange = m.fieldRange * 0.9 + 80
m.fieldDrawRadius = m.fieldRange * 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak()
} else if (this.fieldRange < 4000) {
this.fieldRange += 50
m.fieldDrawRadius = this.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
} else if (m.fieldRange < 4000) {
m.fieldRange += 50
m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak()
}
if (tech.isIntangible) {

View File

@@ -980,7 +980,6 @@ const simulation = {
}
if (tech.isQuantumEraser) {
// tech.quantumEraserCount = 0
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isDropPowerUp && mob[i].alive) tech.quantumEraserCount++
}

View File

@@ -48,7 +48,13 @@ const spawn = {
},
quantumEraserCheck() { //remove mobs from tech: quantum eraser
if (tech.isQuantumEraser && tech.quantumEraserCount > 0) {
for (let i = 0, len = mob.length; i < len; i++) {
//start at a random location in array
const randomMiddle = Math.floor(mob.length * Math.random())
let i = randomMiddle
for (let j = 0; j < mob.length; j++) {
i++
if (i > mob.length - 1) i = 0
if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss
if (mob[i].isFinalBoss) {
tech.quantumEraserCount = 0;
@@ -86,6 +92,47 @@ const spawn = {
if (tech.quantumEraserCount < 1) break
}
}
// for (let i = 0, len = mob.length; i < len; i++) {
// if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss
// if (mob[i].isFinalBoss) {
// tech.quantumEraserCount = 0;
// return
// } else {
// tech.isQuantumEraserDuplication = true
// mob[i].death()
// tech.isQuantumEraserDuplication = false
// }
// //graphics
// const color = 'rgba(255,255,255, 0.8)'
// simulation.drawList.push({
// x: mob[i].position.x,
// y: mob[i].position.y,
// radius: mob[i].radius * 2,
// color: color, //"rgba(0,0,0,0.6)",
// time: 60
// });
// simulation.drawList.push({
// x: mob[i].position.x,
// y: mob[i].position.y,
// radius: mob[i].radius * 1,
// color: color, //"rgba(0,0,0,0.85)",
// time: 90
// });
// simulation.drawList.push({
// x: mob[i].position.x,
// y: mob[i].position.y,
// radius: mob[i].radius * 0.5,
// color: color, //"rgb(0,0,0)",
// time: 120
// });
// tech.quantumEraserCount--
// simulation.makeTextLog(`<span class='color-var'>tech</span>.quantumEraserCount <span class='color-symbol'>=</span> ${tech.quantumEraserCount}`)
// if (tech.quantumEraserCount < 1) break
// }
// }
}
},
randomMob(x, y, chance = 1) {
@@ -2786,6 +2833,7 @@ const spawn = {
mobs.spawn(x, y, 3, radius, "rgb(0,235,255)");
let me = mob[mob.length - 1];
me.isBoss = true;
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
@@ -2808,11 +2856,29 @@ const spawn = {
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.targetingCount = 0;
me.targetingTime = 60 - Math.min(58, 3 * simulation.difficulty)
me.do = function() {
// this.armor();
// //wings
// const wing = (simulation.cycle % 9) > 4 ? this.vertices[0] : this.vertices[2] //Vector.add(this.position, { x: 100, y: 0 })
// const radius = 200
// //draw
// ctx.beginPath();
// ctx.arc(wing.x, wing.y, radius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
// ctx.fillStyle = "rgba(0,235,255,0.3)";
// ctx.fill();
// //check damage
// const hitPlayer = Matter.Query.ray([player], this.position, wing, radius)
// if (hitPlayer.length && m.immuneCycle < m.cycle) {
// m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
// m.damage(0.02 * simulation.dmgScale);
// }
this.seePlayerByLookingAt();
this.checkStatus();
this.attraction();
@@ -5566,7 +5632,7 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1];
me.isBoss = true;
me.accelMag = 0.0003 + 0.0002 * Math.sqrt(simulation.accelScale)
me.accelMag = 0.0004 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250;
me.laserRange = 500;
Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
@@ -5576,13 +5642,12 @@ const spawn = {
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < mob.length; i++) { //wake up tail mobs
if (mob[i].isSnakeTail && mob[i].alive) {
mob[i].isSnakeTail = false;
mob[i].do = mob[i].doActive
// mob[i].removeConsBB();
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.canFire = false;
me.closestVertex1 = 0;
@@ -5660,7 +5725,7 @@ const spawn = {
spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20);
// mag -= 5
// spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20);
if (i === 0) mob[mob.length - 1].snakeHeadID = me.id
if (i < 3) mob[mob.length - 1].snakeHeadID = me.id
mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id
}
@@ -5703,9 +5768,9 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1];
me.isBoss = true;
me.accelMag = 0.00045 + 0.0002 * Math.sqrt(simulation.accelScale)
me.accelMag = 0.0009 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250;
me.laserRange = 500;
me.laserRange = 400;
Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0
@@ -5713,6 +5778,9 @@ const spawn = {
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() {
this.seePlayerByHistory()
@@ -5738,7 +5806,7 @@ const spawn = {
angle -= 0.15 + i * 0.008
mag -= (i < 2) ? -15 : 5
spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20);
if (i === 0) mob[mob.length - 1].snakeHeadID = me.id
if (i < 3) mob[mob.length - 1].snakeHeadID = me.id
mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id
}
@@ -5775,11 +5843,13 @@ const spawn = {
mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
let me = mob[mob.length - 1];
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body
me.accelMag = 0.0007 * simulation.accelScale;
me.damageReduction = 0.2
Matter.Body.setDensity(me, 0.005); //normal is 0.001
// me.accelMag = 0.0007 * simulation.accelScale;
me.leaveBody = Math.random() < 0.33 ? true : false;
me.showHealthBar = false;
me.isDropPowerUp = false;
Matter.Body.setDensity(me, 0.005); //normal is 0.001
me.frictionAir = 0.015;
me.isSnakeTail = true;
me.stroke = "transparent"
@@ -5792,16 +5862,16 @@ const spawn = {
mob[i].damageReduction = mob[i].startingDamageReduction
}
}
}, 150);
}, 500);
};
me.do = function() {
this.checkStatus();
};
me.doActive = function() {
this.checkStatus();
this.alwaysSeePlayer();
this.attraction();
};
// me.doActive = function() {
// this.checkStatus();
// this.alwaysSeePlayer();
// this.attraction();
// };
},
tetherBoss(x, y, constraint, radius = 90) {
// constrained mob boss for the towers level

View File

@@ -239,7 +239,6 @@ const tech = {
if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
if (tech.isDamageForGuns) dmg *= 1 + 0.13 * b.inventory.length
if (tech.isLowHealthDmg) dmg *= 1 + Math.max(0, 1 - m.health) * 0.5
if (tech.isHarmDamage && m.lastHarmCycle + 600 > m.cycle) dmg *= 3;
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.038 * powerUps.research.count
@@ -251,10 +250,10 @@ const tech = {
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2
if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165)
if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.6
// if (m.isSneakAttack && m.cycle > m.lastKillCycle + 240) dmg *= tech.sneakAttackDmg
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= tech.sneakAttackDmg
// if (m.isSneakAttack && m.sneakAttackCharge > 0) dmg *= tech.sneakAttackDmg
if (tech.isAxion && tech.isHarmMACHO) dmg *= 2 - m.harmReduction()
if (tech.isHarmDamage && m.lastHarmCycle + 600 > m.cycle) dmg *= 3;
if (tech.isLastHitDamage && m.lastHit) dmg *= 1 + 5 * m.lastHit // if (!simulation.paused) m.lastHit = 0
return dmg * tech.slowFire * tech.aimDamage
},
duplicationChance() {
@@ -2115,24 +2114,6 @@ const tech = {
tech.isHarmArmor = false;
}
},
// {
// name: "radiative equilibrium",
// description: "for <strong>10 seconds</strong> after receiving <strong class='color-defense'>defense</strong><br>increase <strong class='color-d'>damage</strong> by <strong>200%</strong>",
// maxCount: 1,
// count: 0,
// frequency: 1,
// frequencyDefault: 1,
// allowed() {
// return true
// },
// requires: "",
// effect() {
// tech.isHarmDamage = true;
// },
// remove() {
// tech.isHarmDamage = false;
// }
// },
{
name: "CPT symmetry",
// description: "<strong>charge</strong>, <strong>parity</strong>, and <strong>time</strong> invert to undo <strong class='color-defense'>defense</strong><br><strong class='color-rewind'>rewind</strong> <strong>(1.5—5)</strong> seconds for <strong>(66—220)</strong> <strong class='color-f'>energy</strong>",
@@ -2272,42 +2253,42 @@ const tech = {
}
}
},
{
name: "weak interaction",
description: "for each unused <strong>power up</strong> at the end of a <strong>level</strong><br><strong>+10</strong> maximum <strong class='color-f'>energy</strong>", // <em>(up to 51 health per level)</em>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isDroneGrab
},
requires: "not delivery drone",
effect() {
tech.isExtraMaxEnergy = true; //tracked by tech.extraMaxHealth
},
remove() {
tech.isExtraMaxEnergy = false;
}
},
{
name: "electroweak interaction",
description: "unused <strong>power ups</strong> at the end of a <strong>level</strong><br>are still activated <em>(selections are random)</em>",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isExtraMaxEnergy
},
requires: "weak interaction",
effect() {
tech.isEndLevelPowerUp = true;
},
remove() {
tech.isEndLevelPowerUp = false;
}
},
// {
// name: "weak interaction",
// description: "for each unused <strong>power up</strong> at the end of a <strong>level</strong><br><strong>+10</strong> maximum <strong class='color-f'>energy</strong>", // <em>(up to 51 health per level)</em>",
// maxCount: 1,
// count: 0,
// frequency: 1,
// frequencyDefault: 1,
// allowed() {
// return !tech.isDroneGrab
// },
// requires: "not delivery drone",
// effect() {
// tech.isExtraMaxEnergy = true; //tracked by tech.extraMaxHealth
// },
// remove() {
// tech.isExtraMaxEnergy = false;
// }
// },
// {
// name: "electroweak interaction",
// description: "unused <strong>power ups</strong> at the end of a <strong>level</strong><br>are still activated <em>(selections are random)</em>",
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return tech.isExtraMaxEnergy
// },
// requires: "weak interaction",
// effect() {
// tech.isEndLevelPowerUp = true;
// },
// remove() {
// tech.isEndLevelPowerUp = false;
// }
// },
{
name: "electronegativity",
description: "<strong>+1%</strong> <strong class='color-d'>damage</strong> per <strong>8</strong> stored <strong class='color-f'>energy</strong>",
@@ -4107,7 +4088,7 @@ const tech = {
{
name: "spin-statistics",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Spin%E2%80%93statistics_theorem' class="link">spin-statistics</a>`,
description: "<strong>invulnerable</strong> while firing the <strong>shotgun</strong><br>shotgun has <strong>50%</strong> fewer shots",
description: "after firing the <strong>shotgun</strong> you are <strong>invulnerable</strong><br>shotgun has <strong>50%</strong> fewer shots",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -6665,8 +6646,8 @@ const tech = {
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass"
},
@@ -6678,6 +6659,26 @@ const tech = {
tech.isHarmDamage = false;
}
},
{
name: "dynamic equilibrium",
descriptionFunction() { return `increase <strong class='color-d'>damage</strong> by <strong>5%</strong><br>of your last ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"} loss` },
// description: `increase <strong class='color-d'>damage</strong> by <strong>500%</strong><br>of your last <strong class='color-h'>health</strong> loss`,
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 === "standing wave") && !tech.isCloakHealLastHit
},
requires: "negative mass, pilot wave, not patch",
effect() {
tech.isLastHitDamage = true;
},
remove() {
tech.isLastHitDamage = false;
}
},
{
name: "neutronium",
description: `<strong>move</strong> and <strong>jump</strong> <strong>25%</strong> <strong>slower</strong><br>if your <strong class='color-f'>field</strong> is active <strong>+90%</strong> <strong class='color-defense'>defense</strong>`,
@@ -7347,6 +7348,26 @@ const tech = {
}
}
},
{
name: "patch",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Patch_(computing)' class="link">patch</a>`,
description: "after <strong class='color-cloaked'>cloaking</strong> recover <strong>75%</strong> of your<br>last <strong class='color-h'>health</strong> loss using that much <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" && !tech.isLastHitDamage && !tech.isEnergyHealth
},
requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy",
effect() {
tech.isCloakHealLastHit = true;
},
remove() {
tech.isCloakHealLastHit = false;
}
},
{
name: "dazzler",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Dazzler_(weapon)' class="link">dazzler</a>`,
@@ -10528,5 +10549,7 @@ const tech = {
isLaserLens: null,
laserCrit: null,
isSporeColony: null,
isExtraBotOption: null
isExtraBotOption: null,
isLastHitDamage: null,
isCloakHealLastHit: null
}