abiogenesis

tech: abiogenesis - spawn a second level boss on each level, but costs 5 research or if you don't have the research add 49 JUNK tech to the pool
  note to level builders I rewrote the add duplicate boss code in all levels: spawn.secondaryBossChance(x,y)

foam tech: uncertainty principle - foam bullets change position randomly, increase foam damage by 66%

throwing blocks now charges faster with reduced fire cooldown
tech renormalization now has a 40% chance to refund a research  (was 37%)
performance- now precalculate player gradient fill
This commit is contained in:
landgreen
2021-06-30 06:40:37 -07:00
parent 5d4ef1994c
commit a2b56d1f7e
9 changed files with 338 additions and 342 deletions

View File

@@ -216,18 +216,18 @@ const b = {
}
},
fireProps(cd, speed, dir, me) {
m.fireCDcycle = m.cycle + Math.floor(cd * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(cd * b.fireCDscale); // cool down
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(dir),
y: m.Vy / 2 + speed * Math.sin(dir)
});
World.add(engine.world, bullet[me]); //add bullet to world
},
fireCD: 1,
fireCDscale: 1,
setFireCD() {
b.fireCD = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage / tech.fastTime
if (tech.isFireRateForGuns) b.fireCD *= Math.pow(0.86, b.inventory.length)
if (tech.isFireMoveLock) b.fireCD *= 0.5
b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage / tech.fastTime
if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.86, b.inventory.length)
if (tech.isFireMoveLock) b.fireCDscale *= 0.5
},
fireAttributes(dir, rotate = true) {
if (rotate) {
@@ -2435,7 +2435,7 @@ const b = {
// friction: 0.2,
// restitution: 0.2,
dmg: 0, //damage on impact
damage: tech.isFastFoam ? 0.048 : 0.012, //damage done over time
damage: (tech.isFastFoam ? 0.048 : 0.012) * (tech.isFoamTeleport ? 1.66 : 1), //damage done over time
scale: 1 - 0.006 / tech.isBulletsLastLonger * (tech.isFastFoam ? 1.6 : 1),
classType: "bullet",
collisionFilter: {
@@ -2449,6 +2449,8 @@ const b = {
target: null,
targetVertex: null,
targetRelativePosition: null,
portFrequency: 5 + Math.floor(5 * Math.random()),
nextPortCycle: Infinity, //disabled unless you have the teleport tech
beforeDmg(who) {
if (!this.target && who.alive) {
this.target = who;
@@ -2494,6 +2496,8 @@ const b = {
if (this.radius < 8) this.endCycle = 0;
}
if (this.target && this.target.alive) { //if stuck to a target
const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector
if (this.target.isVerticesChange) {
@@ -2577,9 +2581,15 @@ const b = {
}
}
}
if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isFoamTeleport
this.nextPortCycle = simulation.cycle + this.portFrequency
const range = 10 * Math.sqrt(this.radius) * Math.random()
Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random())))
}
}
}
});
if (tech.isFoamTeleport) bullet[me].nextPortCycle = simulation.cycle + bullet[me].portFrequency
World.add(engine.world, bullet[me]); //add bullet to world
Matter.Body.setVelocity(bullet[me], velocity);
},
@@ -3502,9 +3512,9 @@ const b = {
fireNormal() {
if (this.nextFireCycle + 1 < m.cycle) this.startingHoldCycle = m.cycle //reset if not constantly firing
const CD = Math.max(11 - 0.06 * (m.cycle - this.startingHoldCycle), 2) //CD scales with cycles fire is held down
this.nextFireCycle = m.cycle + CD * b.fireCD //predict next fire cycle if the fire button is held down
this.nextFireCycle = m.cycle + CD * b.fireCDscale //predict next fire cycle if the fire button is held down
m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCDscale); // cool down
this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / CD)
},
fireNeedles() {
@@ -3575,13 +3585,13 @@ const b = {
}
if (m.crouch) {
m.fireCDcycle = m.cycle + 45 * b.fireCD; // cool down
m.fireCDcycle = m.cycle + 45 * b.fireCDscale; // cool down
makeNeedle()
for (let i = 1; i < 4; i++) { //4 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i);
}
} else {
m.fireCDcycle = m.cycle + 25 * b.fireCD; // cool down
m.fireCDcycle = m.cycle + 25 * b.fireCDscale; // cool down
makeNeedle()
for (let i = 1; i < 3; i++) { //3 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i);
@@ -3595,7 +3605,7 @@ const b = {
// makeNeedle(m.angle - spread)
},
fireRivets() {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCDscale); // cool down
const me = bullet.length;
const size = tech.rivetSize * 7.5
@@ -3640,13 +3650,13 @@ const b = {
fireNailFireRate() {
if (this.nextFireCycle + 1 < m.cycle) this.startingHoldCycle = m.cycle //reset if not constantly firing
const CD = Math.max(7.5 - 0.06 * (m.cycle - this.startingHoldCycle), 2) //CD scales with cycles fire is held down
this.nextFireCycle = m.cycle + CD * b.fireCD //predict next fire cycle if the fire button is held down
this.nextFireCycle = m.cycle + CD * b.fireCDscale //predict next fire cycle if the fire button is held down
m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(CD * b.fireCDscale); // cool down
this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / CD)
},
fireInstantFireRate() {
m.fireCDcycle = m.cycle + Math.floor(2 * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(2 * b.fireCDscale); // cool down
this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / 2)
},
baseFire(angle) {
@@ -3685,18 +3695,18 @@ const b = {
let knock, spread
if (m.crouch) {
spread = 0.65
m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCD); // cool down
if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(58 * b.fireCD)) m.immuneCycle = m.cycle + Math.floor(58 * b.fireCD); //player is immune to damage for 30 cycles
m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCDscale); // cool down
if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(58 * b.fireCDscale)) m.immuneCycle = m.cycle + Math.floor(58 * b.fireCDscale); //player is immune to damage for 30 cycles
knock = 0.01
} else {
m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCD); // cool down
if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(47 * b.fireCD)) m.immuneCycle = m.cycle + Math.floor(47 * b.fireCD); //player is immune to damage for 30 cycles
m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale); // cool down
if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(47 * b.fireCDscale)) m.immuneCycle = m.cycle + Math.floor(47 * b.fireCDscale); //player is immune to damage for 30 cycles
spread = 1.3
knock = 0.1
}
if (tech.isShotgunRecoil) {
m.fireCDcycle -= 0.66 * (45 * b.fireCD)
m.fireCDcycle -= 0.66 * (45 * b.fireCDscale)
player.force.x -= 2 * knock * Math.cos(m.angle)
player.force.y -= 2 * knock * Math.sin(m.angle) //reduce knock back in vertical direction to stop super jumps
} else {
@@ -3848,7 +3858,7 @@ const b = {
do() {},
fireOne() {
const SPEED = m.crouch ? 43 : 36
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCDscale); // cool down
let dir = m.angle
const me = bullet.length;
bullet[me] = Bodies.polygon(m.pos.x + 30 * Math.cos(m.angle), m.pos.y + 30 * Math.sin(m.angle), 12, 21 * tech.bulletSize, b.fireAttributes(dir, false));
@@ -3875,7 +3885,7 @@ const b = {
},
fireMulti() {
const SPEED = m.crouch ? 43 : 36
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 23 : 15) * b.fireCDscale); // cool down
const SPREAD = m.crouch ? 0.08 : 0.13
let dir = m.angle - SPREAD * (tech.superBallNumber - 1) / 2;
for (let i = 0; i < tech.superBallNumber; i++) {
@@ -3908,7 +3918,7 @@ const b = {
const dir = m.angle
const x = m.pos.x + 30 * Math.cos(m.angle)
const y = m.pos.y + 30 * Math.sin(m.angle)
const delay = Math.floor((m.crouch ? 18 : 12) * b.fireCD)
const delay = Math.floor((m.crouch ? 18 : 12) * b.fireCDscale)
m.fireCDcycle = m.cycle + delay; // cool down
for (let i = 0; i < tech.superBallNumber; i++) {
@@ -3960,7 +3970,7 @@ const b = {
do() {
if (this.wavePacketCycle && !input.fire) {
this.wavePacketCycle = 0;
m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCDscale); // cool down
}
},
damage: 1,
@@ -4060,7 +4070,7 @@ const b = {
//fire a packet of bullets then delay for a while
this.wavePacketCycle++
if (this.wavePacketCycle > tech.wavePacketLength) {
m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(this.delay * b.fireCDscale); // cool down
this.wavePacketCycle = 0;
}
}
@@ -4076,7 +4086,7 @@ const b = {
fire() {
const countReduction = Math.pow(0.9, tech.missileCount)
if (m.crouch) {
m.fireCDcycle = m.cycle + 10 * b.fireCD / countReduction; // cool down
m.fireCDcycle = m.cycle + 10 * b.fireCDscale / countReduction; // cool down
// for (let i = 0; i < tech.missileCount; i++) {
// b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2, Math.sqrt(countReduction))
@@ -4102,7 +4112,7 @@ const b = {
b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5), -2)
}
} else {
m.fireCDcycle = m.cycle + 50 * b.fireCD / countReduction; // cool down
m.fireCDcycle = m.cycle + 50 * b.fireCDscale / countReduction; // cool down
const direction = {
x: Math.cos(m.angle),
y: Math.sin(m.angle)
@@ -4147,7 +4157,7 @@ const b = {
// bullet[bullet.length - 1].force.x -= 0.015 * (i - 1);
// }
// } else {
// m.fireCDcycle = m.cycle + 80 * b.fireCD; // cool down
// m.fireCDcycle = m.cycle + 80 * b.fireCDscale; // cool down
// const direction = {
// x: Math.cos(m.angle),
// y: Math.sin(m.angle)
@@ -4164,7 +4174,7 @@ const b = {
// }
// } else {
// if (m.crouch) {
// m.fireCDcycle = m.cycle + 10 * b.fireCD; // cool down
// m.fireCDcycle = m.cycle + 10 * b.fireCDscale; // cool down
// const off = Math.random() - 0.5
// b.missile({
// x: m.pos.x,
@@ -4174,7 +4184,7 @@ const b = {
// bullet[bullet.length - 1].force.x += off * 0.03;
// // bullet[bullet.length - 1].force.y += push.y * (i - 1);
// } else {
// m.fireCDcycle = m.cycle + 55 * b.fireCD; // cool down
// m.fireCDcycle = m.cycle + 55 * b.fireCDscale; // cool down
// // bullet[bullet.length - 1].force.y += 0.01; //a small push down at first to make it seem like the missile is briefly falling
// }
@@ -4189,7 +4199,7 @@ const b = {
have: false,
do() {},
fire() {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 40 : 30) * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 40 : 30) * b.fireCDscale); // cool down
b.grenade()
},
}, {
@@ -4218,7 +4228,7 @@ const b = {
y: speed * Math.sin(m.angle)
}, 0, tech.isMineAmmoBack)
}
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 50 : 25) * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 50 : 25) * b.fireCDscale); // cool down
}
}, {
name: "spores",
@@ -4362,18 +4372,18 @@ const b = {
if (tech.isDroneRadioactive) {
if (m.crouch) {
b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45)
m.fireCDcycle = m.cycle + Math.floor(5 * 13 * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(5 * 13 * b.fireCDscale); // cool down
} else {
b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 10)
m.fireCDcycle = m.cycle + Math.floor(5 * 6 * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(5 * 6 * b.fireCDscale); // cool down
}
} else {
if (m.crouch) {
b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45)
m.fireCDcycle = m.cycle + Math.floor(13 * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(13 * b.fireCDscale); // cool down
} else {
b.drone()
m.fireCDcycle = m.cycle + Math.floor(6 * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(6 * b.fireCDscale); // cool down
}
}
}
@@ -4388,10 +4398,10 @@ const b = {
// fire() {
// if (m.crouch) {
// b.iceIX(10, 0.3)
// m.fireCDcycle = m.cycle + Math.floor(8 * b.fireCD); // cool down
// m.fireCDcycle = m.cycle + Math.floor(8 * b.fireCDscale); // cool down
// } else {
// b.iceIX(2)
// m.fireCDcycle = m.cycle + Math.floor(3 * b.fireCD); // cool down
// m.fireCDcycle = m.cycle + Math.floor(3 * b.fireCDscale); // cool down
// }
// }
@@ -4427,7 +4437,7 @@ const b = {
},
fire() {
this.charge++
m.fireCDcycle = m.cycle + Math.floor((1 + 0.35 * this.charge) * b.fireCD);
m.fireCDcycle = m.cycle + Math.floor((1 + 0.35 * this.charge) * b.fireCDscale);
},
fireFoam() {
const spread = (m.crouch ? 0.05 : 0.6) * (Math.random() - 0.5)
@@ -4517,7 +4527,7 @@ const b = {
if (tech.isCapacitor) {
if ((m.energy > 0.16 || tech.isRailEnergyGain)) { //&& m.immuneCycle < m.cycle
m.energy += 0.16 * (tech.isRailEnergyGain ? 6 : -1)
m.fireCDcycle = m.cycle + Math.floor(30 * b.fireCD);
m.fireCDcycle = m.cycle + Math.floor(30 * b.fireCDscale);
const me = bullet.length;
bullet[me] = Bodies.rectangle(m.pos.x + 50 * Math.cos(m.angle), m.pos.y + 50 * Math.sin(m.angle), 60, 14, {
density: 0.005, //0.001 is normal
@@ -4552,7 +4562,7 @@ const b = {
}
},
onEnd() {},
drawCycle: Math.floor(10 * b.fireCD),
drawCycle: Math.floor(10 * b.fireCDscale),
do() {
this.force.y += this.mass * 0.0003; // low gravity that scales with charge
if (this.drawCycle > 0) {
@@ -4693,7 +4703,7 @@ const b = {
m.fireCDcycle = Infinity //can't fire until mouse is released
const previousCharge = this.charge
let smoothRate = 0.98 * (m.crouch ? 0.99 : 1) * (0.98 + 0.02 * b.fireCD) //small b.fireCD = faster shots, b.fireCD=1 = normal shot, big b.fireCD = slower chot
let smoothRate = 0.98 * (m.crouch ? 0.99 : 1) * (0.98 + 0.02 * b.fireCDscale) //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
this.charge = this.charge * smoothRate + 1 * (1 - smoothRate)
if (tech.isRailEnergyGain) {
if (m.immuneCycle < m.cycle) m.energy += (this.charge - previousCharge) * 2 //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
@@ -4827,12 +4837,12 @@ const b = {
this.do = () => {};
if (tech.isPulseLaser) {
this.fire = () => {
const drain = 0.01 * tech.isLaserDiode / b.fireCD
const drain = 0.01 * tech.isLaserDiode / b.fireCDscale
if (m.energy > drain) {
m.energy -= m.fieldRegen
if (this.charge < 50 * m.maxEnergy) {
m.energy -= drain
this.charge += 1 / b.fireCD
this.charge += 1 / b.fireCDscale
}
}
}
@@ -4905,7 +4915,7 @@ const b = {
// this.fire = this.firePhoton
},
// firePhoton() {
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down
// b.photon({ x: m.pos.x + 23 * Math.cos(m.angle), y: m.pos.y + 23 * Math.sin(m.angle) }, m.angle)
// },
fireLaser() {
@@ -5041,7 +5051,7 @@ const b = {
}
},
// firePulse() {
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down
// let energy = 0.3 * Math.min(m.energy, 1.5)
// m.energy -= energy * tech.isLaserDiode
// if (tech.beamSplitter) {
@@ -5082,7 +5092,7 @@ const b = {
if (this.rewindCount > 599 || m.energy < DRAIN || history.activeGun !== this.activeGunIndex) {
this.rewindCount = 0;
m.resetHistory();
m.fireCDcycle = m.cycle + Math.floor(120 * b.fireCD); // cool down
m.fireCDcycle = m.cycle + Math.floor(120 * b.fireCDscale); // cool down
} else {
m.energy -= DRAIN
if (m.immuneCycle < m.cycle + 30) m.immuneCycle = m.cycle + 30; //player is immune to damage for 5 cycles

View File

@@ -119,6 +119,8 @@ window.addEventListener('load', () => {
const canvas = document.getElementById("canvas");
//using "const" causes problems in safari when an ID shares the same name.
const ctx = canvas.getContext("2d");
// const ctx = canvas.getContext('2d', { alpha: false }); //optimization, but doesn't work
document.body.style.backgroundColor = "#fff";
//disable pop up menu on right click
@@ -195,7 +197,7 @@ const build = {
${simulation.isCheating? "<em>lore disabled</em><br><br>": ""}
<strong class='color-d'>damage</strong> increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}%
<br><strong class='color-harm'>harm</strong> reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}%
<br><strong><em>fire delay</em></strong> decrease: ${((1-b.fireCD)*100).toFixed(b.fireCD < 0.1 ? 2 : 0)}%
<br><strong><em>fire delay</em></strong> decrease: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
<br><strong class='color-dup'>duplication</strong> chance: ${(Math.min(1,tech.duplicationChance())*100).toFixed(0)}%
${botText}
<br>

View File

@@ -15,9 +15,9 @@ const level = {
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(30)
// simulation.isHorizontalFlipped = true
// m.setField("time dilation")
// b.giveGuns("grenades")
// tech.giveTech("neutron bomb")
// m.setField("metamaterial cloaking")
// b.giveGuns("foam")
// tech.giveTech("uncertainty principle")
// for (let i = 0; i < 9; i++) tech.giveTech("spherical harmonics")
// tech.giveTech("supertemporal")
// for (let i = 0; i < 3; i++) tech.giveTech("packet length")
@@ -1273,7 +1273,6 @@ const level = {
}
}
)
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 2000 - 650, y + -875);
spawn.randomMob(x + 2000 - 1600, y + -425, Infinity);
spawn.randomMob(x + 2000 - 1725, y + -1250, Infinity);
spawn.randomMob(x + 2000 - 1250, y + -1200, Infinity);
@@ -1281,6 +1280,7 @@ const level = {
spawn.randomMob(x + 2000 - 800, y + -125, Infinity);
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
spawn.secondaryBossChance(x + 2000 - 650, y + -875)
} else {
powerUps.spawnStartingPowerUps(x + 1650, y + -400);
spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall
@@ -1305,7 +1305,6 @@ const level = {
}
}
)
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875);
spawn.randomMob(x + 1600, y + -425, Infinity);
spawn.randomMob(x + 1725, y + -1250, Infinity);
spawn.randomMob(x + 1250, y + -1200, Infinity);
@@ -1313,6 +1312,7 @@ const level = {
spawn.randomMob(x + 800, y + -125, Infinity);
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
spawn.secondaryBossChance(x + 650, y + -875)
}
},
(x = offset.x, y = offset.y) => { //spawn block and fire it
@@ -1365,7 +1365,6 @@ const level = {
}
}
)
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875);
spawn.randomMob(x + 2000 - 1600, y + -425, Infinity);
spawn.randomMob(x + 2000 - 1725, y + -1250, Infinity);
spawn.randomMob(x + 2000 - 1250, y + -1200, Infinity);
@@ -1373,6 +1372,7 @@ const level = {
spawn.randomMob(x + 2000 - 800, y + -125, Infinity);
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
spawn.secondaryBossChance(x + 650, y + -875)
} else {
powerUps.spawnStartingPowerUps(x + 1650, y + -400);
spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall
@@ -1422,7 +1422,6 @@ const level = {
}
}
)
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875);
spawn.randomMob(x + 1600, y + -425, Infinity);
spawn.randomMob(x + 1725, y + -1250, Infinity);
spawn.randomMob(x + 1250, y + -1200, Infinity);
@@ -1430,6 +1429,7 @@ const level = {
spawn.randomMob(x + 800, y + -125, Infinity);
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
spawn.secondaryBossChance(x + 650, y - 875)
}
},
(x = offset.x, y = offset.y) => { //fire an "ammo clip" of blocks
@@ -1493,7 +1493,6 @@ const level = {
}
}
)
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875);
spawn.randomMob(x + 2000 - 1600, y + -425, Infinity);
spawn.randomMob(x + 2000 - 1725, y + -1250, Infinity);
spawn.randomMob(x + 2000 - 1250, y + -1200, Infinity);
@@ -1501,6 +1500,7 @@ const level = {
spawn.randomMob(x + 2000 - 800, y + -125, Infinity);
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
spawn.secondaryBossChance(x + 650, y - 875)
} else {
powerUps.spawnStartingPowerUps(x + 1650, y + -400);
spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall
@@ -1561,7 +1561,6 @@ const level = {
}
}
)
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(x + 650, y + -875);
spawn.randomMob(x + 1600, y + -425, Infinity);
spawn.randomMob(x + 1725, y + -1250, Infinity);
spawn.randomMob(x + 1250, y + -1200, Infinity);
@@ -1569,6 +1568,7 @@ const level = {
spawn.randomMob(x + 800, y + -125, Infinity);
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
spawn.secondaryBossChance(x + 650, y - 875)
}
}
]
@@ -2169,7 +2169,6 @@ const level = {
// spawn.randomGroup(1700, -900, 0.4);
// if (simulation.difficulty > 3) spawn.randomLevelBoss(2200, -1300);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
// if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
},
final() {
level.custom = () => {
@@ -2219,7 +2218,7 @@ const level = {
spawn.mapRect(5700, -3300, 1800, 5100); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.mapRect(5425, -650, 375, 450); //blocking exit
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
spawn.secondaryBossChance(4800, -500)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -2289,7 +2288,7 @@ const level = {
if (simulation.difficulty * Math.random() > 7 * i) spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350);
spawn.secondaryBossChance(4125, -350)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -2509,7 +2508,6 @@ const level = {
}
}
powerUps.spawnStartingPowerUps(2300, -150);
// if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1900, -675);
},
testChamber() {
level.setPosToSpawn(0, -50); //lower start
@@ -2705,8 +2703,7 @@ const level = {
}
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1925, -1250);
spawn.secondaryBossChance(1925, -1250)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -2913,8 +2910,7 @@ const level = {
spawn.randomMob(2825, 400, 0.9);
if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss", "orbitalBoss", "shieldingBoss"]);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275);
spawn.secondaryBossChance(7725, 2275)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3101,7 +3097,7 @@ const level = {
}
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3950, -850);
spawn.secondaryBossChance(3950, -850)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3272,7 +3268,7 @@ const level = {
spawn.randomGroup(4900, -1200, 0);
if (simulation.difficulty > 3) spawn.randomLevelBoss(3200, -1900);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(2175, -2425);
spawn.secondaryBossChance(2175, -2425)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3489,7 +3485,7 @@ const level = {
}
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(5350, -325);
spawn.secondaryBossChance(5350, -325)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3657,7 +3653,7 @@ const level = {
spawn.randomGroup(1700, -900, 0.4);
if (simulation.difficulty > 3) spawn.randomLevelBoss(2600, -2300);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(3075, -2050);
spawn.secondaryBossChance(3075, -2050)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3899,7 +3895,7 @@ const level = {
if (simulation.difficulty > 3) spawn.randomLevelBoss(-2400, -2650);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(-1825, -1975);
spawn.secondaryBossChance(-1825, -1975)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -4206,8 +4202,8 @@ const level = {
spawn.snakeBoss(-1000 + Math.random() * 2500, -1300); //boss snake with head
}
}
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(300, -800);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
spawn.secondaryBossChance(300, -800)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -4438,7 +4434,7 @@ const level = {
}
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(1875, -675);
spawn.secondaryBossChance(1875, -675)
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -5920,7 +5916,7 @@ const level = {
}
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275);
spawn.secondaryBossChance(7725, 2275)
},
coliseum() {
level.custom = () => {
@@ -6070,8 +6066,7 @@ const level = {
powerUps.spawn(200, 50, "ammo");
powerUps.addResearchToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(6600, 600, ["historyBoss", "powerUpBoss", "pulsarBoss", "orbitalBoss"]);
spawn.secondaryBossChance(6600, 600)
},
crossfire() {
//*1.5
@@ -6179,12 +6174,8 @@ const level = {
// spawn.randomGroup(7700, -1100, 0.5);
spawn.randomGroup(9800, -1100, 0.5);
if (simulation.difficulty > 10) {
spawn.randomLevelBoss(8600, -600, ["powerUpBoss", "bomberBoss", "snakeBoss", "spiderBoss", "historyBoss"]);
}
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) {
spawn.randomLevelBoss(7900, -400, ["powerUpBoss", "spiderBoss", "historyBoss"]);
}
if (simulation.difficulty > 10) spawn.randomLevelBoss(8600, -600, ["powerUpBoss", "bomberBoss", "snakeBoss", "spiderBoss", "historyBoss"])
spawn.secondaryBossChance(7900, -400)
//Boss Spawning
if (simulation.difficulty > 10) {
@@ -6422,7 +6413,7 @@ const level = {
} else {
exitDoor.isOpen = false;
}
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(800, -800);
spawn.secondaryBossChance(800, -800)
powerUps.spawn(4450, 1050, "heal");
if (Math.random() > (0.2 + (simulation.difficulty / 60))) {
@@ -6933,15 +6924,7 @@ const level = {
spawn.randomLevelBoss(850 + Math.random() * 250, -1100 + Math.random() * 200, bosses);
}
}
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) {
if (abc < 0.6 * 5 / 8 || abc >= 1 - 0.15 * 5 / 17) {
spawn.laserBoss(-350 + Math.random() * 300, -600 + Math.random() * 200);
} else if (abc < 0.65) {
spawn.randomLevelBoss(850 + Math.random() * 250, -1100 + Math.random() * 200, bosses);
} else {
spawn.randomLevelBoss(-1500 + Math.random() * 250, -1100 + Math.random() * 200, bosses);
}
}
spawn.secondaryBossChance(850 + Math.random() * 250, -1100 + Math.random() * 200)
//draw leg for statue
function statueLeg(shift, color) {

View File

@@ -49,6 +49,7 @@ const m = {
eyeFillColor: null,
fillColor: null, //set by setFillColors
fillColorDark: null, //set by setFillColors
bodyGradient: null, //set by setFillColors
color: {
hue: 0,
sat: 0,
@@ -57,6 +58,10 @@ const m = {
setFillColors() {
this.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
this.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light-25}%)`
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
this.bodyGradient = grd
},
height: 42,
yOffWhen: {
@@ -803,10 +808,7 @@ const m = {
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient;
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
@@ -838,10 +840,7 @@ const m = {
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
@@ -873,10 +872,7 @@ const m = {
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
@@ -1091,8 +1087,8 @@ const m = {
if (input.field) {
if (m.energy > 0.001) {
if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle
m.energy -= 0.001 / tech.throwChargeRate;
m.throwCharge += 0.5 * (tech.throwChargeRate + 2 * tech.isAddBlockMass) / m.holdingTarget.mass
m.throwCharge += 0.5 * (tech.throwChargeRate / b.fireCDscale + 2 * tech.isAddBlockMass) / m.holdingTarget.mass
if (m.throwCharge < 6) m.energy -= 0.001 / tech.throwChargeRate / b.fireCDscale; // m.throwCharge caps at 5
//draw charge
const x = m.pos.x + 15 * Math.cos(m.angle);
const y = m.pos.y + 15 * Math.sin(m.angle);
@@ -2996,10 +2992,7 @@ const m = {
//body
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";

View File

@@ -223,7 +223,7 @@ const powerUps = {
b.randomBot()
if (tech.renormalization) {
for (let i = 0; i < limit; i++) {
if (Math.random() < 0.37) {
if (Math.random() < 0.4) {
m.fieldCDcycle = m.cycle + 30;
powerUps.spawn(m.pos.x, m.pos.y, "research");
}
@@ -234,7 +234,7 @@ const powerUps = {
if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) {
document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}`
}
if (tech.renormalization && Math.random() < 0.37 && amount < 0) {
if (tech.renormalization && Math.random() < 0.4 && amount < 0) {
for (let i = 0, len = -amount; i < len; i++) powerUps.spawn(m.pos.x, m.pos.y, "research");
}
if (tech.isRerollHaste) {

View File

@@ -87,6 +87,19 @@ const spawn = {
// other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
},
secondaryBossChance(x, y) {
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) {
spawn.randomLevelBoss(x, y);
} else if (tech.isResearchBoss) {
if (powerUps.research.count > 4) {
powerUps.research.changeRerolls(-5)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>-=</span> 5<br>${powerUps.research.count}`)
} else {
tech.addJunkTechToPool(49)
}
spawn.randomLevelBoss(x, y);
}
},
//mob templates *********************************************************************************************
//***********************************************************************************************************
MACHO(x = m.pos.x, y = m.pos.y) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the player

View File

@@ -66,6 +66,7 @@
if (options.length) {
for (let i = 0; i < num; i++) tech.tech[options[Math.floor(Math.random() * options.length)]].frequency++
}
simulation.makeTextLog(`<span class='color-var'>tech</span>.tech.push(${num} <span class='color-text'>JUNK</span>)`)
},
removeJunkTechFromPool(num = 1) {
for (let j = 0; j < num; j++) {
@@ -77,11 +78,6 @@
}
}
},
// removeJunkTechFromPool() {
// for (let i = tech.tech.length - 1; i > 0; i--) {
// if (tech.tech[i].isJunk && tech.tech[i].count === 0) tech.tech.splice(i, 1)
// }
// },
giveTech(index = 'random') {
if (index === 'random') {
let options = [];
@@ -93,7 +89,6 @@
let newTech = options[Math.floor(Math.random() * options.length)]
tech.giveTech(newTech)
simulation.makeTextLog(`<span class='color-var'>tech</span>.giveTech("<span class='color-text'>${tech.tech[newTech].name}</span>")<em> //random tech</em>`);
}
} else {
if (isNaN(index)) { //find index by name
@@ -704,6 +699,24 @@
tech.isRadioactive = false
}
},
{
name: "water shielding",
description: "<strong class='color-p'>radioactive</strong> effects on you are reduced by 75%<br><em>neutron bomb, drones, explosions, slime</em>",
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: "<strong class='color-e'>explosions</strong> release <strong class='color-p'>gamma radiation</strong><br><strong>100%</strong> more <strong class='color-d'>damage</strong>, but over 4 seconds",
@@ -951,15 +964,15 @@
},
{
name: "decorrelation",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>66%</strong><br>after not using your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> for <strong>2</strong> seconds",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>66%</strong> after not <strong>activating</strong><br>your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> for <strong>2</strong> seconds",
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (b.totalBots() > 1 || tech.haveGunCheck("mine") || tech.haveGunCheck("spores") || m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing") && !tech.isEnergyHealth
return ((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") && !tech.isEnergyHealth
},
requires: "drones, spores, mines, or bots",
requires: "drones, spores, mines, or bots, ",
effect() {
tech.isNoFireDefense = true
},
@@ -2244,7 +2257,7 @@
},
{
name: "overcharge",
description: "increase your <strong>maximum</strong> <strong class='color-f'>energy</strong> by <strong>60</strong><br>add <strong>10</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
description: "increase your <strong>maximum</strong> <strong class='color-f'>energy</strong> by <strong>60</strong><br><strong>+10</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 9,
count: 0,
frequency: 1,
@@ -2266,7 +2279,7 @@
},
{
name: "Maxwell's demon",
description: "<strong class='color-f'>energy</strong> above your max decays <strong>92%</strong> slower<br>add <strong>18</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
description: "<strong class='color-f'>energy</strong> above your max decays <strong>92%</strong> slower<br><strong>+18</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2712,7 +2725,7 @@
},
{
name: "renormalization",
description: "using a <strong class='color-r'>research</strong> for <strong>any</strong> purpose<br>has a <strong>37%</strong> chance to spawn a <strong class='color-r'>research</strong>",
description: "using a <strong class='color-r'>research</strong> for <strong>any</strong> purpose<br>has a <strong>40%</strong> chance to spawn a <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2819,6 +2832,24 @@
},
remove() {}
},
{
name: "abiogenesis",
description: "at the start of a level spawn a 2nd <strong>boss</strong> for<br><strong>5</strong> <strong class='color-r'>research</strong> or <strong>+49</strong> <strong class='color-j'>JUNK</strong> to the <strong class='color-m'>tech</strong> pool",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return (build.isExperimentSelection || powerUps.research.count > 4) && !tech.isDuplicateBoss
},
requires: "at least 5 research and not parthenogenesis",
effect() {
tech.isResearchBoss = true; //abiogenesis
},
remove() {
tech.isResearchBoss = false;
}
},
{
name: "bubble fusion",
description: "after destroying a mob's natural <strong>shield</strong><br>spawn <strong>1-2</strong> <strong class='color-h'>heals</strong>, <strong class='color-g'>ammo</strong>, or <strong class='color-r'>research</strong>",
@@ -2857,7 +2888,7 @@
},
{
name: "replication",
description: "<strong>10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>add <strong>18</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
description: "<strong>10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+18</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 9,
count: 0,
frequency: 1,
@@ -2983,9 +3014,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.duplicationChance() > 0
return tech.duplicationChance() > 0 && !tech.isResearchBoss
},
requires: "some duplication chance",
requires: "some duplication chance, not abiogenesis",
effect() {
tech.isDuplicateBoss = true;
},
@@ -3259,7 +3290,7 @@
},
{
name: "dark patterns",
description: "reduce combat <strong>difficulty</strong> by <strong>1 level</strong><br>add <strong>21</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
description: "reduce combat <strong>difficulty</strong> by <strong>1 level</strong><br><strong>+21</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 1,
count: 0,
frequency: 1,
@@ -4058,25 +4089,6 @@
b.setGrenadeMode()
}
},
{
name: "water shielding",
description: "<strong class='color-p'>radioactive</strong> effects on you are reduced by 75%<br><em>neutron bomb, drones, explosions, slime</em>",
isGunTech: true,
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: "vacuum permittivity",
description: "increase <strong class='color-p'>radioactive</strong> range by <strong>20%</strong><br>objects in range of the bomb are <strong>slowed</strong>",
@@ -4155,7 +4167,7 @@
},
{
name: "booby trap",
description: "drop a <strong>mine</strong> after picking up a <strong>power up</strong><br>add <strong>13</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
description: "drop a <strong>mine</strong> after picking up a <strong>power up</strong><br><strong>+13</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 1,
count: 0,
frequency: 2,
@@ -4410,6 +4422,25 @@
tech.droneRadioDamage = 1
}
},
{
name: "uncertainty principle",
description: "<strong>foam</strong> bubbles randomly change <strong>position</strong><br>increase <strong>foam</strong> <strong class='color-d'>damage</strong> per second by <strong>66%</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.foamBotCount > 1)
},
requires: "foam, not electrostatic induction",
effect() {
tech.isFoamTeleport = true
},
remove() {
tech.isFoamTeleport = false;
}
},
{
name: "necrophoresis",
description: "<strong>foam</strong> bubbles grow and split into 3 <strong>copies</strong><br> when the mob they are stuck to <strong>dies</strong>",
@@ -4450,25 +4481,6 @@
tech.foamGravity = 0.00008
}
},
{
name: "electrostatic induction",
description: "<strong>foam</strong> bullets are electrically charged<br>causing <strong>attraction</strong> to nearby <strong>mobs</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam") || tech.foamBotCount > 1
},
requires: "foam",
effect() {
tech.isFoamAttract = true
},
remove() {
tech.isFoamAttract = false
}
},
{
name: "quantum foam",
description: "<strong>foam</strong> gun fires <strong>0.30</strong> seconds into the <strong>future</strong><br>increase <strong>foam</strong> gun <strong class='color-d'>damage</strong> by <strong>90%</strong>",
@@ -4507,6 +4519,25 @@
tech.isAmmoFoamSize = false;
}
},
{
name: "electrostatic induction",
description: "<strong>foam</strong> bullets are electrically charged<br>causing <strong>attraction</strong> to nearby <strong>mobs</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isFoamTeleport && (tech.haveGunCheck("foam") || tech.foamBotCount > 1)
},
requires: "foam, not uncertainty",
effect() {
tech.isFoamAttract = true
},
remove() {
tech.isFoamAttract = false
}
},
{
name: "half-wave rectifier",
description: "charging the <strong>rail gun</strong> gives you <strong class='color-f'>energy</strong><br><em>instead of draining it</em>",
@@ -6454,7 +6485,7 @@
},
{
name: "expert system",
description: "spawn a <strong class='color-m'>tech</strong> power up<br>add <strong>64</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
description: "spawn a <strong class='color-m'>tech</strong> power up<br><strong>+64</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
maxCount: 9,
count: 0,
frequency: 0,
@@ -6604,10 +6635,7 @@
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
@@ -6652,10 +6680,7 @@
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
@@ -6694,10 +6719,7 @@
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(1, m.fillColor);
ctx.fillStyle = grd;
ctx.fillStyle = this.bodyGradient
ctx.fill();
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;
@@ -6909,7 +6931,7 @@
},
{
name: "quantum black hole",
description: "use all your <strong class='color-f'>energy</strong> to <strong>spawn</strong><br>inside the event horizon of a huge <strong>black hole</strong>",
description: "use your <strong class='color-f'>energy</strong> and <strong>1</strong> <strong class='color-r'>research</strong> to <strong>spawn</strong><br>inside the event horizon of a huge <strong>black hole</strong>",
maxCount: 9,
count: 0,
frequency: 0,
@@ -6917,12 +6939,14 @@
isExperimentHide: true,
isJunk: true,
allowed() {
return true
return powerUps.research.count > 0
},
requires: "",
requires: "at least 1 research",
effect() {
m.energy = 0
spawn.suckerBoss(m.pos.x, m.pos.y - 1000)
powerUps.research.changeRerolls(-1)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>--</span><br>${powerUps.research.count}`)
},
remove() {}
},
@@ -7267,5 +7291,7 @@
isBlockExplode: null,
isOverHeal: null,
isDroneRadioactive: null,
droneRadioDamage: null
droneRadioDamage: null,
isFoamTeleport: null,
isResearchBoss: null
}