diff --git a/.DS_Store b/.DS_Store
index dd7f993..4df85bd 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index 55af9b6..d7e5b8d 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -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
diff --git a/js/index.js b/js/index.js
index 96aa9ab..b9219fe 100644
--- a/js/index.js
+++ b/js/index.js
@@ -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? "lore disabled
": ""}
damage increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}%
harm reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}%
-
fire delay decrease: ${((1-b.fireCD)*100).toFixed(b.fireCD < 0.1 ? 2 : 0)}%
+
fire delay decrease: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
duplication chance: ${(Math.min(1,tech.duplicationChance())*100).toFixed(0)}%
${botText}
diff --git a/js/level.js b/js/level.js
index 6f0369a..56fe8ff 100644
--- a/js/level.js
+++ b/js/level.js
@@ -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) {
diff --git a/js/player.js b/js/player.js
index 7ee8b3c..c0cd448 100644
--- a/js/player.js
+++ b/js/player.js
@@ -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";
diff --git a/js/powerup.js b/js/powerup.js
index a84de0c..8dc572d 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -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) {
diff --git a/js/spawn.js b/js/spawn.js
index de4f64b..773ec26 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -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(`m.research -= 5
${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
diff --git a/js/tech.js b/js/tech.js
index c768d8b..70c800e 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -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(`tech.tech.push(${num} JUNK)`)
},
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(`tech.giveTech("${tech.tech[newTech].name}") //random tech`);
-
}
} else {
if (isNaN(index)) { //find index by name
@@ -704,6 +699,24 @@
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",
@@ -951,15 +964,15 @@
},
{
name: "decorrelation",
- description: "reduce harm by 66%
after not using your gun or field for 2 seconds",
+ description: "reduce harm by 66% after not activating
your gun or field for 2 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 maximum energy by 60
add 10 JUNK tech to the potential pool",
+ description: "increase your maximum energy by 60
+10 JUNK to the potential tech pool",
maxCount: 9,
count: 0,
frequency: 1,
@@ -2266,7 +2279,7 @@
},
{
name: "Maxwell's demon",
- description: "energy above your max decays 92% slower
add 18 JUNK tech to the potential pool",
+ description: "energy above your max decays 92% slower
+18 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2712,7 +2725,7 @@
},
{
name: "renormalization",
- description: "using a research for any purpose
has a 37% chance to spawn a research",
+ description: "using a research for any purpose
has a 40% chance to spawn a research",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2819,6 +2832,24 @@
},
remove() {}
},
+ {
+ name: "abiogenesis",
+ description: "at the start of a level spawn a 2nd boss for
5 research or +49 JUNK to the tech 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 shield
spawn 1-2 heals, ammo, or research",
@@ -2857,7 +2888,7 @@
},
{
name: "replication",
- description: "10% chance to duplicate spawned power ups
add 18 JUNK tech to the potential pool",
+ description: "10% chance to duplicate spawned power ups
+18 JUNK to the potential tech 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 difficulty by 1 level
add 21 JUNK tech to the potential pool",
+ description: "reduce combat difficulty by 1 level
+21 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 1,
@@ -4058,25 +4089,6 @@
b.setGrenadeMode()
}
},
- {
- name: "water shielding",
- description: "radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio
- },
- requires: "neutron bomb or irradiated drones or iridium-192",
- effect() {
- tech.isRadioactiveResistance = true
- },
- remove() {
- tech.isRadioactiveResistance = false
- }
- },
{
name: "vacuum permittivity",
description: "increase radioactive range by 20%
objects in range of the bomb are slowed",
@@ -4155,7 +4167,7 @@
},
{
name: "booby trap",
- description: "drop a mine after picking up a power up
add 13 JUNK tech to the potential pool",
+ description: "drop a mine after picking up a power up
+13 JUNK to the potential tech pool",
maxCount: 1,
count: 0,
frequency: 2,
@@ -4410,6 +4422,25 @@
tech.droneRadioDamage = 1
}
},
+ {
+ name: "uncertainty principle",
+ description: "foam bubbles randomly change position
increase foam damage per second by 66%",
+ 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: "foam bubbles grow and split into 3 copies
when the mob they are stuck to dies",
@@ -4450,25 +4481,6 @@
tech.foamGravity = 0.00008
}
},
- {
- name: "electrostatic induction",
- description: "foam bullets are electrically charged
causing attraction to nearby mobs",
- 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: "foam gun fires 0.30 seconds into the future
increase foam gun damage by 90%",
@@ -4507,6 +4519,25 @@
tech.isAmmoFoamSize = false;
}
},
+ {
+ name: "electrostatic induction",
+ description: "foam bullets 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)
+ },
+ requires: "foam, not uncertainty",
+ effect() {
+ tech.isFoamAttract = true
+ },
+ remove() {
+ tech.isFoamAttract = false
+ }
+ },
{
name: "half-wave rectifier",
description: "charging the rail gun gives you energy
instead of draining it",
@@ -6454,7 +6485,7 @@
},
{
name: "expert system",
- description: "spawn a tech power up
add 64 JUNK tech to the potential pool",
+ description: "spawn a tech power up
+64 JUNK to the potential tech 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 energy to spawn
inside the event horizon of a huge black hole",
+ description: "use your energy and 1 research to spawn
inside the event horizon of a huge black hole",
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(`m.research --
${powerUps.research.count}`)
},
remove() {}
},
@@ -7267,5 +7291,7 @@
isBlockExplode: null,
isOverHeal: null,
isDroneRadioactive: null,
- droneRadioDamage: null
+ droneRadioDamage: null,
+ isFoamTeleport: null,
+ isResearchBoss: null
}
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index abe42bd..f34fb9f 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,170 +1,19 @@
******************************************************** NEXT PATCH ********************************************************
-irradiated drones
- new tech: beta radiation - double damage and half lifespan
- now don't clump as often, to make the graphics look better
- effective radius now includes edges of mobs, not just centers
- so they work better on large radius mobs
- do 50% more damage, but have a 10% smaller radius and last 3 second shorter time and 80% less ammo (was 75%)
- irradiated drones can't get a slowing effect anymore
- it was just too annoying
- nano-scale can now unlock irradiated drone tech properly
- nano-scale now drains more energy per irradiated drone, to scale with the higher ammo costs
+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)
-time dilation field is now just called "time dilation"
-constraints under time dilation is less buggy, but still a bit buggy
+foam tech: uncertainty principle - foam bullets change position randomly, increase foam damage by 66%
-******************************************************** BUGS ********************************************************
-
-player can become crouched while not touching the ground if they exit the ground while crouched
-
-a couple times people have reported the final boss dropping extra bodies on death
-
-Why does micro-extruder lag so much
-
-blue triangle boss can move backwards and aim away from you if set up properly
- issues with dot product probably, but might not be worth fixing
-
-mouse event e.which is deprecated
-
-fix door.isOpen actually meaning isClosed?
-
-make it so that when you are immune to harm you can either jump on mobs or you pass through them
-
-is there a way to check if the player is stuck inside the map or block
- trigger a short term non-collide if that occurs
-
-(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause
-
-******************************************************** LEVELS ********************************************************
-
-labs - procedural generation
- bugs
- mob spawns shouldn't be based on probability?
- style
- graphics look too bright?
- add shadows and lighting and graphic details?
- what about performance?
- with the mobs staggered spawning it should be fine
- feel
- disrupt the flat ground
- less platforming / easier platforming
- the spinners on exit are still too hard...
- make combat more interesting
- is it laggy?
- in loot room, spawn mobs after power up is grabbed
- more background graphics, better colors
- loot room:
- make it more interesting to get the power up
- slow player and reduce damage in region
- increase the size of the region
- don't have space for much
- make graphics more unique
- push player away, so that normal pick up methods don't work, but add a button to disable region
- room ideas -
- portal room
- endlessly falling blocks down a slide, that the player has to climb up
- portal + rotor + falling blocks = perpetual motion
- slime room
- sound room, with buttons to control sound
- color room with r,g,b buttons to control color
- mob buff zone: Map element: "Orbital Pickup Zone": Mobs that enter a specific area of the map gain +1 orbital per second, or a shield
- could put in the loot room
-
-buttons can now on/off boosts
-
-repeat map in vertical when you fall teleport to above the mab, as if the map repeats
- camera looks strange when you teleport player with a high velocity
-
-map element - player rotates a rotor that makes a platform go up or down
-
-level element: a zone with wind, anti-gravity, extra gravity
- control with button
-
-map: observatory
- button controls rotation of telescope
- laser beam shoots out of telescope
- button opens the dome
-
-******************************************************** MOBS ********************************************************
-
-mob mechanics
- use the force at a location effect, like the plasma field
- Matter.Body.applyForce(who, path[1], force)
-
-mob - after taking damage
- release seekers
- teleports
-
-hop boss:
- AoE damage when landing
- pull in player? and blocks?
- extra gravity on falling?
- immune to damage while falling?
-
-mob: molecule shapes - 2 separate mobs joined by a bond
- use constraints: just spawn 2x or 3x groupings
- low friction so they can spin around
- spin when attacking player?
- increase constraint length when attacking
-
-mob vision: look at player history
- build a new type of attraction for mobs
- if mobs can't see player, they check to see if they can see where the player was in the history
- if mobs can't see player, they could check to see if they can find player in the past
- https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
- write find in spawn undo exploder, but commented out
-
-Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
- maybe it could be immune to damage? but it is spawned by an actual mob
-
-level Boss: fractal Sierpiński triangle
- https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
- spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level
- they spawn once at the start of the level
- if a version dies, one can be replaced every ten seconds by the largest version
-
-give mobs more animal-like behaviors like rain world
- mobs play, look for food, explore
- mobs some times aren't aggressive
- when low on life or after taking a large hit
- mobs can fight each other
- this might be hard to code
- isolated mobs try to group up
-
-mob: wall mounted guns / lasers
- not part of randomized mob pool, customized to each level
-
-level boss: fires a line intersection in a random direction every few seconds.
- the last two intersections have a destructive laser between them.
+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
******************************************************** TODO ********************************************************
-tech - shorter cloaking delay
-
-irradiated drones, get annoying when they go after mobs near the player...
- should they only follow mouse? or at least show a preference for targets near mouse, not near player
-
-tech - 1/2 your drone ammo/efficiency double the damage?
-
-tech foam teleports around, like a quantum wave function collapse
-
should ammo apply to all guns, or just one of your guns?
if one gun only, it would make multi-gun builds weaker
-nail bots should benefit from nail gun tech
-
-tech: picking up heal power ups at max health does harm, but increases max health
- scales with heal value
-
-let standing wave harmonics get tech decorrelation
-
-tech: cloaking field - decrease/increase cooldown on sneak attack?
- decrease/increase damage bonus?
- decrease/increase visual radius?
-
-have throw charge scale with fire delay
-
in testing mode console log the body you click on
throwing a block removes the block and rewinds time 10 seconds (including health and energy)
@@ -174,8 +23,6 @@ tech plasma : plasma length increases then decreases as you hold down the field
grows to 1.5 longer after 0.3 seconds, then returns to normal length over 1 second, until field is pressed again
extra energy is drained when field is longer
-tech: at the start of a new level remove 5 research and spawn a second boss
-
energy conservation 6% damage recovered as energy
add a negative effect:
junk tech
@@ -335,6 +182,129 @@ n-gon outreach ideas
hacker news - show hacker news post
twitch - lets play
+******************************************************** BUGS ********************************************************
+
+player can become crouched while not touching the ground if they exit the ground while crouched
+
+a couple times people have reported the final boss dropping extra bodies on death
+
+Why does micro-extruder lag so much
+
+blue triangle boss can move backwards and aim away from you if set up properly
+ issues with dot product probably, but might not be worth fixing
+
+mouse event e.which is deprecated
+
+fix door.isOpen actually meaning isClosed?
+
+make it so that when you are immune to harm you can either jump on mobs or you pass through them
+
+is there a way to check if the player is stuck inside the map or block
+ trigger a short term non-collide if that occurs
+
+(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause
+
+******************************************************** LEVELS ********************************************************
+
+labs - procedural generation
+ bugs
+ mob spawns shouldn't be based on probability?
+ style
+ graphics look too bright?
+ add shadows and lighting and graphic details?
+ what about performance?
+ with the mobs staggered spawning it should be fine
+ feel
+ disrupt the flat ground
+ less platforming / easier platforming
+ the spinners on exit are still too hard...
+ make combat more interesting
+ is it laggy?
+ in loot room, spawn mobs after power up is grabbed
+ more background graphics, better colors
+ loot room:
+ make it more interesting to get the power up
+ slow player and reduce damage in region
+ increase the size of the region
+ don't have space for much
+ make graphics more unique
+ push player away, so that normal pick up methods don't work, but add a button to disable region
+ room ideas -
+ portal room
+ endlessly falling blocks down a slide, that the player has to climb up
+ portal + rotor + falling blocks = perpetual motion
+ slime room
+ sound room, with buttons to control sound
+ color room with r,g,b buttons to control color
+ mob buff zone: Map element: "Orbital Pickup Zone": Mobs that enter a specific area of the map gain +1 orbital per second, or a shield
+ could put in the loot room
+
+buttons can now on/off boosts
+
+repeat map in vertical when you fall teleport to above the mab, as if the map repeats
+ camera looks strange when you teleport player with a high velocity
+
+map element - player rotates a rotor that makes a platform go up or down
+
+level element: a zone with wind, anti-gravity, extra gravity
+ control with button
+
+map: observatory
+ button controls rotation of telescope
+ laser beam shoots out of telescope
+ button opens the dome
+
+******************************************************** MOBS ********************************************************
+
+mob mechanics
+ use the force at a location effect, like the plasma field
+ Matter.Body.applyForce(who, path[1], force)
+
+mob - after taking damage
+ release seekers
+ teleports
+
+hop boss:
+ AoE damage when landing
+ pull in player? and blocks?
+ extra gravity on falling?
+ immune to damage while falling?
+
+mob: molecule shapes - 2 separate mobs joined by a bond
+ use constraints: just spawn 2x or 3x groupings
+ low friction so they can spin around
+ spin when attacking player?
+ increase constraint length when attacking
+
+mob vision: look at player history
+ build a new type of attraction for mobs
+ if mobs can't see player, they check to see if they can see where the player was in the history
+ if mobs can't see player, they could check to see if they can find player in the past
+ https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
+ write find in spawn undo exploder, but commented out
+
+Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
+ maybe it could be immune to damage? but it is spawned by an actual mob
+
+level Boss: fractal Sierpiński triangle
+ https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
+ spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level
+ they spawn once at the start of the level
+ if a version dies, one can be replaced every ten seconds by the largest version
+
+give mobs more animal-like behaviors like rain world
+ mobs play, look for food, explore
+ mobs some times aren't aggressive
+ when low on life or after taking a large hit
+ mobs can fight each other
+ this might be hard to code
+ isolated mobs try to group up
+
+mob: wall mounted guns / lasers
+ not part of randomized mob pool, customized to each level
+
+level boss: fires a line intersection in a random direction every few seconds.
+ the last two intersections have a destructive laser between them.
******************************************************** LORE ********************************************************
@@ -342,7 +312,6 @@ possible names for tech
strange loop
holonomy - parallel transport of a vector leads to movement (applies to curved space)
hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.
- uncertainty principle
swarm intelligence - for a drone tech
genetic algorithm
metaheuristic - is a higher-level procedure or heuristic designed to find, generate, or select a heuristic (partial search algorithm) that may provide a sufficiently good solution to an optimization problem, especially with incomplete or imperfect information or limited computation capacity