const tech = {
totalCount: null,
setupAllTech() {
for (let i = 0, len = tech.tech.length; i < len; i++) {
tech.tech[i].remove();
tech.tech[i].isLost = false
tech.tech[i].count = 0
if (tech.tech[i].isJunk) {
tech.tech[i].frequency = 0
} else if (tech.tech[i].frequencyDefault) {
tech.tech[i].frequency = tech.tech[i].frequencyDefault
} else {
tech.tech[i].frequency = 2
}
}
lore.techCount = 0;
if (simulation.isCheating) { //simulation.isCommunityMaps ||
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0;
tech.tech[i].count = 0;
}
}
}
// tech.removeJunkTechFromPool();
// tech.removeLoreTechFromPool();
// tech.addLoreTechToPool();
tech.extraMaxHealth = 0;
tech.totalCount = 0;
simulation.updateTechHUD();
},
removeTech(index) {
if (isNaN(index)) { //find index by name
let found = false;
for (let i = 0; i < tech.tech.length; i++) {
if (index === tech.tech[i].name) {
index = i;
found = true;
break;
}
}
if (!found) return //if name not found don't remove any tech
}
tech.tech[index].remove();
tech.tech[index].count = 0;
simulation.updateTechHUD();
},
// onclick="tech.removeTechPaused(${i}, this)" //add this to tech elements in pause menu
// removeTechPaused(index, who) {
// tech.tech[index].remove();
// tech.tech[index].count = 0;
// simulation.updateTechHUD();
// who.innerHTML = "removed"
// // who.style.display = "none"
// },
// removeLoreTechFromPool() {
// for (let i = tech.tech.length - 1; i > 0; i--) {
// if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1)
// }
// },
addJunkTechToPool(num = 1) {
let options = [];
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].isJunk) options.push(i);
}
if (options.length) {
for (let i = 0; i < num; i++) tech.tech[options[Math.floor(Math.random() * options.length)]].frequency++
}
simulation.makeTextLog(`tech.tech.push(${num} JUNK)`)
},
removeJunkTechFromPool(num = 1) {
for (let j = 0; j < num; j++) {
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].isJunk && tech.tech[i].frequency > 0 && tech.tech[i].count < tech.tech[i].maxCount) {
tech.tech[i].frequency--
break
}
}
}
},
giveTech(index = 'random') {
if (index === 'random') {
let options = [];
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk && !tech.tech[i].isLore && !tech.tech[i].isBadRandomOption) options.push(i);
}
// give a random tech from the tech I don't have
if (options.length > 0) {
let newTech = options[Math.floor(Math.random() * options.length)]
tech.giveTech(newTech)
simulation.makeTextLog(`tech.giveTech("${tech.tech[newTech].name}") //random tech`);
}
} else {
if (isNaN(index)) { //find index by name
let found = false;
for (let i = 0; i < tech.tech.length; i++) {
if (index === tech.tech[i].name) {
index = i;
found = true;
break;
}
}
if (!found) return //if name not found don't give any tech
}
if (tech.isMetaAnalysis && tech.tech[index].isJunk) {
simulation.makeTextLog(`//tech: meta-analysis replaced junk tech with random tech`);
tech.giveTech('random')
for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 40 * Math.random(), m.pos.y + 40 * Math.random(), "research");
return
}
if (tech.tech[index].isLost) tech.tech[index].isLost = false; //give specific tech
tech.tech[index].effect(); //give specific tech
tech.tech[index].count++
tech.totalCount++ //used in power up randomization
simulation.updateTechHUD();
}
},
setTechoNonRefundable(name) {
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech.name === name) {
tech.tech[i].isNonRefundable = true;
return
}
}
},
setCheating() {
if (!simulation.isCheating) {
simulation.isCheating = true;
level.levelAnnounce();
lore.techCount = 0;
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0;
tech.tech[i].count = 0;
}
}
sound.tone(250)
sound.tone(300)
sound.tone(375)
}
},
haveGunCheck(name) {
// if (
// !build.isExperimentSelection &&
// b.inventory.length > 2 &&
// name !== b.guns[b.activeGun].name &&
// Math.random() > 2 - b.inventory.length * 0.5
// ) {
// return false
// }
// for (i = 0, len = b.inventory.length; i < len; i++) {
// if (b.guns[b.inventory[i]].name === name) return true
// }
// return false
if (build.isExperimentSelection) {
for (i = 0, len = b.inventory.length; i < len; i++) {
if (b.guns[b.inventory[i]].name === name) return true
}
return false
} else {
return b.inventory.length > 0 && b.guns[b.activeGun].name === name
}
},
hasExplosiveDamageCheck() {
return tech.haveGunCheck("missiles") || tech.isMissileField || tech.missileBotCount > 0 || tech.boomBotCount > 1 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)
},
damageFromTech() {
let dmg = 1 //m.fieldDamage
if (tech.isCloakingDamage) dmg *= 1.35
if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.45
if (tech.isAnthropicDamage && tech.isDeathAvoidedThisLevel) dmg *= 2.3703599
if (tech.isDamageAfterKill) dmg *= (m.lastKillCycle + 300 > m.cycle) ? 2 : 0.66
if (m.isSneakAttack && m.cycle > m.lastKillCycle + 240) dmg *= tech.sneakAttackDmg
if (tech.isTechDamage) dmg *= 1.9
if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
if (tech.isLowEnergyDamage) dmg *= 1 + Math.max(0, 1 - m.energy) * 0.5
if (tech.isMaxEnergyTech) dmg *= 1.5
if (tech.isEnergyNoAmmo) dmg *= 1.6
if (tech.isDamageForGuns) dmg *= 1 + 0.14 * b.inventory.length
if (tech.isLowHealthDmg) dmg *= 1 + 0.5 * Math.max(0, 1 - m.health)
if (tech.isHarmDamage && m.lastHarmCycle + 600 > m.cycle) dmg *= 3;
if (tech.isEnergyLoss) dmg *= 1.55;
if (tech.isAcidDmg && m.health > 1) dmg *= 1.35;
if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage
if (tech.isEnergyDamage) dmg *= 1 + m.energy / 11;
if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.005
if (tech.isRerollDamage) dmg *= 1 + 0.037 * powerUps.research.count
if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.23
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.isBotDamage) dmg *= 1 + 0.06 * b.totalBots()
return dmg * tech.slowFire * tech.aimDamage
},
duplicationChance() {
return (tech.isPowerUpsVanish ? 0.17 : 0) + (tech.isStimulatedEmission ? 0.2 : 0) + tech.cancelCount * 0.048 + tech.duplicateChance + m.duplicateChance + tech.wormDuplicate + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0)
},
maxDuplicationEvent() {
if (tech.is100Duplicate && tech.duplicationChance() > 0.99) {
tech.is100Duplicate = false
const range = 550
for (let i = 0, len = 8; i < len; i++) {
const angle = 2 * Math.PI * i / len
spawn.randomLevelBoss(m.pos.x + range * Math.cos(angle), m.pos.y + range * Math.sin(angle), spawn.nonCollideBossList);
}
// spawn.randomLevelBoss(m.pos.x + range, m.pos.y, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x, m.pos.y + range, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x - range, m.pos.y, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x, m.pos.y - range, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x + range, m.pos.y + range, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x + range, m.pos.y - range, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x - range, m.pos.y + range, spawn.nonCollideBossList);
// spawn.randomLevelBoss(m.pos.x - range, m.pos.y - range, spawn.nonCollideBossList);
}
},
setTechFrequency(name, frequency) {
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].name === name) tech.tech[i].frequency = frequency
}
},
setBotTechFrequency(f = 0) {
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isBotTech) {
switch (tech.tech[i].name) {
case "dynamo-bot":
tech.tech[i].frequency = f
break;
case "orbital-bot":
tech.tech[i].frequency = f
break;
case "laser-bot":
tech.tech[i].frequency = f
break;
case "boom-bot":
tech.tech[i].frequency = f
break;
case "foam-bot":
tech.tech[i].frequency = f
break;
case "nail-bot":
tech.tech[i].frequency = f
break;
}
}
}
},
tech: [{
name: "integrated armament",
description: `increase damage by 23%
your inventory can only hold 1 gun`,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return b.inventory.length === 1 //&& !tech.haveGunCheck("CPT gun")
},
requires: "only 1 gun",
effect() {
tech.isOneGun = true;
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].name === "CPT gun") tech.tech[i].description = `adds the CPT gun to your inventory
it rewinds your health, velocity, and position
replaces your current gun
`
}
},
remove() {
tech.isOneGun = false;
for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].name === "CPT gun") tech.tech[i].description = `adds the CPT gun to your inventory
it rewinds your health, velocity, and position`
}
}
},
{
name: "entanglement",
nameInfo: "",
addNameInfo() {
setTimeout(function() {
simulation.boldActiveGunHUD();
}, 1000);
},
description: "while your first gun is equipped
reduce harm by 13% for each of your guns",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return b.inventory.length > 1 && !tech.isEnergyHealth
},
requires: "at least 2 guns, not mass-energy",
effect() {
tech.isEntanglement = true
setTimeout(function() {
simulation.boldActiveGunHUD();
}, 1000);
},
remove() {
tech.isEntanglement = false;
}
},
{
name: "arsenal",
description: "increase damage by 14%
for each gun in your inventory",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return b.inventory.length > 0
},
requires: "at least 1 gun",
effect() {
tech.isDamageForGuns = true;
},
remove() {
tech.isDamageForGuns = false;
}
},
{
name: "active cooling",
description: "18% decreased delay after firing
for each gun in your inventory",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return b.inventory.length > 0
},
requires: "at least 1 gun",
effect() {
tech.isFireRateForGuns = true;
b.setFireCD();
},
remove() {
tech.isFireRateForGuns = false;
b.setFireCD();
}
},
{
name: "generalist",
description: "spawn 8 guns, but you can't switch guns
guns cycle automatically with each new level",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.isDamageForGuns || tech.isFireRateForGuns) && b.inventory.length + 5 < b.guns.length
},
requires: "arsenal or active cooling and less than 7 guns",
effect() {
tech.isGunCycle = true;
for (let i = 0; i < 8; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
},
remove() {
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: "gun sciences",
description: "spawn a gun and double the frequency
of finding tech for your guns",
maxCount: 1,
count: 0,
frequency: 1,
isNonRefundable: true,
// isExperimentHide: true,
isBadRandomOption: true,
allowed() {
return !tech.isSuperDeterminism
},
requires: "not superdeterminism",
effect() {
powerUps.spawn(m.pos.x, m.pos.y, "gun");
// this.count--
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2
}
},
remove() {}
},
{
name: "ad hoc",
description: "for every gun in your inventory spawn a
heal, research, field, ammo, or tech",
maxCount: 1, //random power up
count: 0,
frequency: 1,
isNonRefundable: true,
// isExperimentHide: 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() < 0.2) {
powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "tech");
} else if (Math.random() < 0.25) {
powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
} else if (Math.random() < 0.33) {
powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "heal");
} else if (Math.random() < 0.5) {
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");
}
}
},
remove() {}
},
{
name: "logistics",
description: "ammo power ups give 80% more ammo
but ammo is only added to your current gun",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isEnergyNoAmmo
},
requires: "not exciton-lattice",
effect() {
tech.isAmmoForGun = true;
},
remove() {
tech.isAmmoForGun = false;
}
},
{
name: "supply chain",
description: "double your current ammo for all guns",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
return tech.isAmmoForGun
},
requires: "logistics",
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();
},
remove() {}
},
{
name: "catabolism",
description: "firing while out of ammo spawns 4 ammo
and reduces your maximum health by 1",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isEnergyNoAmmo && !tech.isEnergyHealth
},
requires: "exciton-lattice, not mass-energy",
effect: () => {
tech.isAmmoFromHealth = true;
},
remove() {
tech.isAmmoFromHealth = false;
}
},
{
name: "desublimated ammunition",
description: "use 50% less ammo when crouching",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect() {
tech.isCrouchAmmo = true
},
remove() {
tech.isCrouchAmmo = false;
}
},
{
name: "gun turret",
description: "reduce harm by 55% when crouching",
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isCrouchAmmo && !tech.isEnergyHealth
},
requires: "desublimated ammunition, not mass-energy",
effect() {
tech.isTurret = true
},
remove() {
tech.isTurret = false;
}
},
{
name: "dead reckoning",
description: "increase damage by 36% when at rest",
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect: () => {
tech.restDamage += 0.36
},
remove() {
tech.restDamage = 1;
}
},
{
name: "Higgs mechanism",
description: "while firing your position is locked
50% decreased delay after firing",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !m.isShipMode && !tech.isAlwaysFire
},
requires: "not ship mode, not automatic",
effect: () => {
tech.isFireMoveLock = true;
b.setFireCD();
b.setFireMethod();
},
remove() {
if (tech.isFireMoveLock) {
tech.isFireMoveLock = false
b.setFireCD();
b.setFireMethod();
}
}
},
{
name: "squirrel-cage rotor",
description: "move and jump about 30% faster
take 5% more harm",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect() { // good with melee builds, content skipping builds
tech.squirrelFx += 0.25;
tech.squirrelJump += 0.1;
m.setMovement()
},
remove() {
tech.squirrelFx = 1;
tech.squirrelJump = 1;
m.setMovement()
}
},
{
name: "Newton's 1st law",
description: "moving at high speeds reduces harm
by up to 66%",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy equivalence",
effect() {
tech.isSpeedHarm = true //max at speed = 40
},
remove() {
tech.isSpeedHarm = false
}
},
{
name: "Newton's 2nd law",
description: "moving at high speeds increases damage
by up to 66%",
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: "kinetic bombardment",
description: "increase damage by up to 33%
at a distance of 40 steps from the target",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect() {
tech.isFarAwayDmg = true; //used in mob.damage()
},
remove() {
tech.isFarAwayDmg = false;
}
},
{
name: "simulated annealing",
description: "increase damage by 20%
20% increased delay after firing",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
effect() {
tech.slowFire = 1.2
b.setFireCD();
},
remove() {
tech.slowFire = 1;
b.setFireCD();
}
},
{
name: "auto-loading heuristics",
description: "30% decreased delay after firing",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect() {
tech.fireRate *= 0.7
b.setFireCD();
},
remove() {
tech.fireRate = 1;
b.setFireCD();
}
},
{
name: "fracture analysis",
description: "bullet impacts do 400% damage
to stunned mobs",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isExplosionStun
},
requires: "a stun effect",
effect() {
tech.isCrit = true;
},
remove() {
tech.isCrit = false;
}
},
{
name: "microstates",
description: "increase damage by 6%
for every 10 active projectiles",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect() {
tech.isDamageFromBulletCount = true
},
remove() {
tech.isDamageFromBulletCount = false
}
},
{
name: "anti-shear topology",
description: "some projectiles last 30% longer
drones, spores, missiles, foam, wave, neutron",
// isGunTech: true,
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("wave beam") || tech.isNeutronBomb || tech.isIceField || tech.isIceShot || tech.relayIce || tech.blockingIce > 1
},
requires: "drones, spores, missiles, foam, wave beam, neutron bomb, ice IX",
effect() {
tech.isBulletsLastLonger += 0.3
},
remove() {
tech.isBulletsLastLonger = 1;
}
},
{
name: "radioactive contamination",
description: "after a mob or shield dies,
leftover radiation spreads to a nearby mob",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio
},
requires: "radiation damage source",
effect() {
tech.isRadioactive = true
},
remove() {
tech.isRadioactive = false
}
},
{
name: "water shielding",
description: "radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio
},
requires: "neutron bomb or irradiated drones or iridium-192",
effect() {
tech.isRadioactiveResistance = true
},
remove() {
tech.isRadioactiveResistance = false
}
},
{
name: "iridium-192",
description: "explosions release gamma radiation
100% more damage, but over 4 seconds",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isTokamak)
},
requires: "an explosive damage source, not ammonium nitrate or nitroglycerin",
effect: () => {
tech.isExplodeRadio = true; //iridium-192
},
remove() {
tech.isExplodeRadio = false;
}
},
{
name: "ammonium nitrate",
description: "increase explosive damage by 30%
increase explosive radius by 30%",
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.3;
},
remove() {
tech.explosiveRadius = 1;
}
},
{
name: "nitroglycerin",
description: "increase explosive damage by 66%
decrease explosive radius by 33%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
},
requires: "an explosive damage source, not iridium-192",
effect: () => {
tech.isSmallExplosion = true;
},
remove() {
tech.isSmallExplosion = false;
}
},
{
name: "acetone peroxide",
description: "increase explosive radius by 80%, but
you take 300% more harm from explosions",
maxCount: 1,
count: 0,
frequency: 2,
isBadRandomOption: true,
allowed() {
return tech.hasExplosiveDamageCheck()
},
requires: "an explosive damage source",
effect: () => {
tech.isExplosionHarm = true;
},
remove() {
tech.isExplosionHarm = false;
}
},
{
name: "shock wave",
description: "explosions stun mobs for 1-2 seconds
decrease explosive damage by 30%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
},
requires: "an explosive damage source, not iridium-192",
effect() {
tech.isExplosionStun = true;
},
remove() {
tech.isExplosionStun = false;
}
},
{
name: "electric reactive armor",
// description: "explosions do no harm
while your energy is above 98%",
description: "harm from explosions is passively reduced
by 6% for every 10 stored energy",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
},
requires: "an explosive damage source, not iridium-192",
effect: () => {
tech.isImmuneExplosion = true;
},
remove() {
tech.isImmuneExplosion = false;
}
},
{
name: "incendiary ammunition",
description: "shotgun, super balls, and drones
are loaded with explosives",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isDroneTeleport || tech.isDroneRadioactive || tech.isSporeField || tech.isMissileField || tech.isIceField)) || (tech.haveGunCheck("drones") && !tech.isDroneRadioactive && !tech.isDroneTeleport) || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot
},
requires: "super balls, basic or slug shotgun, drones, not irradiated drones or burst drones",
effect() {
tech.isIncendiary = true
},
remove() {
tech.isIncendiary = false;
}
},
{
name: "fragmentation",
description: "some detonations and collisions eject nails
blocks, rail gun, grenades, missiles, shotgun slugs",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || tech.missileBotCount || tech.haveGunCheck("rail gun") || (tech.haveGunCheck("shotgun") && tech.isSlugShot) || tech.throwChargeRate > 1
},
requires: "grenades, missiles, rail gun, shotgun slugs, or mass driver",
effect() {
tech.fragments++
},
remove() {
tech.fragments = 0
}
},
{
name: "thermal runaway",
description: "mobs explode when they die",
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: "impact shear",
description: "mobs release a nail when they die
nails target 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: "zoospore vector",
description: "mobs produce spores when they die
11% chance",
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.11;
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: "reaction inhibitor",
description: "mobs spawn with 11% less health",
maxCount: 3,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath
},
requires: "any mob death tech",
effect: () => {
tech.mobSpawnWithHealth *= 0.89
//set all mobs at full health to 0.85
for (let i = 0; i < mob.length; i++) {
if (mob.health > tech.mobSpawnWithHealth) mob.health = tech.mobSpawnWithHealth
}
},
remove() {
tech.mobSpawnWithHealth = 1;
}
},
{
name: "decorrelation",
description: "reduce harm by 70% after not activating
your gun or field for 2 seconds",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isEnergyHealth //((m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" && (tech.blockingIce !== 0 || tech.blockDmg !== 0)) || b.totalBots() > 1 || tech.haveGunCheck("mine") || tech.haveGunCheck("spores") || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing") &&
},
requires: "not mass-energy",
effect() {
tech.isNoFireDefense = true
},
remove() {
tech.isNoFireDefense = false
}
},
{
name: "anticorrelation",
description: "increase damage by 100%
after not using your gun or field for 2 seconds",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNoFireDefense
},
requires: "decorrelation",
effect() {
tech.isNoFireDamage = true
},
remove() {
tech.isNoFireDamage = false
}
},
{
name: "scrap bots",
description: "33% chance after killing a mob to build
a scrap bot that operates for 14 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",
description: "killing a mob resets your functional scrap bots
to 14 seconds of operation",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
allowed() {
return tech.botSpawner
},
requires: "scrap bots",
effect() {
tech.isBotSpawnerReset = true;
},
remove() {
tech.isBotSpawnerReset = false;
}
},
{
name: "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",
description: "convert all your bots to nail-bots
500% increased nail-bot fire rate",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.nailBotCount > 1 && !b.hasBotUpgrade()
},
requires: "2 or more nail bots and only 1 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)
},
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
}
},
{
name: "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();
}
}
},
{
name: "foam-bot upgrade",
description: "convert all your bots to foam-bots
250% increased foam size and fire rate",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.foamBotCount > 1 && !b.hasBotUpgrade()
},
requires: "2 or more foam bots and only 1 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 = false
}
tech.setBotTechFrequency(1)
}
tech.isFoamBotUpgrade = false
}
},
{
name: "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();
}
}
},
{
name: "boom-bot upgrade",
description: "convert all your bots to boom-bots
250% increased explosion damage and size",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.boomBotCount > 1 && !b.hasBotUpgrade()
},
requires: "2 or more boom bots and only 1 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 = false
}
tech.setBotTechFrequency(1)
}
tech.isBoomBotUpgrade = false
}
},
{
name: "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();
}
}
},
{
name: "laser-bot upgrade",
description: "convert all your bots to laser-bots
75% improved damage, efficiency, and range", // 400% increased laser-bot laser damage",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.laserBotCount > 1 && !b.hasBotUpgrade()
},
requires: "2 or more laser bots and only 1 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 = false
}
tech.setBotTechFrequency(1)
}
tech.isLaserBotUpgrade = false
}
},
{
name: "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();
}
}
},
{
name: "orbital-bot upgrade",
description: "convert all your bots to orbital-bots
increase damage by 250% and radius by 40%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.orbitBotCount > 1 && !b.hasBotUpgrade()
},
requires: "2 or more orbital bots and only 1 bot upgrade",
effect() {
tech.isOrbitBotUpgrade = true
b.convertBotsTo("orbital-bot")
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
}
},
{
name: "dynamo-bot",
description: "a bot damages mobs while it traces your path
regen 6 energy per second when it's near",
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();
}
}
},
{
name: "dynamo-bot upgrade",
description: "convert your bots to dynamo-bots
increase regen to 16 energy per second",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.dynamoBotCount > 1 && !b.hasBotUpgrade()
},
requires: "2 or more dynamo bots and only 1 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 = false
}
tech.setBotTechFrequency(1)
}
tech.isDynamoBotUpgrade = false
}
},
{
name: "bot fabrication",
description: "anytime you collect 4 research
use them to build a random bot",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return powerUps.research.count > 3 || build.isExperimentSelection
},
requires: "at least 4 research",
effect() {
tech.isRerollBots = true;
powerUps.research.changeRerolls(0)
simulation.makeTextLog(`m.research = 0`)
},
remove() {
tech.isRerollBots = false;
}
},
{
name: "robotics",
description: "use 1 research to spawn a random bot
quadruple the frequency of finding bot tech",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
allowed() {
return (b.totalBots() > 1 && powerUps.research.count > 0) || build.isExperimentSelection
},
requires: "at least 2 bots",
effect: () => {
if (powerUps.research.count > 0) {
powerUps.research.changeRerolls(-1)
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) {
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isBotTech) tech.tech[i].frequency /= 4
}
}
}
},
{
name: "perimeter defense",
description: "reduce harm by 7%
for each of your permanent bots",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return b.totalBots() > 3 && !tech.isEnergyHealth
},
requires: "at least 4 bots",
effect() {
tech.isBotArmor = true
},
remove() {
tech.isBotArmor = false
}
},
{
name: "network effect",
description: "increase damage by 6%
for each of your permanent bots",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return b.totalBots() > 3
},
requires: "at least 4 bots",
effect() {
tech.isBotDamage = true
},
remove() {
tech.isBotDamage = false
}
},
{
name: "ersatz bots",
description: "double your current permanent bots
remove all of your current guns",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
// isNonRefundable: true,
isBadRandomOption: true,
numberOfGunsLost: 0,
allowed() {
return b.totalBots() > 3
},
requires: "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();
}
}
},
{
name: "mass driver",
description: "charge throws more quickly for less energy
increase block collision damage by 200%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name !== "wormhole"
},
requires: "not wormhole",
effect() {
tech.throwChargeRate = 3
},
remove() {
tech.throwChargeRate = 1
}
},
{
name: "inflation",
description: "throwing a block expands it by 300%
increase throw charge rate by 200%",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name === "pilot wave" && !tech.isTokamak
},
requires: "mass driver, not pilot wave not tokamak",
effect() {
tech.isAddBlockMass = true
},
remove() {
tech.isAddBlockMass = false
}
},
{
name: "restitution",
description: "throwing a block makes it very bouncy
increase block collision damage by 150%",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name === "pilot wave" && !tech.isTokamak
},
requires: "mass driver, not pilot wave not tokamak",
effect() {
tech.isBlockRestitution = true
},
remove() {
tech.isBlockRestitution = false
}
},
{
name: "flywheel",
description: "after a mob dies its block is flung at mobs
increase block collision damage by 150%",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.throwChargeRate > 1 && !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.throwChargeRate > 1 || 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: "inelastic collision",
description: "holding a block reduces harm by 85%
increase block collision damage by 150%",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name === "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isEnergyHealth
},
requires: "mass driver, a field that can hold things, not mass-energy",
effect() {
tech.isBlockHarm = true
},
remove() {
tech.isBlockHarm = false
}
},
{
name: "buckling",
description: "if a block you threw kills a mob
spawn 1 heal, ammo, or research",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name === "pilot wave" && !tech.isTokamak
},
requires: "mass driver, not pilot wave not tokamak",
effect() {
tech.isBlockPowerUps = true
},
remove() {
tech.isBlockPowerUps = false
}
},
{
name: "Pauli exclusion",
description: `after receiving harm from a collision become
immune to harm for 1 extra second`,
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.collisionImmuneCycles += 60;
if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles
},
remove() {
tech.collisionImmuneCycles = 30;
}
},
{
name: "complex spin-statistics",
description: `become immune to harm for 1.5 seconds
once every 7 seconds`,
maxCount: 3,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true //tech.collisionImmuneCycles > 30
},
requires: "",
effect() {
tech.cyclicImmunity += 90;
},
remove() {
tech.cyclicImmunity = 0;
}
},
{
name: "NOR gate",
description: "if flip-flop is in the ON state
take 0 harm from collisions with mobs",
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isFlipFlop
},
requires: "flip-flop",
effect() {
tech.isFlipFlopHarm = true //do you have this tech
},
remove() {
tech.isFlipFlopHarm = false
}
},
{
name: "flip-flop",
description: `toggle ON and OFF after a collision
unlock 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?
tech.isFlipFlopOn = true //what is the state of flip-Flop?
if (!m.isShipMode) {
m.draw = m.drawFlipFlop
}
},
remove() {
tech.isFlipFlop = false
tech.isFlipFlopOn = false
m.eyeFillColor = 'transparent'
}
},
{
name: "relay switch",
description: `toggle ON and OFF after picking up a power up
unlock 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() {
tech.isRelay = true //do you have this tech?
tech.isFlipFlopOn = true //what is the state of flip-Flop?
if (!m.isShipMode) {
m.draw = m.drawFlipFlop
}
},
remove() {
tech.isRelay = false
tech.isFlipFlopOn = false
m.eyeFillColor = 'transparent'
}
},
{
name: "thermocouple",
description: "if relay switch is in the ON state
condense 1-7 ice IX crystals every second",
maxCount: 9,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isRelay
},
requires: "relay switch",
effect() {
tech.relayIce++
},
remove() {
tech.relayIce = 0
}
},
{
name: "NAND gate",
description: "if in the ON state
do 45% more damage",
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isFlipFlop || tech.isRelay
},
requires: "ON/OFF tech",
effect() {
tech.isFlipFlopDamage = true;
},
remove() {
tech.isFlipFlopDamage = false;
}
},
{
name: "transistor",
description: "if ON regen 22 energy per second
if OFF drain 4.1 energy per second",
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isFlipFlop || tech.isRelay
},
requires: "ON/OFF tech",
effect() {
tech.isFlipFlopEnergy = true;
},
remove() {
tech.isFlipFlopEnergy = false;
}
},
{
name: "shift registers",
description: "set to the ON state
at the start of a level",
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isFlipFlopEnergy || tech.isFlipFlopDamage || tech.isFlipFlopHarm || tech.relayIce
},
requires: "2 ON/OFF techs",
effect() {
tech.isFlipFlopLevelReset = true;
},
remove() {
tech.isFlipFlopLevelReset = false;
}
},
{
name: "crystallizer",
description: "after frozen mobs die they
shatter into ice IX crystals",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField || tech.isIceShot || tech.relayIce || tech.blockingIce > 1) && !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: "killing mobs with ice IX
generates 100 energy",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isIceField || tech.relayIce || tech.blockingIce || 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",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField || tech.relayIce || tech.blockingIce > 1 || tech.iceIXOnDeath || tech.isIceShot
},
requires: "a localized freeze effect",
effect() {
tech.isAoESlow = true
},
remove() {
tech.isAoESlow = false
}
},
{
name: "osmoprotectant",
description: `collisions with stunned or frozen mobs
cause you no harm`,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isStunField || tech.isExplosionStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 || tech.iceIXOnDeath || tech.isIceShot
},
requires: "a freezing or stunning effect",
effect() {
tech.isFreezeHarmImmune = true;
},
remove() {
tech.isFreezeHarmImmune = false;
}
},
{
name: "liquid cooling",
description: `freeze all mobs for 7 seconds
after receiving harm`,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.isSlowFPS
},
requires: "clock gating",
effect() {
tech.isHarmFreeze = true;
},
remove() {
tech.isHarmFreeze = false;
}
},
{
name: "clock gating",
description: `slow time by 50% after receiving harm
reduce harm by 20%`,
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: "MACHO",
description: "a massive but compact object slowly follows you
take 66% less harm inside it's halo",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy",
effect: () => {
tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO
spawn.MACHO()
},
remove() {
tech.isMACHO = false;
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isMACHO) mob[i].alive = false;
}
}
},
{
name: "ablative drones",
description: "rebuild your broken parts as drones
chance to occur after receiving harm",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.harmReduction() < 1
},
requires: "some harm reduction",
effect() {
tech.isDroneOnDamage = true;
for (let i = 0; i < 4; i++) {
b.drone() //spawn drone
}
},
remove() {
tech.isDroneOnDamage = false;
}
},
{
name: "non-Newtonian armor",
description: "for 10 seconds after receiving harm
reduce harm by 66%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isEnergyHealth && m.harmReduction() < 1
},
requires: "some harm reduction",
effect() {
tech.isHarmArmor = true;
},
remove() {
tech.isHarmArmor = false;
}
},
{
name: "radiative equilibrium",
description: "for 10 seconds after receiving harm
increase damage by 200%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.harmReduction() < 1
},
requires: "some harm reduction",
effect() {
tech.isHarmDamage = true;
},
remove() {
tech.isHarmDamage = false;
}
},
{
name: "CPT reversal",
description: "charge, parity, and time invert to undo harm
rewind (1.5—5) seconds for (66—220) energy",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() { //&& (m.fieldUpgrades[m.fieldMode].name !== "nano-scale manufacturing" || m.maxEnergy > 1)
return m.maxEnergy > 0.99 && m.fieldUpgrades[m.fieldMode].name !== "standing wave harmonics" && !tech.isEnergyHealth && !tech.isRewindGun
},
requires: "not standing wave, mass-energy, max energy reduction, CPT gun",
effect() {
tech.isRewindAvoidDeath = true;
},
remove() {
tech.isRewindAvoidDeath = false;
}
},
{
name: "causality bots",
description: "when you rewind, build several bots
that protect you for about 9 seconds",
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.isRewindAvoidDeath
},
requires: "CPT",
effect() {
tech.isRewindBot++;
},
remove() {
tech.isRewindBot = 0;
}
},
{
name: "causality bombs",
description: "before you rewind drop several grenades
become immune to harm until they explode",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isRewindAvoidDeath
},
requires: "CPT",
effect() {
tech.isRewindGrenade = true;
},
remove() {
tech.isRewindGrenade = false;
}
},
{
name: "piezoelectricity",
description: "colliding with mobs gives you 2048 energy", //
reduce harm by 15%
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy",
effect() {
tech.isPiezo = true;
m.energy += 20.48;
},
remove() {
tech.isPiezo = false;
}
},
{
name: "ground state",
description: "reduce harm by 66%
you no longer passively regenerate energy",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.iceEnergy || tech.isWormholeEnergy || tech.isPiezo || tech.isRailEnergyGain || tech.energySiphon || tech.isEnergyRecovery || tech.dynamoBotCount || tech.isFlipFlopEnergy || tech.isTokamak) && tech.energyRegen !== 0.004 && !tech.isEnergyHealth
},
requires: "a way to regen extra energy, not time crystals",
effect: () => {
tech.energyRegen = 0;
m.fieldRegen = tech.energyRegen;
},
remove() {
tech.energyRegen = 0.001;
m.fieldRegen = tech.energyRegen;
}
},
{
name: "mass-energy equivalence",
description: "energy protects you instead of health
harm reduction effects provide no benefit",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isZeno && !tech.isNoHeals && !tech.isPiezo && !tech.isRewindAvoidDeath && !tech.isRewindGun && !tech.isTechDamage && !tech.isMutualism
},
requires: "not Zeno, ergodicity, piezoelectricity, CPT, rewind gun, antiscience, mutualism",
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(14, 190, 235,0.7)" //"#0cf"
m.displayHealth();
},
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();
}
}
},
{
name: "1st ionization energy",
description: "each heal power up you collect
increases your maximum energy by 6",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isEnergyHealth
},
requires: "mass-energy equivalence",
effect() {
tech.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
powerUps.heal.color = "#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() {
tech.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: "inductive coupling",
description: "each unused power up at the end of a level
adds 3 maximum energy", // (up to 51 health per level)",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isDroneGrab
},
requires: "not drone harvester",
effect() {
tech.isExtraMaxEnergy = true; //tracked by tech.extraMaxHealth
},
remove() {
tech.isExtraMaxEnergy = false;
}
},
{
name: "transceiver chip",
description: "unused power ups at the end of each level
are still activated (selections are random)",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isExtraMaxEnergy
},
requires: "inductive coupling",
effect() {
tech.isEndLevelPowerUp = true;
},
remove() {
tech.isEndLevelPowerUp = false;
}
},
{
name: "electrolytes",
description: "increase damage by 1%
for every 11 stored energy",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect: () => {
tech.isEnergyDamage = true
},
remove() {
tech.isEnergyDamage = false;
}
},
{
name: "exciton-lattice",
description: `increase damage by 60%, but
ammo will no longer spawn`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.isEnergyNoAmmo = true;
},
remove() {
tech.isEnergyNoAmmo = false;
}
},
{
name: "exothermic process",
description: "increase damage by 50%
if a mob dies drain energy by 25%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return true
},
requires: "",
effect() {
tech.isEnergyLoss = true;
},
remove() {
tech.isEnergyLoss = false;
}
},
{
name: "heat engine",
description: `increase damage by 50%, but
reduce maximum energy by 50`,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isEnergyLoss && !tech.isRewindAvoidDeath
},
requires: "exothermic process, not CPT",
effect() {
tech.isMaxEnergyTech = true;
m.setMaxEnergy()
},
remove() {
tech.isMaxEnergyTech = false;
m.setMaxEnergy()
}
},
{
name: "Gibbs free energy",
description: `increase damage by 5%
for every 10 energy below 100`,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isEnergyLoss && m.maxEnergy < 1.01
},
requires: "exothermic process, not max energy increase",
effect() {
tech.isLowEnergyDamage = true;
},
remove() {
tech.isLowEnergyDamage = false;
}
},
{
name: "overcharge",
description: "increase your maximum energy by 60
+10 JUNK to the potential tech pool",
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.bonusEnergy += 0.6
m.setMaxEnergy()
tech.addJunkTechToPool(10)
},
remove() {
tech.bonusEnergy = 0;
m.setMaxEnergy()
if (this.count > 0) tech.removeJunkTechFromPool(10)
}
},
{
name: "Maxwell's demon",
description: "energy above your max decays 92% slower
+18 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isEnergyRecovery || tech.isPiezo || tech.energySiphon > 0 || tech.isRailEnergyGain || tech.isWormholeEnergy || tech.iceEnergy > 0 || tech.isMassEnergy || tech.isTokamak
},
requires: "a source of overfilled energy",
effect() {
tech.overfillDrain = 0.85 //70% = 1-(1-0.75)/(1-0.15) //92% = 1-(1-0.75)/(1-0.87)
tech.addJunkTechToPool(18)
},
remove() {
tech.overfillDrain = 0.7
if (this.count > 0) tech.removeJunkTechFromPool(18)
}
},
{
name: "energy conservation",
description: "6% of damage done recovered as energy",
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.energySiphon += 0.06;
},
remove() {
tech.energySiphon = 0;
}
},
{
name: "waste energy recovery",
description: "if a mob has died in the last 5 seconds
regen 5% of max energy every second",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.isEnergyRecovery = true;
},
remove() {
tech.isEnergyRecovery = false;
}
},
{
name: "scrap recycling",
description: "if a mob has died in the last 5 seconds
regain 1% of max health every second",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isHealTech: true,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy equivalence",
effect() {
tech.isHealthRecovery = true;
},
remove() {
tech.isHealthRecovery = false;
}
},
{
name: "dormancy",
description: "if a mob has died in the last 5 seconds
increase damage by 99% else decrease it by 33%",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.isDamageAfterKill = true;
},
remove() {
tech.isDamageAfterKill = false;
}
},
{
name: "torpor",
description: "if a mob has died in the last 5 seconds
reduce harm by 66% else increase it by 15%",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.isDamageAfterKill && !tech.isEnergyHealth
},
requires: "dormancy, not mass-energy",
effect() {
tech.isHarmReduceAfterKill = true;
},
remove() {
tech.isHarmReduceAfterKill = false;
}
},
{
name: "Zeno's paradox",
description: "reduce harm by 84%, but every 5 seconds
remove 1/10 of your current health",
// description: "every 5 seconds remove 1/10 of your health
reduce harm by 90%",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy",
effect() {
tech.isZeno = true;
},
remove() {
tech.isZeno = false;
}
},
{
name: "negative feedback",
description: "increase damage by 5%
for every 10 health below 100",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
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: "antiscience",
description: "increase damage by 90%
lose 11 health when you pick up a tech",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy",
effect() {
tech.isTechDamage = true;
},
remove() {
tech.isTechDamage = false;
}
},
{
name: "entropy exchange",
description: "heal for 3% of damage done
take 10% more harm",
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
isHealTech: true,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy equivalence",
effect() {
tech.healthDrain += 0.03;
},
remove() {
tech.healthDrain = 0;
}
},
{
name: "fluoroantimonic acid",
description: "increase damage by 35%
when your health is above 100",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.maxHealth > 1;
},
requires: "health above 100",
effect() {
tech.isAcidDmg = true;
},
remove() {
tech.isAcidDmg = false;
}
},
{
name: "tungsten carbide",
description: "increase your maximum health by 100
landings that force you to crouch cause harm",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy equivalence",
effect() {
tech.isFallingDamage = true;
m.setMaxHealth();
m.addHealth(1 / simulation.healScale)
},
remove() {
tech.isFallingDamage = false;
m.setMaxHealth();
}
},
{
name: "quenching",
description: "over healing from heal power ups does harm
but it also increase your maximum health",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isEnergyHealth && !tech.isNoHeals
},
requires: "not mass-energy equivalence, ergodicity",
effect() {
tech.isOverHeal = true;
},
remove() {
tech.isOverHeal = false;
}
},
{
name: "negative entropy",
description: `at the start of each level
spawn a heal for every 26 missing health`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isHealTech: true,
allowed() {
return m.health > 0.1 && !tech.isNoHeals
},
requires: "has some health, not ergodicity",
effect() {
tech.isHealLowHealth = true;
},
remove() {
tech.isHealLowHealth = false;
}
},
{
name: "adiabatic healing",
description: "heal power ups are 100% more effective",
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
isHealTech: true,
allowed() {
return ((m.health / m.maxHealth) < 0.7 || build.isExperimentSelection) && !tech.isEnergyHealth && !tech.isNoHeals
},
requires: "under 70% health, not mass-energy equivalence, ergodicity",
effect() {
tech.largerHeals++;
},
remove() {
tech.largerHeals = 1;
}
},
{
name: "maintenance",
description: "double the frequency of finding healing tech
spawn 11 heals",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 11; 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
}
},
remove() {}
},
{
name: "anthropic principle",
nameInfo: "",
addNameInfo() {
setTimeout(function() {
powerUps.research.changeRerolls(0)
}, 1000);
},
description: "once per level, instead of dying
consume 1 research and spawn 6 heals",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
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;
}
},
{
name: "weak anthropic principle",
description: "after anthropic principle prevents your death
add 50% duplication chance for that level",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.isDeathAvoid && tech.duplicationChance() < 0.66
},
requires: "anthropic principle, below 66% duplication chance",
effect() {
tech.isAnthropicTech = true
powerUps.setDo(); //needed after adjusting duplication chance
},
remove() {
tech.isAnthropicTech = false
powerUps.setDo(); //needed after adjusting duplication chance
}
},
{
name: "strong anthropic principle",
description: "after anthropic principle prevents your death
increase damage by 137.03599% 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: "reduce harm by 33%
after dying, continue in an alternate reality",
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.isDeathAvoid
},
requires: "anthropic principle",
effect() {
tech.isImmortal = true;
},
remove() {
tech.isImmortal = false;
}
},
{
name: "non-unitary operator",
description: "reduce combat difficulty by 2 levels, but
after a collision enter an alternate reality",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isResearchReality && !tech.isSwitchReality
},
requires: "Ψ(t) collapse, many-worlds",
effect() {
tech.isCollisionRealitySwitch = true;
level.difficultyDecrease(simulation.difficultyMode * 2)
},
remove() {
tech.isCollisionRealitySwitch = false;
if (this.count > 0) {
level.difficultyIncrease(simulation.difficultyMode * 2)
}
}
},
{
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 use 1 research to enter an
alternate reality and spawn a tech power up",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isResearchReality && !tech.isCollisionRealitySwitch
},
requires: "not Ψ(t) collapse, non-unitary",
effect() {
tech.isSwitchReality = true;
},
remove() {
tech.isSwitchReality = false;
}
},
{
name: "Ψ(t) collapse",
description: "enter an alternate reality after you research
spawn 16 research",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch
},
requires: "many-worlds, non-unitary, not pseudoscience",
effect() {
tech.isResearchReality = true;
for (let i = 0; i < 16; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false);
},
remove() {
tech.isResearchReality = false;
}
},
{
name: "decoherence",
description: "researched or canceled tech won't reoccur
spawn 9 research",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (powerUps.research.count > 2 || build.isExperimentSelection) && !tech.isDeterminism
},
requires: "not determinism, at least 3 research",
effect() {
tech.isBanish = true
for (let i = 0; i < 9; 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
powerUps.tech.banishLog = [] //reset banish log
powerUps.research.changeRerolls(-10)
}
}
},
{
name: "renormalization",
description: "using a research for any purpose
has a 40% chance to spawn a research",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (powerUps.research.count > 2 || build.isExperimentSelection) && !tech.isSuperDeterminism
},
requires: "at least 3 research and not superdeterminism",
effect() {
tech.renormalization = true;
},
remove() {
tech.renormalization = false;
}
},
{
name: "perturbation theory",
description: "66% decreased delay after firing
when you have no research in your inventory",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return powerUps.research.count === 0
},
requires: "no research",
effect() {
tech.isRerollHaste = true;
tech.researchHaste = 0.33;
b.setFireCD();
},
remove() {
tech.isRerollHaste = false;
tech.researchHaste = 1;
b.setFireCD();
}
},
{
name: "ansatz",
description: "after choosing a field, tech, or gun
if you have no research spawn 2",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return powerUps.research.count === 0 && !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: "increase damage by 3.7%
for each research in your inventory",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return powerUps.research.count > 4 || build.isExperimentSelection
},
requires: "at least 5 research",
effect() {
tech.isRerollDamage = true;
},
remove() {
tech.isRerollDamage = false;
}
},
{
name: "pseudoscience",
description: "when selecting a power up, research 3 times
for free, but add 0-3 JUNK to the tech pool",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isResearchReality //tech.isResearchBoss || tech.isMetaAnalysis || tech.isRerollBots || tech.isDeathAvoid || tech.isRerollDamage || build.isExperimentSelection
},
requires: "not Ψ(t) collapse", //"abiogenesis, meta-analysis, bot fabrication, anthropic principle, or Bayesian statistics, not Ψ(t) collapse",
effect() {
tech.isJunkResearch = true;
},
remove() {
tech.isJunkResearch = false;
}
},
{
name: "Born rule",
description: "remove all current tech
spawn new tech to replace them",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
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: "abiogenesis",
description: "at the start of a level spawn a 2nd boss for
4 research or +49 JUNK to the tech pool",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (build.isExperimentSelection || powerUps.research.count > 3) && !tech.isDuplicateBoss
},
requires: "at least 4 research and not parthenogenesis",
effect() {
tech.isResearchBoss = true; //abiogenesis
},
remove() {
tech.isResearchBoss = false;
}
},
{
name: "bubble fusion",
description: "after destroying a mob's natural shield
spawn 1-2 heals, ammo, or research",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.isShieldAmmo = true;
},
remove() {
tech.isShieldAmmo = false;
}
},
{
name: "meta-analysis",
description: "if you choose a JUNK tech you instead get a
random normal tech and 5 research",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.duplicateChance
},
requires: "replication",
effect() {
tech.isMetaAnalysis = true
},
remove() {
tech.isMetaAnalysis = false
}
},
{
name: "replication",
description: "10% chance to duplicate spawned power ups
+30 JUNK to the potential 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.setDo(); //needed after adjusting duplication chance
tech.addJunkTechToPool(30)
},
remove() {
tech.duplicateChance = 0
powerUps.setDo(); //needed after adjusting duplication chance
if (this.count > 1) tech.removeJunkTechFromPool(30)
}
},
{
name: "stimulated emission",
description: "20% 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 100% duplication chance",
effect: () => {
tech.isStimulatedEmission = true
powerUps.setDo(); //needed after adjusting duplication chance
},
remove() {
tech.isStimulatedEmission = false
powerUps.setDo(); //needed after adjusting duplication chance
}
},
{
name: "metastability",
description: "17% chance to duplicate spawned power ups
duplicates 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.setDo(); //needed after adjusting duplication chance
},
remove() {
tech.isPowerUpsVanish = false
powerUps.setDo(); //needed after adjusting duplication chance
}
},
{
name: "futures exchange",
description: "clicking × to cancel a field, tech, or gun
adds 4.8% power up duplication chance",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.duplicationChance() < 1 && !tech.isDeterminism
},
requires: "below 100% duplication chance, not determinism",
effect() {
// tech.cancelCount = 0
tech.isCancelDuplication = true
powerUps.setDo(); //needed after adjusting duplication chance
},
remove() {
// tech.cancelCount = 0
tech.isCancelDuplication = false
powerUps.setDo(); //needed after adjusting duplication chance
}
},
{
name: "commodities exchange",
description: "clicking × to cancel a field, tech, or gun
spawns 9 heals, ammo, and research",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isDeterminism
},
requires: "not determinism",
effect() {
tech.isCancelRerolls = true
},
remove() {
tech.isCancelRerolls = false
}
},
{
name: "correlated damage",
description: "your chance to duplicate power ups
increases your damage by the same percent",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.duplicationChance() > 0.15
},
requires: "duplication chance > 15%",
effect() {
tech.isDupDamage = true;
},
remove() {
tech.isDupDamage = false;
}
},
{
name: "parthenogenesis",
description: "levels have a chance to spawn a 2nd boss
equal to double your duplication chance",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.duplicationChance() > 0 && !tech.isResearchBoss
},
requires: "some duplication chance, not abiogenesis",
effect() {
tech.isDuplicateBoss = true;
},
remove() {
tech.isDuplicateBoss = false;
}
},
{
name: "apomixis",
description: "after reaching 100% duplication chance
immediately spawn 8 bosses",
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.duplicationChance() > 0.6
},
requires: "duplication chance above 60%",
effect() {
tech.is100Duplicate = true;
tech.maxDuplicationEvent()
},
remove() {
tech.is100Duplicate = false;
}
},
{
name: "exchange symmetry",
description: "convert 1 random tech into 3 new guns
recursive tech lose all stacks",
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) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
simulation.makeTextLog(`tech.remove("${tech.tech[choose].name}")`)
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 experiment",
description: "spawn 2 tech
remove 1 random tech",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
return (tech.totalCount > 3) && !tech.isSuperDeterminism && tech.duplicationChance() > 0
},
requires: "at least 4 tech, a chance to duplicate power ups, not superdeterminism",
effect: () => {
const removeTotal = powerUps.removeRandomTech()
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",
description: `use 2 research to spawn 1 tech
with double your duplication chance`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
return !tech.isSuperDeterminism && tech.duplicationChance() > 0 && powerUps.research.count > 1
},
requires: "at least 2 research, not super determinism",
effect: () => {
powerUps.research.changeRerolls(-2)
simulation.makeTextLog(`m.research -= 2
${powerUps.research.count}`)
const chanceStore = tech.duplicateChance
tech.duplicateChance = (tech.isStimulatedEmission ? 0.2 : 0) + tech.cancelCount * 0.045 + m.duplicateChance + tech.duplicateChance * 2 //increase duplication chance to simulate doubling all 3 sources of duplication chance
powerUps.spawn(m.pos.x, m.pos.y, "tech");
tech.duplicateChance = chanceStore
},
remove() {}
},
{
name: "vector fields",
description: "double the frequency of finding field tech
spawn a field",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
return !tech.isSuperDeterminism
},
requires: "not superdeterminism",
effect() {
powerUps.spawn(m.pos.x, m.pos.y, "field");
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isFieldTech) tech.tech[i].frequency *= 2
}
},
remove() {
// 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: "reinforcement learning",
description: "increase the frequency of finding copies of
recursive tech you already have 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
}
},
remove() {
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",
description: "use 2 research to choose all the unchosen
tech from your previous tech selection",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isNonRefundable: true,
isBadRandomOption: true,
allowed() {
return powerUps.tech.choiceLog.length > 10 && !tech.isDeterminism && powerUps.research.count > 1
},
requires: "rejected an option in the last tech selection, at least 2 research, not determinism",
effect: () => {
powerUps.research.changeRerolls(-2)
let num = 3
if (tech.isExtraChoice) 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() {}
},
{
name: "unified field theory",
description: `spawn 6 research, and when paused
clicking the field box switches your field`,
// description: `in the pause menu, change your field
by clicking on your field's box`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isSuperDeterminism
},
requires: "not superdeterminism",
effect() {
tech.isGunSwitchField = true;
for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
},
remove() {
if (tech.isGunSwitchField) {
tech.isGunSwitchField = false;
powerUps.research.changeRerolls(-6)
}
}
},
{
name: "cross disciplinary",
description: "tech have an extra field or gun choice", //
+7 JUNK to the potential tech pool //
spawn 2 research
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isDeterminism
},
requires: "not determinism",
effect: () => {
tech.isExtraGunField = true;
// for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
},
remove() {
tech.isExtraGunField = false;
// if (this.count > 0) powerUps.research.changeRerolls(-2)
}
},
{
name: "emergence",
description: "tech, fields, and guns have 5 choices
+5 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isDeterminism
},
requires: "not determinism",
effect: () => {
tech.isExtraChoice = true;
tech.addJunkTechToPool(5)
},
remove() {
tech.isExtraChoice = false;
if (this.count > 0) tech.removeJunkTechFromPool(5)
}
},
{
name: "determinism",
description: "spawn 5 tech, but you have no cancel
and 1 choice for tech, fields, and guns",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBadRandomOption: true,
allowed() {
return !tech.isExtraChoice && !tech.isCancelDuplication && !tech.isCancelRerolls
},
requires: "not emergence, not futures or commodities exchanges",
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 (tech.isDeterminism) {
tech.isDeterminism = false;
for (let i = 0; i < 5; i++) powerUps.removeRandomTech()
}
}
},
{
name: "superdeterminism",
description: "spawn 5 tech
research, guns, and fields no longer spawn",
maxCount: 1,
count: 0,
frequency: 8,
frequencyDefault: 8,
isBadRandomOption: true,
allowed() {
return tech.isDeterminism && !tech.isAnsatz && !tech.isGunSwitchField
},
requires: "determinism, not unified field theory, not ansatz",
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;
for (let i = 0; i < 5; i++) powerUps.removeRandomTech()
}
},
{
name: "dark patterns",
description: "reduce combat difficulty by 1 level
+31 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return level.onLevel < 8 && level.onLevel > 0
},
requires: "on levels 1 through 7",
effect() {
level.difficultyDecrease(simulation.difficultyMode)
// simulation.difficulty-=
simulation.makeTextLog(`level.difficultyDecrease(simulation.difficultyMode)`)
tech.addJunkTechToPool(31)
// for (let i = 0; i < tech.junk.length; i++) tech.tech.push(tech.junk[i])
},
remove() {
if (this.count > 0) {
tech.removeJunkTechFromPool(31)
level.difficultyIncrease(simulation.difficultyMode)
}
}
},
{
name: "ergodicity",
description: "reduce combat difficulty by 2 levels
heal power ups have no effect",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return level.onLevel > 1 && !tech.isEnergyHealth
},
requires: "past levels 1, not mass-energy",
effect() {
tech.isNoHeals = true;
level.difficultyDecrease(simulation.difficultyMode * 2)
simulation.makeTextLog(`level.difficultyDecrease(simulation.difficultyMode * 2)`)
powerUps.heal.color = "#abb"
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() {
if (tech.isNoHeals) {
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
}
}
tech.isNoHeals = false;
if (this.count > 0) level.difficultyIncrease(simulation.difficultyMode * 2)
}
},
//**************************************************
//************************************************** gun
//************************************************** tech
//**************************************************
{
name: "CPT gun",
description: `adds the CPT gun to your inventory
it rewinds your health, velocity, and position`,
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (b.totalBots() > 3 || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isEnergyHealth && !tech.isRewindAvoidDeath //build.isExperimentSelection ||
},
requires: "bots > 3, plasma torch, nano-scale, pilot wave, not mass-energy equivalence, CPT",
effect() {
tech.isRewindGun = true
b.guns.push(b.gunRewind)
b.giveGuns("CPT gun");
},
remove() {
if (tech.isRewindGun) {
b.removeGun("CPT gun", true)
// for (let i = 0; i < b.guns.length; i++) {
// if (b.guns[i].name === "CPT gun") {
// b.guns[i].have = false
// for (let j = 0; j < b.inventory.length; j++) {
// if (b.inventory[j] === i) {
// b.inventory.splice(j, 1)
// break
// }
// }
// if (b.inventory.length) {
// b.activeGun = b.inventory[0];
// } else {
// b.activeGun = null;
// }
// simulation.makeGunHUD();
// b.guns.splice(i, 1) //also remove CPT gun from gun pool array
// break
// }
// }
tech.isRewindGun = false
}
}
},
{
name: "needle gun",
description: "nail gun fires 3 mob piercing needles
requires 3 times more ammo",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isIceCrystals && !tech.isRivets
},
requires: "nail gun, not ice crystal, rivets, or pneumatic actuator",
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
}
}
},
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: "ceramic needles",
description: `needles pierce shields
directly damaging shielded mobs`,
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.isNeedles || tech.isNeedleShot) && !tech.isNailRadiation
},
requires: "needle gun, needle-shot, not irradiated nails",
effect() {
tech.isNeedleShieldPierce = true
},
remove() {
tech.isNeedleShieldPierce = false
}
},
{
name: "rivet gun",
description: "nail gun slowly fires a heavy rivet",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isIceCrystals && !tech.isNeedles
},
requires: "nail gun, 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
}
}
},
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
}
}
}
}
},
{
name: "rivet diameter",
description: `rivets are 20% larger
increases mass and physical damage`,
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isRivets
},
requires: "rivet gun",
effect() {
tech.rivetSize += 0.2
},
remove() {
tech.rivetSize = 1;
}
},
{
name: "ice crystal nucleation",
description: "the 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;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") {
b.guns[i].ammoPack = Infinity
b.guns[i].recordedAmmo = b.guns[i].ammo
b.guns[i].ammo = Infinity
simulation.updateGunHUD();
break;
}
}
},
remove() {
if (tech.isIceCrystals) {
tech.isIceCrystals = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") {
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
if (b.guns[i].recordedAmmo) b.guns[i].ammo = b.guns[i].recordedAmmo
simulation.updateGunHUD();
break;
}
}
}
}
},
{
name: "pneumatic actuator",
description: "nail gun takes no time to ramp up
to it's shortest delay after firing",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles
},
requires: "nail gun, not 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()
}
},
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: "powder-actuated",
// description: "nail gun takes no time to ramp up
nails have a 30% faster muzzle speed",
// isGunTech: true,
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return tech.haveGunCheck("nail gun") && tech.nailFireRate && !tech.isIceCrystals
// },
// requires: "nail gun and pneumatic actuator not ice crystal nucleation",
// 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()
// }
// },
// 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: "supercritical fission",
description: "nails, needles, and rivets can explode
if they strike mobs near their center",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.isNailShot || tech.isNeedleShot || tech.nailBotCount > 1 || tech.haveGunCheck("nail gun"))
},
requires: "nails",
effect() {
tech.isNailCrit = true
},
remove() {
tech.isNailCrit = false
}
},
{
name: "irradiated nails",
description: "nails, needles, and rivets are radioactive
about 90% more damage over 2 seconds",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isMineDrop + tech.nailBotCount + tech.fragments + tech.nailsDeathMob / 2 + ((tech.haveGunCheck("mine") && !tech.isLaserMine) + (tech.haveGunCheck("nail gun") && !tech.isNeedleShieldPierce) + tech.isNeedleShot + tech.isNailShot) * 2 > 1
},
requires: "nails, rivets, not ceramic needles",
effect() {
tech.isNailRadiation = true;
},
remove() {
tech.isNailRadiation = false;
}
},
{
name: "4s half-life",
description: "nails are made of plutonium-238
increase damage by 100% over 6 seconds",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNailRadiation && !tech.isFastRadiation
},
requires: "irradiated nails, not 1/2s half-life",
effect() {
tech.isSlowRadiation = true;
},
remove() {
tech.isSlowRadiation = false;
}
},
{
name: "1/2s half-life",
description: "nails are made of lithium-8
damage occurs after 1/2 a second",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNailRadiation && !tech.isSlowRadiation
},
requires: "irradiated nails, not 4s half-life",
effect() {
tech.isFastRadiation = true;
},
remove() {
tech.isFastRadiation = false;
}
},
{
name: "shotgun spin-statistics",
description: "immune to harm while firing the shotgun
shotgun ammo gives 50% less 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();
},
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;
}
}
}
}
},
{
name: "Newton's 3rd law",
description: "shotgun recoil is increased
decrease shotgun delay after firing by 66%",
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",
description: "increase shotgun and rail gun damage 60%
their recoil is increased and reversed",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("shotgun") || tech.haveGunCheck("rail gun")) && !tech.isShotgunRecoil
},
requires: "shotgun or rail gun, not Newton's 3rd law",
effect() {
tech.isShotgunReversed = true;
},
remove() {
tech.isShotgunReversed = false;
}
},
{
name: "shotgun slug",
description: "shotgun lobs 1 huge bullet",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not nail-shot, foam-shot, worm-shot, ice-shot",
effect() {
tech.isSlugShot = true;
},
remove() {
tech.isSlugShot = false;
}
},
{
name: "nail-shot",
description: "shotgun fires 17 nails",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isSlugShot && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, slug, foam-shot, worm-shot, ice-shot",
effect() {
tech.isNailShot = true;
},
remove() {
tech.isNailShot = false;
}
},
{
name: "needle-shot",
description: "shotgun propels 11 mob piercing needles",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isFoamShot && !tech.isWormShot && !tech.isIceShot
},
requires: "shotgun, not incendiary, nail-shot, slug, foam-shot, worm-shot, ice-shot",
effect() {
tech.isNeedleShot = true;
},
remove() {
tech.isNeedleShot = false;
}
},
{
name: "worm-shot",
description: "shotgun hatches 3-4 mob seeking worms
worms benefit from spore technology", //
worms seek out nearby mobs
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, nail-shot, slug, foam-shot, ice-shot",
effect() {
tech.isWormShot = true;
},
remove() {
tech.isWormShot = false;
}
},
{
name: "foam-shot",
description: "shotgun sprays 13 sticky foam bubbles",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isIceShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, nail-shot, slug, worm-shot, ice-shot",
effect() {
tech.isFoamShot = true;
},
remove() {
tech.isFoamShot = false;
}
},
{
name: "ice-shot",
description: "shotgun grows 18 freezing ice IX crystals",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, nail-shot, slug, foam-shot, worm-shot",
effect() {
tech.isIceShot = true;
},
remove() {
tech.isIceShot = false;
}
},
{
name: "super duper",
description: "fire 1 additional super ball",
isGunTech: true,
maxCount: 9,
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.superBallNumber++
},
remove() {
tech.superBallNumber = 3;
}
},
{
name: "supertemporal",
description: "fire super ball from the same point in space
but separated by 0.1 seconds in time",
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()
}
},
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 ball",
description: "fire just 1 large super ball
that stuns mobs for 3 second",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("super balls") && tech.superBallNumber === 3 && !tech.superBallDelay
},
requires: "super balls, but not super duper or supertemporal",
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()
}
},
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: "super sized",
description: `super balls are 20% larger
increases mass and physical damage`,
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("super balls")
},
requires: "super balls",
effect() {
tech.bulletSize += 0.15
},
remove() {
tech.bulletSize = 1;
}
},
{
name: "phase velocity",
description: "wave beam propagates faster through solids
up by 3000% in the map and 760% in blocks",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("wave beam") && !tech.isLongitudinal
},
requires: "wave beam, not phonon",
effect() {
tech.isPhaseVelocity = true;
},
remove() {
tech.isPhaseVelocity = false;
}
},
{
name: "bound state",
description: "wave packets reflect backwards 2 times
range is reduced by 25%",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("wave beam")
},
requires: "wave beam",
effect() {
tech.waveReflections += 2
},
remove() {
tech.waveReflections = 1
}
},
{
name: "amplitude",
description: "wave packet amplitude is 33% higher
wave damage is increased by 50%",
isGunTech: true,
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("wave beam")
},
requires: "wave beam",
effect() {
tech.waveFrequency *= 0.66
tech.wavePacketDamage *= 1.5
},
remove() {
tech.waveFrequency = 0.2
tech.wavePacketDamage = 1
}
},
{
name: "propagation",
description: "wave packet propagation speed is 20% slower
wave damage is increased by 50%",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("wave beam")
},
requires: "wave beam",
effect() {
tech.waveBeamSpeed *= 0.8;
tech.waveBeamDamage += 1.5 * 0.5 //this sets base wave beam damage, not used by arcs or circles
},
remove() {
tech.waveBeamSpeed = 10;
tech.waveBeamDamage = 1.5 //this sets base wave beam damage, not used by arcs or circles
}
},
{
name: "phonon", //longitudinal //gravitational wave?
description: "wave beam emits low frequency, high damage
expanding arcs that propagate through solids",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.haveGunCheck("wave beam") && !tech.isPhaseVelocity
},
requires: "wave beam, not phase velocity ",
effect() {
tech.isLongitudinal = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "wave beam") {
b.guns[i].chooseFireMethod()
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack / 8
b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 8);
simulation.updateGunHUD();
break
}
}
},
remove() {
if (tech.isLongitudinal) {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "wave beam") {
tech.isLongitudinal = false;
b.guns[i].chooseFireMethod()
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 8);
simulation.updateGunHUD();
break
}
}
}
tech.isLongitudinal = false;
}
},
{
name: "isotropic radiator",
description: "wave beam expands in all directions
range reduced 40% and damage increased 50%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isLongitudinal
},
requires: "phonon",
effect() {
tech.is360Longitudinal = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "wave beam") {
b.guns[i].chooseFireMethod()
break
}
}
},
remove() {
tech.is360Longitudinal = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "wave beam") {
b.guns[i].chooseFireMethod()
break
}
}
}
},
{
name: "cruise missile",
description: "missiles travel 63% slower,
but have a 50% larger explosive payload",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("missiles") || tech.isMissileField || tech.missileBotCount
},
requires: "missiles",
effect() {
tech.missileSize = true
},
remove() {
tech.missileSize = false
}
},
{
name: "MIRV",
description: "missile gun and bot launch +1 missile
decrease size and fire rate by 10%",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("missiles") || tech.missileBotCount
},
requires: "missiles",
effect() {
tech.missileCount++;
},
remove() {
tech.missileCount = 1;
}
},
{
name: "missile-bot",
description: "remove your missile gun
gain a bot that fires missiles at mobs",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
isBot: true,
isBotTech: true,
allowed() {
return tech.haveGunCheck("missiles")
},
requires: "missiles",
effect() {
tech.missileBotCount++;
b.missileBot();
if (tech.haveGunCheck("missiles")) b.removeGun("missiles") //remove your last gun
},
remove() {
if (this.count) {
tech.missileBotCount = 0;
b.clearPermanentBots();
b.respawnBots();
if (!tech.haveGunCheck("missiles")) b.giveGuns("missiles")
}
}
},
{
name: "rocket-propelled grenade",
description: "grenades rapidly accelerate forward
map collisions trigger an explosion",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades")
},
requires: "grenades",
effect() {
tech.isRPG = true;
b.setGrenadeMode()
},
remove() {
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
},
requires: "grenades, not neutron bomb",
effect() {
tech.isVacuumBomb = true;
b.setGrenadeMode()
},
remove() {
tech.isVacuumBomb = false;
b.setGrenadeMode()
}
},
{
name: "chain reaction",
description: "increase grenade radius and damage 33%
blocks caught in explosions also explode",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.isVacuumBomb && !tech.isExplodeRadio
},
requires: "vacuum bomb && not iridium-192",
effect() {
tech.isBlockExplode = true; //chain reaction
},
remove() {
tech.isBlockExplode = false;
}
},
{
name: "neutron bomb",
description: "grenades are irradiated with Cf-252
does damage, harm, and drains energy",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb
},
requires: "grenades, not fragmentation, vacuum bomb",
effect() {
tech.isNeutronBomb = true;
b.setGrenadeMode()
},
remove() {
tech.isNeutronBomb = false;
b.setGrenadeMode()
}
},
{
name: "vacuum permittivity",
description: "increase radioactive range by 20%
objects in range of the bomb are slowed",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNeutronBomb
},
requires: "neutron bomb",
effect() {
tech.isNeutronSlow = true
},
remove() {
tech.isNeutronSlow = false
}
},
{
name: "laser-mines",
description: "mines hover in place until mobs get in range
mines use energy to emit 3 unaimed lasers",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("mine") || tech.isMineDrop) && !tech.isMineSentry
},
requires: "mines, not sentry",
effect() {
tech.isLaserMine = true;
},
remove() {
tech.isLaserMine = false;
}
},
{
name: "mine reclamation",
description: "retrieve ammo from all undetonated mines
and 20% of mines after detonation",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("mine") && !tech.isMineSentry
},
requires: "mine, not sentry",
effect() {
tech.isMineAmmoBack = true;
},
remove() {
tech.isMineAmmoBack = false;
}
},
{
name: "sentry",
description: "mines target mobs with nails over time
mines last about 14 seconds",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("mine") || tech.isMineDrop) && !tech.isMineAmmoBack && !tech.isLaserMine
},
requires: "mines, not mine reclamation, laser-mines",
effect() {
tech.isMineSentry = true;
},
remove() {
tech.isMineSentry = false;
}
},
{
name: "booby trap",
description: "drop a mine after picking up a power up
+23 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isMineSentry === true || tech.isLaserMine === true || tech.isMineAmmoBack === true
},
requires: "some mine tech",
effect() {
tech.isMineDrop = true;
if (tech.isMineDrop) b.mine(m.pos, { x: 0, y: 0 }, 0, tech.isMineAmmoBack)
tech.addJunkTechToPool(23)
},
remove() {
tech.isMineDrop = false;
if (this.count > 0) tech.removeJunkTechFromPool(13)
}
},
{
name: "mycelial fragmentation",
description: "sporangium release 6 extra spores
during their growth phase",
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: "tinsellated flagella",
description: "sporangium release 2 more spores
spores accelerate 40% faster",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField
},
requires: "spores",
effect() {
tech.isFastSpores = true
},
remove() {
tech.isFastSpores = false
}
},
{
name: "cryodesiccation",
description: "sporangium release 2 more spores
spores freeze mobs for 1.5 second",
//
spores do 1/3 damage
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormShot
},
requires: "spores or worms",
effect() {
tech.isSporeFreeze = true
},
remove() {
tech.isSporeFreeze = false
}
},
{
name: "diplochory",
description: "spores use you for dispersal
until they locate a viable host",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormShot
},
requires: "spores or worms",
effect() {
tech.isSporeFollow = true
},
remove() {
tech.isSporeFollow = false
}
},
{
name: "mutualism",
description: "increase spore damage by 150%
spores 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 || tech.isSporeField) && !tech.isEnergyHealth || tech.isWormShot
},
requires: "spores, worms, not mass-energy",
effect() {
tech.isMutualism = true
},
remove() {
tech.isMutualism = false
}
},
{
name: "nematodes",
description: "spores develop into 1/2 as many worms
worms do 250% more damage",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormholeSpores
},
requires: "spores",
effect() {
tech.isSporeWorm = true
},
remove() {
tech.isSporeWorm = false
}
},
{
name: "necrophage",
description: "if worms kill their target
they reset their lifespan",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isSporeWorm || tech.isWormShot
},
requires: "worms",
effect() {
tech.wormSurviveDmg = true
},
remove() {
tech.wormSurviveDmg = false
}
},
{
name: "reduced tolerances",
description: "increase drone ammo/efficiency by 66%
reduce the average drone lifetime by 40%",
isGunTech: true,
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isDroneRadioactive && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)))
},
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.isExtraMaxEnergy && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)))
},
requires: "drones, not inductive coupling",
effect() {
tech.isDroneGrab = true
},
remove() {
tech.isDroneGrab = false
}
},
{
name: "drone repair",
description: "broken drones repair if the drone gun is active
repairing has a 25% chance to use 1 ammo",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("drones")
},
requires: "drone gun",
effect() {
tech.isDroneRespawn = true
},
remove() {
tech.isDroneRespawn = false
}
},
{
name: "torque bursts",
description: "drones rapidly rush towards their target
increase drone collision damage by 33%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return tech.haveGunCheck("drones") && !tech.isDroneRadioactive && !tech.isIncendiary
},
requires: "drone gun, not irradiated drones, incendiary",
effect() {
tech.isDroneTeleport = true
},
remove() {
tech.isDroneTeleport = false
}
},
{
name: "brushless motor",
description: "drones can rush 66% more often
increase drone collision damage by 44%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isDroneTeleport
},
requires: "torque bursts",
effect() {
tech.isDroneFastLook = true
},
remove() {
tech.isDroneFastLook = false
}
},
{
name: "irradiated drones",
description: "the space around drones is irradiated
reduce ammo/efficiency by 75%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.droneCycleReduction === 1 && !tech.isIncendiary && !tech.isDroneTeleport && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)))
},
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)
}
}
},
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
}
}
}
}
},
{
name: "beta radiation", //"control rod ejection",
description: "reduce the average drone lifetime by 50%
increase radiation damage by 100%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isDroneRadioactive
},
requires: "irradiated drones",
effect() {
tech.droneRadioDamage = 2
},
remove() {
tech.droneRadioDamage = 1
}
},
{
name: "orthocyclic winding",
description: "drones accelerate 66% faster
increase radiation damage by 33%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isDroneRadioactive
},
requires: "irradiated drones",
effect() {
tech.isFastDrones = true
},
remove() {
tech.isFastDrones = false
}
},
{
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.isFoamTeleport && (tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot)
},
requires: "foam, not uncertainty",
effect() {
tech.isFoamAttract = true
},
remove() {
tech.isFoamAttract = false
}
},
{
name: "uncertainty principle",
description: "foam bubbles randomly change position
increase foam damage per second by 60%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot)
},
requires: "foam, not electrostatic induction",
effect() {
tech.isFoamTeleport = true
},
remove() {
tech.isFoamTeleport = false;
}
},
{
name: "necrophoresis",
description: "foam bubbles grow and split into 3 copies
when the mob they are stuck to dies",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot
},
requires: "foam",
effect() {
tech.isFoamGrowOnDeath = true
},
remove() {
tech.isFoamGrowOnDeath = false;
}
},
{
name: "aerogel",
description: "foam bubbles float and dissipate 50% faster
increase foam damage per second by 300%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot
},
requires: "foam",
effect() {
tech.isFastFoam = true
tech.foamGravity = -0.0003
},
remove() {
tech.isFastFoam = false;
tech.foamGravity = 0.00008
}
},
{
name: "quantum foam",
description: "foam gun fires 0.25 seconds into the future
increase foam gun damage by 70%",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam")
},
requires: "foam gun",
effect() {
tech.foamFutureFire++
},
remove() {
tech.foamFutureFire = 0;
}
},
{
name: "foam fractionation",
description: "foam gun bubbles are 100% larger
when you have below 300 ammo",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam")
},
requires: "foam gun",
effect() {
tech.isAmmoFoamSize = true
},
remove() {
tech.isAmmoFoamSize = false;
}
},
{
name: "half-wave rectifier",
description: "charging the rail gun gives you energy
instead of draining it",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("rail gun")
},
requires: "rail gun",
effect() {
tech.isRailEnergyGain = true;
},
remove() {
tech.isRailEnergyGain = false;
}
},
{
name: "dielectric polarization",
description: "firing the rail gun damages nearby mobs",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("rail gun")
},
requires: "rail gun",
effect() {
tech.isRailAreaDamage = true;
},
remove() {
tech.isRailAreaDamage = false;
}
},
{
name: "capacitor bank",
description: "the rail gun no longer takes time to charge
rail gun rods are 66% less massive",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("rail gun")
},
requires: "rail gun",
effect() {
tech.isCapacitor = true;
},
remove() {
tech.isCapacitor = false;
}
},
{
name: "laser diode",
description: "all lasers drain 30% less energy
affects laser-gun, laser-bot, and laser-mines",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("laser") || tech.laserBotCount > 1 || tech.isLaserMine) && tech.laserDamage === 0.15
},
requires: "laser, not free-electron",
effect() {
tech.isLaserDiode = 0.70; //100%-37%
tech.laserColor = "rgb(0, 11, 255)"
tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
},
remove() {
tech.isLaserDiode = 1;
tech.laserColor = "#f02"
tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
}
},
{
name: "free-electron laser",
description: "increase all laser damage by 200%
increase all laser energy drain by 250%",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.laserBotCount > 1) && !tech.isPulseLaser && tech.isLaserDiode === 1
},
requires: "laser, not pulse, diodes",
effect() {
tech.laserFieldDrain = 0.007 //base is 0.002
tech.laserDamage = 0.45; //base is 0.15
tech.laserColor = "#83f"
tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
},
remove() {
tech.laserFieldDrain = 0.002;
tech.laserDamage = 0.15; //used in check on pulse: tech.laserDamage === 0.15
tech.laserColor = "#f00"
tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
}
},
{
name: "relativistic momentum",
description: "all lasers push mobs away
affects laser-gun, laser-bot, and laser-mines",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.laserBotCount > 1
},
requires: "laser, not pulse",
effect() {
tech.isLaserPush = true;
},
remove() {
tech.isLaserPush = false;
}
},
{
name: "specular reflection",
description: "+2 reflection for all lasers
affects laser-gun, laser-bot, and laser-mines",
isGunTech: true,
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.laserBotCount > 1) && !tech.isWideLaser && !tech.isPulseLaser && !tech.historyLaser
},
requires: "laser, not wide beam, diffuse beam, pulse, or slow light",
effect() {
tech.laserReflections += 2;
},
remove() {
tech.laserReflections = 2;
}
},
{
name: "diffraction grating",
description: `laser gains a diverging beam`,
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.isPulseAim && !tech.historyLaser
},
requires: "laser gun, not neocognitron, diffuse beam, or slow light",
effect() {
tech.beamSplitter++
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
},
remove() {
if (tech.beamSplitter !== 0) {
tech.beamSplitter = 0
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
}
}
},
{
name: "diffuse beam",
description: "laser beam is wider and doesn't reflect
increase full beam damage by 200%",
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;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
},
remove() {
if (tech.isWideLaser) {
// tech.wideLaser = 0
tech.isWideLaser = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
}
}
},
{
name: "output coupler",
description: "widen diffuse laser beam by 40%
increase full beam damage by 40%",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isWideLaser
},
requires: "diffuse beam",
effect() {
tech.wideLaser += 2
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
},
remove() {
if (tech.isWideLaser) {
tech.wideLaser = 3
} else {
tech.wideLaser = 0
}
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
}
},
{
name: "slow light",
description: "laser beam is spread into your recent past
increase total beam damage by 300%",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
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++
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
},
remove() {
// this.description = "laser beam is spread into your recent past
increase total beam damage by 300%"
if (tech.historyLaser) {
tech.historyLaser = 0
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
}
}
},
{
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.laserDamage === 0.15
},
requires: "laser gun, not specular reflection, diffuse, free-electron laser",
effect() {
tech.isPulseLaser = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
},
remove() {
if (tech.isPulseLaser) {
tech.isPulseLaser = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
}
}
}
},
{
name: "neocognitron",
description: "pulse automatically aims at a nearby mob",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isPulseLaser && !tech.beamSplitter
},
requires: "pulse, not diffraction grating",
effect() {
tech.isPulseAim = true;
},
remove() {
tech.isPulseAim = false;
}
},
//**************************************************
//************************************************** field
//************************************************** tech
//**************************************************
{
name: "zero point energy",
description: "use 2 research to
increase your maximum energy by 74",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && (build.isExperimentSelection || powerUps.research.count > 1)
},
requires: "standing wave harmonics or pilot wave",
effect() {
tech.harmonicEnergy = 0.74
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: "standing wave oscillates in a 3rd dimension
increasing deflecting efficiency by 40%",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics"
},
requires: "standing wave harmonics",
effect() {
tech.harmonics++
m.fieldShieldingScale = 1.3 * Math.pow(0.6, (tech.harmonics - 2))
m.harmonicShield = m.harmonicAtomic
},
remove() {
tech.harmonics = 2
m.fieldShieldingScale = 1.3 * Math.pow(0.6, (tech.harmonics - 2))
m.harmonicShield = m.harmonic3Phase
}
},
{
name: "expansion",
description: "using standing wave field uses energy
to temporarily expand its radius",
// description: "use energy to expand standing wave
the 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 harmonics"
},
requires: "standing wave harmonics",
effect() {
tech.isStandingWaveExpand = true
},
remove() {
tech.isStandingWaveExpand = false
m.harmonicRadius = 1
}
},
{
name: "bremsstrahlung",
description: "deflecting does damage to mobs",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
},
requires: "standing wave harmonics, perfect diamagnetism",
effect() {
tech.blockDmg += 1.25 //if you change this value also update the for loop in the electricity graphics in m.pushMass
},
remove() {
tech.blockDmg = 0;
}
},
{
name: "triple point",
description: "the pressure from deflecting is used
to condense ice IX crystals",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
},
requires: "standing wave harmonics, perfect diamagnetism",
effect() {
tech.blockingIce++
},
remove() {
tech.blockingIce = 0;
}
},
{
name: "flux pinning",
description: "deflecting mobs with your field
stuns them for 2 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 harmonics" || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing"
},
requires: "a field that can block",
effect() {
tech.isStunField += 120;
},
remove() {
tech.isStunField = 0;
}
},
{
name: "eddy current brake",
description: "project a field that limits the top speed of mobs
field 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: "Lenz's law",
description: "after deactivation perfect diamagnetism
maintains at the location you left it",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism"
},
requires: "perfect diamagnetism",
effect() {
tech.isFieldFree = true;
},
remove() {
tech.isFieldFree = false;
}
},
{
name: "tessellation",
description: "use 4 research
reduce harm by 50%",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "negative mass field") && (build.isExperimentSelection || powerUps.research.count > 3)
},
requires: "perfect diamagnetism or negative mass field",
effect() {
tech.isFieldHarmReduction = true
for (let i = 0; i < 4; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.isFieldHarmReduction = false
if (this.count > 0) powerUps.research.changeRerolls(4)
}
},
{
name: "degenerate matter",
description: "reduce harm by 60% while your field is active",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass field") && !tech.isEnergyHealth
},
requires: "field: perfect, negative mass, pilot wave, plasma, not mass-energy",
effect() {
tech.isHarmReduce = true
},
remove() {
tech.isHarmReduce = false;
}
},
{
name: "annihilation",
description: "touching normal mobs annihilates them
but drains 33% of your maximum energy",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "negative mass field"
},
requires: "negative mass field",
effect() {
tech.isAnnihilation = true
},
remove() {
tech.isAnnihilation = false;
}
},
{
name: "inertial mass",
description: "negative mass field is larger and faster
blocks 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 field"
},
requires: "negative mass field",
effect() {
tech.isFlyFaster = true
},
remove() {
tech.isFlyFaster = false;
}
},
{
name: "Bose Einstein condensate",
description: "mobs inside your field are frozen
pilot 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 field" || m.fieldUpgrades[m.fieldMode].name === "time dilation"
},
requires: "pilot wave, negative mass field, time dilation",
effect() {
tech.isFreezeMobs = true
},
remove() {
tech.isFreezeMobs = false
}
},
{
name: "bot manufacturing",
description: "use nano-scale manufacturing and 2 research
to build 3 random bots",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
isNonRefundable: true,
// isExperimentHide: true,
allowed() {
return powerUps.research.count > 1 && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing"
},
requires: "nano-scale manufacturing",
effect: () => {
for (let i = 0; i < 2; 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 nano-scale and 3 research to build
2 random bots and upgrade all bots to that type",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
isNonRefundable: true,
// isExperimentHide: true,
allowed() {
return powerUps.research.count > 2 && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing"
},
requires: "nano-scale manufacturing",
effect: () => {
for (let i = 0; i < 3; 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 nano-scale
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",
description: "use 3 research to repurpose nano-scale
excess energy used to grow spores",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (build.isExperimentSelection || powerUps.research.count > 2) && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
},
requires: "nano-scale manufacturing, no other manufacturing, no drone tech",
effect() {
if (!build.isExperimentSelection) {
for (let i = 0; i < 3; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
}
tech.isSporeField = true;
},
remove() {
tech.isSporeField = false;
if (this.count > 0) powerUps.research.changeRerolls(3)
}
},
{
name: "missile manufacturing",
description: "use 3 research to repurpose nano-scale
excess energy used to construct missiles",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (build.isExperimentSelection || powerUps.research.count > 2) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
},
requires: "nano-scale manufacturing, no other manufacturing, no drone tech",
effect() {
if (!build.isExperimentSelection) {
for (let i = 0; i < 3; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
}
tech.isMissileField = true;
},
remove() {
tech.isMissileField = false;
if (this.count > 0) powerUps.research.changeRerolls(3)
}
},
{
name: "ice IX manufacturing",
description: "use 3 research to repurpose nano-scale
excess energy used to condense ice IX",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (build.isExperimentSelection || powerUps.research.count > 2) && m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
},
requires: "nano-scale manufacturing, no other manufacturing, no drone tech",
effect() {
if (!build.isExperimentSelection) {
for (let i = 0; i < 3; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
}
tech.isIceField = true;
},
remove() {
tech.isIceField = false;
if (this.count > 0) powerUps.research.changeRerolls(3)
}
},
{
name: "pair production",
description: "picking up a power up gives you 200 energy",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
requires: "nano-scale manufacturing or pilot wave",
effect: () => {
tech.isMassEnergy = true // used in m.grabPowerUp
m.energy += 2
},
remove() {
tech.isMassEnergy = false;
}
},
// {
// name: "thermal reservoir",
// description: "increase your plasma damage by 100%
plasma temporarily lowers health not energy",
// isFieldTech: true,
// maxCount: 1,
// count: 0,
// frequency: 2,
// allowed() {
// return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isEnergyHealth
// },
// requires: "plasma torch, not mass-energy equivalence",
// effect() {
// tech.isPlasmaRange += 0.27;
// },
// remove() {
// tech.isPlasmaRange = 1;
// }
// },
{
name: "plasma-bot",
description: "use 1 research to build 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" && (build.isExperimentSelection || powerUps.research.count > 0)
},
requires: "plasma torch",
effect() {
tech.plasmaBotCount++;
b.plasmaBot();
for (let i = 0; i < 1; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.plasmaBotCount = 0;
b.clearPermanentBots();
b.respawnBots();
if (this.count > 0) powerUps.research.changeRerolls(1)
}
},
{
name: "plasma jet",
description: "increase plasma torch's range by 30%",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isExtruder
},
requires: "plasma torch, not micro-extruder",
effect() {
tech.isPlasmaRange += 0.3;
},
remove() {
tech.isPlasmaRange = 1;
}
},
{
name: "tokamak",
description: "throwing a block converts it into energy
and a pulsed fusion explosion",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "plasma torch"
},
requires: "plasma torch",
effect() {
tech.isTokamak = true;
},
remove() {
tech.isTokamak = false;
}
},
{
name: "micro-extruder",
description: "plasma torch extrudes a thin hot wire
increases damage, energy drain, and lag",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isPlasmaRange === 1
},
requires: "plasma torch, not plasma jet",
effect() {
tech.isExtruder = true;
},
remove() {
tech.isExtruder = false;
}
},
{
name: "timelike world line",
description: "time dilation doubles your relative time rate
and makes you immune to harm",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "time dilation"
},
requires: "time dilation",
effect() {
tech.isTimeSkip = true;
b.setFireCD();
},
remove() {
tech.isTimeSkip = false;
b.setFireCD();
}
},
{
name: "Lorentz transformation",
description: "use 3 research to increase your time rate
move, jump, and shoot 50% faster",
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: "quadruple your default energy regeneration",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "time dilation") && tech.energyRegen !== 0
},
requires: "time dilation, not ground state",
effect: () => {
tech.energyRegen = 0.004;
m.fieldRegen = tech.energyRegen;
},
remove() {
tech.energyRegen = 0.001;
m.fieldRegen = tech.energyRegen;
}
},
{
name: "boson composite",
description: "intangible to blocks and mobs while cloaked
passing through mobs drains your 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() {
tech.isIntangible = false;
}
},
{
name: "dazzler",
description: "decloaking stuns nearby mobs
drains 25% of your stored 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 300% to 600%",
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 = 7
},
remove() {
tech.sneakAttackDmg = 4
}
},
{
name: "dynamical systems",
description: "use 1 research
increase your damage by 35%",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && (build.isExperimentSelection || powerUps.research.count > 0)
},
requires: "metamaterial cloaking or pilot wave",
effect() {
tech.isCloakingDamage = true
for (let i = 0; i < 1; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.isCloakingDamage = false
if (this.count > 0) powerUps.research.changeRerolls(1)
}
},
{
name: "discrete optimization",
description: "increase damage by 50%
50% increased delay after firing",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
requires: "metamaterial cloaking or pilot wave",
effect() {
tech.aimDamage = 1.5
b.setFireCD();
},
remove() {
tech.aimDamage = 1
b.setFireCD();
}
},
{
name: "potential well",
description: "the force that pilot wave generates
to trap blocks is greatly increased",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
requires: "pilot wave",
effect() {
tech.pilotForce = 0.0006
},
remove() {
tech.pilotForce = 0.00002
}
},
{
name: "WIMPs",
description: "at the end of each level spawn 3-9 research
and a harmful particle that slowly chases you",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "wormhole"
},
requires: "wormhole",
effect: () => {
tech.wimpCount++
spawn.WIMP()
for (let j = 0, len = 1 + 5 * Math.random(); 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: "cosmic string",
description: "stun and do radioactive damage to mobs
if you tunnel through them with a wormhole",
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: "virtual particles",
description: "use 3 research to exploit your wormhole for a
17% chance to duplicate spawned power ups",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "wormhole" && (build.isExperimentSelection || powerUps.research.count > 2) && tech.duplicationChance() < 1
},
requires: "wormhole,below 100% duplication chance",
effect() {
tech.wormDuplicate = 0.17
powerUps.setDo(); //needed after adjusting duplication chance
for (let i = 0; i < 3; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.wormDuplicate = 0
powerUps.setDo(); //needed after adjusting duplication chance
if (this.count > 0) powerUps.research.changeRerolls(3)
}
},
{
name: "Penrose process",
description: "after a block falls into a wormhole
you gain 63 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 spores",
description: "when blocks fall into a wormhole
higher dimension spores are summoned",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "wormhole"
},
requires: "wormhole",
effect() {
tech.isWormholeSpores = true
},
remove() {
tech.isWormholeSpores = false
}
},
{
name: "traversable geodesics",
description: "your projectiles can traverse wormholes
spawn 2 guns and ammo",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "wormhole"
},
requires: "wormhole",
effect() {
tech.isWormBullets = true
for (let i = 0; i < 2; i++) {
powerUps.spawn(m.pos.x, m.pos.y, "gun");
powerUps.spawn(m.pos.x, m.pos.y, "ammo");
}
},
remove() {
if (tech.isWormBullets) {
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.isWormBullets = 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 field"
},
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
}
},
{
name: "-WIMP-",
description: "experiment: harmful particles slowly chase you",
maxCount: 1,
count: 0,
frequency: 0,
isBadRandomOption: true,
isExperimentalMode: true,
allowed() {
return build.isExperimentSelection
},
requires: "",
effect() {
tech.wimpExperiment = 3
},
remove() {
tech.wimpExperiment = 0
}
},
//**************************************************
//************************************************** JUNK
//************************************************** tech
//**************************************************
// {
// name: "junk",
// description: "",
// maxCount: 9,
// count: 0,
// frequency: 0,
// isNonRefundable: true,
// isExperimentHide: true,
// isJunk: true,
// allowed() {
// return true
// },
// requires: "",
// effect() {
// },
// remove() {}
// },
{
name: "emergency broadcasting",
description: "emit 2 sound sine waveforms at 853 Hz and 960 Hz
lower your volume",
maxCount: 1,
count: 0,
frequency: 0,
isExperimentHide: true,
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)();
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 = 853; // 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 = 960; // value in hertz
oscillator2.start();
return audioCtx
}
let sound = EBS()
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.resume()
setTimeout(() => {
sound.suspend()
powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
sound.resume()
setTimeout(() => {
sound.suspend()
powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
sound.resume()
setTimeout(() => {
sound.suspend()
powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
setTimeout(() => {
sound.resume()
setTimeout(() => {
sound.suspend()
powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
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);
}, delay);
}, delay);
}, delay);
}, delay);
}, delay);
}, delay);
}, delay);
}, delay);
}, delay);
}, delay);
},
remove() {}
},
{
name: "automatic",
description: "you can't fire when moving
always fire when at rest",
maxCount: 1,
count: 0,
frequency: 0,
isExperimentHide: true,
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();
}
}
},
{
name: "hidden variable",
description: "spawn 15 heal power ups
but hide your health bar",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return !tech.isEnergyHealth
},
requires: "not mass-energy",
effect() {
document.getElementById("health").style.display = "none"
document.getElementById("health-bg").style.display = "none"
for (let i = 0; i < 15; 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 5 seconds",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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
}, 5000);
// for (;;) {} //freezes the tab
},
remove() {}
},
{
name: "posture",
description: "stand a bit taller",
maxCount: 1,
count: 0,
frequency: 0,
isExperimentHide: true,
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,
isExperimentHide: true,
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: "spinor",
description: "the direction you aim is determined by your position",
maxCount: 1,
count: 0,
frequency: 0,
isExperimentHide: true,
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: "decomposers",
description: "after they die mobs leave behind spawns",
maxCount: 1,
count: 0,
frequency: 0,
isExperimentHide: true,
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,
isExperimentHide: true,
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,
isExperimentHide: true,
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 gun
remove your active gun",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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 frequency
of one random tech by 100",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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,
isExperimentHide: 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: "transparency",
description: "become invisible to yourself
mobs can still see you",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
m.draw = () => {}
},
remove() {}
},
{
name: "quantum leap",
description: "become an alternate version of yourself
every 20 seconds",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
setInterval(() => {
m.switchWorlds()
simulation.trails()
}, 20000); //every 30 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,
isExperimentHide: 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,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
window.open('https://www.youtube.com/results?search_query=music', '_blank')
},
remove() {}
},
{
name: "performance",
description: "display performance stats to n-gon",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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"
},
remove() {}
},
{
name: "repartitioning",
description: "set the frequency of finding normal tech to 0
spawn 5 tech",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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 JUNK tech to zero",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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: "ship",
description: "fly around with no legs
reduce combat difficulty by 1 level",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return !m.isShipMode && m.fieldUpgrades[m.fieldMode].name !== "negative mass field"
},
requires: "",
effect() {
m.shipMode()
level.difficultyDecrease(simulation.difficultyMode)
},
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,
isExperimentHide: 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,
isExperimentHide: 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,
isExperimentHide: true,
isJunk: true,
allowed() {
return m.fieldUpgrades[m.fieldMode].name !== "negative mass field"
},
requires: "",
effect() {
ctx.globalCompositeOperation = "lighter";
},
remove() {}
},
{
name: "rewind",
description: "every 5 seconds rewind 2 seconds
lasts 120 seconds",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 24; i++) {
setTimeout(() => { m.rewind(120) }, i * 5000);
}
},
remove() {}
},
{
name: "energy to mass conversion",
description: "convert your energy into blocks",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
level.nextLevel();
},
remove() {}
},
{
name: "expert system",
description: "spawn a tech power up
+64 JUNK to the potential tech pool",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
powerUps.spawn(m.pos.x, m.pos.y, "tech");
tech.addJunkTechToPool(64)
},
remove() {}
},
{
name: "energy investment",
description: "every 10 seconds drain your energy
return it doubled 10 seconds later
lasts 180 seconds",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 18; i++) {
setTimeout(() => { //drain energy
const energy = m.energy
m.energy = 0
setTimeout(() => { //return energy
m.energy += 2 * energy
}, 5000);
}, i * 10000);
}
},
remove() {}
},
{
name: "missile Launching System",
description: "fire missiles for the next 60 seconds",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 60; 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 grenades for the next 120 seconds",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 120; i++) {
setTimeout(() => {
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
});
}, i * 1000);
}
},
remove() {}
},
// {
// name: "inverted input",
// description: "left input becomes right and up input becomes down",
// maxCount: 9,
// count: 0,
// frequency: 0,
// isNonRefundable: true,
// isExperimentHide: true,
// isJunk: true,
// allowed() {
// return true
// },
// requires: "",
// effect() {
// const left = input.key.left
// input.key.left = input.key.right
// input.key.right = left
// const up = input.key.up
// input.key.up = input.key.down
// input.key.down = up
// },
// remove() {}
// },
{
name: "Sleipnir",
description: "grow more legs",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return !m.isShipMode
},
requires: "",
effect() {
m.draw = function() {
ctx.fillStyle = m.fillColor;
m.walk_cycle += m.flipLegs * m.Vx;
//draw body
ctx.save();
ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
ctx.translate(m.pos.x, m.pos.y);
for (let i = 0; i < 16; i++) {
m.calcLeg(Math.PI * i / 8, -3 * i / 16)
m.drawLeg("#444")
}
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;
ctx.stroke();
// ctx.beginPath();
// ctx.arc(15, 0, 3, 0, 2 * Math.PI);
// ctx.fillStyle = '#0cf';
// ctx.fill()
ctx.restore();
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
}
},
remove() {}
},
{
name: "diegesis",
description: "indicate gun fire delay
through a rotation of your head",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return !m.isShipMode
},
requires: "",
effect() {
m.draw = function() {
ctx.fillStyle = m.fillColor;
m.walk_cycle += m.flipLegs * m.Vx;
ctx.save();
ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
ctx.translate(m.pos.x, m.pos.y);
m.calcLeg(Math.PI, -3);
m.drawLeg("#4a4a4a");
m.calcLeg(0, 0);
m.drawLeg("#333");
ctx.rotate(m.angle - (m.fireCDcycle != Infinity ? m.flipLegs * 0.25 * Math.pow(Math.max(m.fireCDcycle - m.cycle, 0), 0.5) : 0));
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;
ctx.stroke();
ctx.restore();
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
}
},
remove() {}
},
{
name: "pareidolia",
description: "don't",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return !m.isShipMode
},
requires: "",
effect() {
m.draw = function() {
ctx.fillStyle = m.fillColor;
m.walk_cycle += m.flipLegs * m.Vx;
ctx.save();
ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.7
ctx.translate(m.pos.x, m.pos.y);
m.calcLeg(Math.PI, -3);
m.drawLeg("#4a4a4a");
m.calcLeg(0, 0);
m.drawLeg("#333");
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;
if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1); //here is the flip
ctx.stroke();
ctx.beginPath();
ctx.arc(2, -6, 7, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(25, -6, 7, 0.25 * Math.PI, 1.6 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(2, -10, 9, 1.25 * Math.PI, 1.75 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(25, -10, 9, 1.25 * Math.PI, 1.4 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(18, 13, 10, 0, 2 * Math.PI);
ctx.fillStyle = this.bodyGradient;
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(18, 13, 6, 0, 2 * Math.PI);
ctx.fillStyle = "#555";
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(3, -6, 3, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(26, -6, 3, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
ctx.restore();
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15;
}
},
remove() {}
},
{
name: "prism",
description: "you cycle through different colors",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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: "assimilation",
description: "all your bots are converted to the same random model",
maxCount: 1,
count: 0,
frequency: 0,
isBotTech: true,
isNonRefundable: true,
isExperimentHide: 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,
isExperimentHide: 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,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480)
},
remove() {}
},
{
name: "re-arm",
description: "remove all your guns,
and spawn new ones",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return b.inventory.length > 0
},
requires: "at least 1 gun",
effect() {
for (let i = 0; i < b.inventory.length; 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
},
remove() {}
},
{
name: "re-research",
description: "eject all your research",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return powerUps.research.count > 3
},
requires: "at least 4 research",
effect() {
for (let i = 0; i < powerUps.research.count; i++) powerUps.directSpawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "research");
powerUps.research.count = 0
},
remove() {}
},
{
name: "quantum black hole",
description: "use your energy and 4 research to spawn
inside the event horizon of a huge black hole",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: 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 2 research
spawn 40 nearby black holes",
maxCount: 9,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x, m.pos.y, "research");
const unit = {
x: 1,
y: 0
}
for (let i = 0; i < 40; i++) {
const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 600 + 800 * Math.random()))
spawn.sucker(where.x, where.y)
}
},
remove() {}
},
//**************************************************
//************************************************** undefined / lore
//************************************************** tech
//**************************************************
{
name: `undefined`,
// description: `${lore.techCount+1}/${lore.techGoal}
add copies of this to the potential tech pool`,
description: `this`,
maxCount: 1,
count: 0,
frequency: 2,
isLore: true,
// isNonRefundable: true,
isExperimentHide: true,
allowed() {
return true
},
requires: "",
effect() {
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`
} else {
this.frequency += lore.techGoal
// 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:
${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) {
// tech.tech.push({
// name: `undefined`,
// description: `${lore.techCount+1}/${lore.techGoal}
add copies of this to the potential tech pool`,
// maxCount: 1,
// count: 0,
// frequency: 2,
// isLore: true,
// isNonRefundable: true,
// isExperimentHide: true,
// allowed() {
// return true
// },
// requires: "",
// effect() {
// setTimeout(() => { //a short delay, I can't remember why
// lore.techCount++
// if (lore.techCount > lore.techGoal - 1) {
// // tech.removeLoreTechFromPool();
// for (let i = tech.tech.length - 1; i > 0; i--) {
// if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1)
// }
// } else {
// 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()
// }
// }, 1);
// },
// remove() {}
// })
// }
// },
// junk: [
// ],
//variables use for gun tech upgrades
fireRate: null,
bulletSize: null,
energySiphon: null,
healthDrain: null,
isCrouchAmmo: null,
isBulletsLastLonger: null,
isImmortal: null,
sporesOnDeath: null,
isImmuneExplosion: null,
isExplodeMob: null,
isDroneOnDamage: null,
isAcidDmg: null,
isAnnihilation: null,
largerHeals: null,
squirrelFx: null,
isCrit: null,
isLowHealthDmg: null,
isFarAwayDmg: null,
isEntanglement: null,
isMassEnergy: null,
isExtraChoice: null,
laserBotCount: null,
dynamoBotCount: null,
nailBotCount: null,
foamBotCount: null,
boomBotCount: null,
plasmaBotCount: null,
missileBotCount: null,
orbitBotCount: null,
collisionImmuneCycles: null,
blockDmg: null,
isPiezo: null,
isFastDrones: null,
isFastSpores: null,
superBallNumber: null,
oneSuperBall: null,
laserReflections: null,
laserDamage: null,
laserFieldDrain: null,
isAmmoFromHealth: null,
mobSpawnWithHealth: null,
isEnergyRecovery: null,
isHealthRecovery: null,
isEnergyLoss: null,
isDeathAvoid: null,
isDeathAvoidedThisLevel: null,
isSporeField: null,
isMissileField: null,
isIceField: null,
isMineAmmoBack: null,
isPlasmaRange: null,
isFreezeMobs: null,
isIceCrystals: null,
throwChargeRate: null,
isBlockStun: null,
isStunField: null,
isHarmDamage: null,
energyRegen: null,
isVacuumBomb: null,
renormalization: null,
fragments: null,
isEnergyDamage: null,
botSpawner: null,
isBotSpawnerReset: null,
isSporeFollow: null,
isNailRadiation: null,
isEnergyHealth: null,
isExplosionStun: null,
restDamage: null,
isRPG: null,
missileCount: null,
isDeterminism: null,
isSuperDeterminism: null,
isHarmReduce: null,
nailsDeathMob: null,
isSlowFPS: null,
isNeutronStun: null,
isAnsatz: null,
isDamageFromBulletCount: null,
isLaserDiode: null,
isNailShot: null,
slowFire: null,
fastTime: null,
squirrelJump: null,
isFastRadiation: null,
isExtraMaxEnergy: null,
isAmmoForGun: null,
isRapidPulse: null,
isPulseAim: null,
isSporeFreeze: null,
isShotgunRecoil: null,
isHealLowHealth: null,
isAoESlow: null,
isHarmArmor: null,
isTurret: null,
isRerollDamage: null,
isHarmFreeze: null,
isBotArmor: null,
isRerollHaste: null,
researchHaste: null,
isMineDrop: null,
isRerollBots: null,
isNailBotUpgrade: null,
isFoamBotUpgrade: null,
isLaserBotUpgrade: null,
isBoomBotUpgrade: null,
isOrbitBotUpgrade: null,
isDroneGrab: null,
isOneGun: null,
isDamageForGuns: null,
isGunCycle: null,
isFastFoam: null,
isSporeGrowth: null,
isStimulatedEmission: null,
nailGun: null,
nailInstantFireRate: null,
isCapacitor: null,
isEnergyNoAmmo: null,
isFreezeHarmImmune: null,
isSmallExplosion: null,
isExplosionHarm: null,
extraMaxHealth: null,
// bonusHealth: null,
isIntangible: null,
isCloakStun: null,
bonusEnergy: null,
healGiveMaxEnergy: null,
healMaxEnergyBonus: 0, //not null
aimDamage: null,
isNoFireDefense: null,
isNoFireDamage: null,
duplicateChance: null,
beamSplitter: null,
iceEnergy: null,
isPerfectBrake: null,
explosiveRadius: null,
isWormholeEnergy: null,
isWormholeDamage: null,
isNailCrit: null,
isFlechetteExplode: null,
isWormholeSpores: null,
isWormBullets: null,
isWideLaser: null,
wideLaser: null,
isPulseLaser: null,
isRadioactive: null,
isRailEnergyGain: null,
isMineSentry: null,
isIncendiary: null,
overfillDrain: null,
isNeutronSlow: null,
isRailAreaDamage: null,
historyLaser: null,
isSpeedHarm: null,
isSpeedDamage: null,
isTimeSkip: null,
isCancelDuplication: null,
cancelCount: null,
isCancelRerolls: null,
isBotDamage: null,
isBanish: null,
isMaxEnergyTech: null,
isLowEnergyDamage: null,
isRewindBot: null,
isRewindGrenade: null,
isExtruder: null,
isEndLevelPowerUp: null,
isRewindGun: null,
missileSize: null,
isLaserMine: null,
isAmmoFoamSize: null,
isIceIX: null,
isDupDamage: null,
isFireRateForGuns: null,
cyclicImmunity: null,
isTechDamage: null,
isRestHarm: null,
isFireMoveLock: null,
isRivets: null,
isNeedles: null,
isExplodeRadio: null,
isGunSwitchField: null,
isNeedleShieldPierce: null,
isDuplicateBoss: null,
is100Duplicate: null,
isDynamoBotUpgrade: null,
isBlockPowerUps: null,
isBlockHarm: null,
foamFutureFire: null,
isDamageAfterKill: null,
isHarmReduceAfterKill: null,
isSwitchReality: null,
isResearchReality: null,
isAnthropicDamage: null,
isFlipFlop: null,
isFlipFlopHarm: null,
isFlipFlopOn: null,
isFlipFlopLevelReset: null,
isFlipFlopDamage: null,
isFlipFlopEnergy: null,
isRelay: null,
relayIce: null,
isMetaAnalysis: null,
isFoamAttract: null,
droneCycleReduction: null,
droneEnergyReduction: null,
isNoHeals: null,
isAlwaysFire: null,
isDroneRespawn: null,
deathSpawns: null,
isMobBlockFling: null,
blockingIce: null,
isPhaseVelocity: null,
waveBeamSpeed: null,
wavePacketAmplitude: null,
isCollisionRealitySwitch: null,
iceIXOnDeath: null,
wimpCount: null,
isAddBlockMass: null,
isMACHO: null,
isHarmMACHO: null,
isSneakAttack: null,
isFallingDamage: null,
harmonics: null,
isStandingWaveExpand: null,
isTokamak: null,
superBallDelay: null,
isBlockExplode: null,
isOverHeal: null,
isDroneRadioactive: null,
droneRadioDamage: null,
isDroneTeleport: null,
isDroneFastLook: null,
isFoamTeleport: null,
isResearchBoss: null,
isJunkResearch: null,
junkResearchNumber: null,
laserColor: null,
laserColorAlpha: null,
isLongitudinal: null,
is360Longitudinal: null,
isShotgunReversed: null,
wormDuplicate: null,
isCloakingDamage: null,
harmonicEnergy: null,
isFieldHarmReduction: null,
isFastTime: null,
isAnthropicTech: null,
isSporeWorm: null,
isWormShot: null,
isFoamShot: null,
isIceShot: null,
isNeedleShot: null,
isBlockRestitution: null,
isZeno: null,
isFieldFree: null,
wormSurviveDmg: null,
isExtraGunField: null
}