diff --git a/.DS_Store b/.DS_Store
index 34a581f..1bffd0b 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index 369394b..970a34f 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -2468,7 +2468,7 @@ const b = {
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0 &&
!mob[i].isShielded) {
- const SPEED = 45
+ const SPEED = 40
const unit = Vector.normalise(Vector.sub(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60)), this.position))
b.nail(this.position, Vector.mult(unit, SPEED), 0.4)
this.force = Vector.mult(unit, -0.01 * this.mass)
@@ -2611,8 +2611,8 @@ const b = {
lookFrequency: 40 + Math.floor(7 * Math.random()) - 10 * tech.isLaserBotUpgrade,
range: (700 + 400 * tech.isLaserBotUpgrade) * (1 + 0.1 * Math.random()),
drainThreshold: tech.isEnergyHealth ? 0.6 : 0.4,
- drain: 0.7 - 0.52 * tech.isLaserBotUpgrade,
- laserDamage: 0.38 + 0.29 * tech.isLaserBotUpgrade,
+ drain: 0.56 - 0.42 * tech.isLaserBotUpgrade,
+ laserDamage: 0.5 + 0.35 * tech.isLaserBotUpgrade,
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
@@ -3265,11 +3265,11 @@ const b = {
if (m.crouch) {
spread = 0.75
m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCD); // cool down
- if (tech.isShotgunImmune) m.immuneCycle = m.cycle + Math.floor(58 * b.fireCD); //player is immune to collision damage for 30 cycles
+ 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 collision 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); //player is immune to collision damage for 30 cycles
+ 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 collision damage for 30 cycles
spread = 1.3
knock = 0.1
}
@@ -4514,7 +4514,7 @@ const b = {
m.fireCDcycle = m.cycle + Math.floor(120 * b.fireCD); // cool down
} else {
m.energy -= DRAIN
- m.immuneCycle = m.cycle + 30; //player is immune to collision damage for 5 cycles
+ if (m.immuneCycle < m.cycle + 30) m.immuneCycle = m.cycle + 30; //player is immune to collision damage for 5 cycles
Matter.Body.setPosition(player, history.position);
Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
if (m.health !== history.health) {
diff --git a/js/engine.js b/js/engine.js
index c209c14..52ecb36 100644
--- a/js/engine.js
+++ b/js/engine.js
@@ -108,7 +108,20 @@ function collisionChecks(event) {
m.damage(dmg);
return
}
- m.damage(dmg);
+
+ if (tech.isAnthropicHarm) {
+ if (!tech.isAnthropicHarmImmune) {
+ tech.isAnthropicHarmImmune = true
+ if (document.getElementById("tech-flip-flop")) document.getElementById("tech-flip-flop").innerHTML = ` = on`
+ m.damage(dmg * 1.25); //damage triggers immune to next hit with extra 10% damage
+ } else {
+ tech.isAnthropicHarmImmune = false //immune to damage this hit, lose immunity for next hit
+ if (document.getElementById("tech-flip-flop")) document.getElementById("tech-flip-flop").innerHTML = ` = off`
+ }
+ } else {
+ m.damage(dmg); //normal damage
+ }
+
if (tech.isPiezo) m.energy += 20.48;
if (tech.isBayesian) powerUps.ejectTech()
if (mob[k].onHit) mob[k].onHit(k);
diff --git a/js/level.js b/js/level.js
index fbcc566..eaa6114 100644
--- a/js/level.js
+++ b/js/level.js
@@ -12,7 +12,7 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
- // level.difficultyIncrease(40)
+ // level.difficultyIncrease(5)
// simulation.zoomScale = 1000;
// simulation.setZoom();
// m.setField("nano-scale manufacturing")
@@ -792,7 +792,7 @@ const level = {
} else {
if (damage < 0.02) {
m.damage(damage)
- } else if (m.immuneCycle < m.cycle) {
+ } else if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles;
m.damage(damage)
simulation.drawList.push({ //add dmg to draw queue
@@ -1090,7 +1090,7 @@ const level = {
// spawn.boost(1500, 0, 900);
// spawn.starter(1900, -500, 200) //big boy
- // spawn.starter(1900, -500)
+ spawn.starter(1900, -500)
// spawn.historyBoss(1900, -500)
// spawn.ghoster(2900, -500)
// spawn.launcherBoss(1200, -500)
@@ -1103,12 +1103,12 @@ const level = {
// spawn.cellBossCulture(1600, -500)
// spawn.cellBossCulture(1600, -500)
// simulation.difficulty = 30
- spawn.orbitalBoss(1600, -500)
+ spawn.shieldingBoss(1600, -500)
// spawn.beamer(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1);
// spawn.nodeGroup(1200, -500, "launcher")
- // spawn.snakeBoss(1200, -500)
+ spawn.snakeBoss(1200, -500)
// spawn.powerUpBoss(2900, -500)
// spawn.randomMob(1600, -500)
},
@@ -1698,16 +1698,16 @@ const level = {
spawn.randomMob(-75, -1475, 0);
spawn.randomGroup(600, -2600, 0);
}
- if (simulation.difficulty < 25) {
+ if (simulation.difficulty < 20) {
spawn.randomMob(700, -1650, 0);
spawn.randomMob(600, -3500, 0.2);
spawn.randomMob(-75, -1175, 0.2);
powerUps.spawnBossPowerUp(-125, -1760);
} else {
if (Math.random() < 0.5) {
- spawn.randomLevelBoss(700, -1550, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]);
+ spawn.randomLevelBoss(700, -1550, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss"]);
} else {
- spawn.randomLevelBoss(675, -2775, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]);
+ spawn.randomLevelBoss(675, -2775, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss"]);
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
@@ -1854,7 +1854,7 @@ const level = {
spawn.randomMob(3600, 1725, 0.9);
spawn.randomMob(4100, 1225, 0.9);
spawn.randomMob(2825, 400, 0.9);
- if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss", "orbitalBoss"]);
+ if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss", "orbitalBoss", "shieldingBoss"]);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275);
},
@@ -2459,17 +2459,7 @@ const level = {
if (simulation.difficulty > 3) {
if (Math.random() < 0.1) { // tether ball
const index = mob.length
- spawn.tetherBoss(4250, 0)
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 4250,
- y: -675
- },
- bodyB: mob[index],
- stiffness: 0.00007
- });
- World.add(engine.world, cons[cons.length - 1]);
-
+ spawn.tetherBoss(4250, 0, { x: 4250, y: -675 })
if (simulation.difficulty > 4) spawn.nodeGroup(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss
} else if (Math.random() < 0.2) {
spawn.randomLevelBoss(4250, -250);
@@ -3214,16 +3204,7 @@ const level = {
height: 525,
color: "#ccc"
});
- spawn.tetherBoss(2850, -80)
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 2500,
- y: -500
- },
- bodyB: mob[mob.length - 1],
- stiffness: 0.00012
- });
- World.add(engine.world, cons[cons.length - 1]);
+ spawn.tetherBoss(2850, -80, { x: 2500, y: -500 })
//chance to spawn a ring of exploding mobs around this boss
if (simulation.difficulty > 6) spawn.nodeGroup(2850, -80, "spawns", 8, 20, 105);
} else {
@@ -3690,16 +3671,7 @@ const level = {
if (simulation.difficulty > 2) {
if (Math.random() < 0.2) {
// tether ball
- spawn.tetherBoss(7000, -3300)
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 7300,
- y: -3300
- },
- bodyB: mob[mob.length - 1],
- stiffness: 0.00006
- });
- World.add(engine.world, cons[cons.length - 1]);
+ spawn.tetherBoss(7000, -3300, { x: 7300, y: -3300 })
if (simulation.difficulty > 4) spawn.nodeGroup(7000, -3300, "spawns", 8, 20, 105);
} else if (simulation.difficulty > 3) {
spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss"]);
@@ -3709,16 +3681,7 @@ const level = {
if (simulation.difficulty > 2) {
if (Math.random() < 0.2) {
// tether ball
- spawn.tetherBoss(2300, -1300)
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 2300,
- y: -1750
- },
- bodyB: mob[mob.length - 1],
- stiffness: 0.00036
- });
- World.add(engine.world, cons[cons.length - 1]);
+ spawn.tetherBoss(2300, -1300, { x: 2300, y: -1750 })
if (simulation.difficulty > 4) spawn.nodeGroup(2350, -1300, "spawns", 8, 20, 105);
} else if (simulation.difficulty > 3) {
spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "snakeBoss"]);
@@ -3785,16 +3748,7 @@ const level = {
spawn.mapRect(3075, 1075, 375, 150); //Plafond salle trésor
spawn.mapRect(3300, 1075, 1500, 1800); //Mur droite salle trésor
// tether ball
- spawn.tetherBoss(2330, 1850)
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 2330,
- y: 1425
- },
- bodyB: mob[mob.length - 1],
- stiffness: 0.00017
- });
- World.add(engine.world, cons[cons.length - 1]);
+ spawn.tetherBoss(2330, 1850, { x: 2330, y: 1425 })
//chance to spawn a ring of exploding mobs around this boss
if (simulation.difficulty > 4) spawn.nodeGroup(2330, 1850, "spawns", 8, 20, 105);
powerUps.chooseRandomPowerUp(3100, 1630);
@@ -4062,34 +4016,25 @@ const level = {
spawn.randomGroup(8025, -845, 0.2);
if (simulation.difficulty > 2) {
- if (Math.random() < 0.2) {
- // tether ball
- spawn.tetherBoss(8000, 630)
- let me = mob[mob.length - 1];
- me.onDeath = function() {
- this.removeCons(); //remove constraint
- spawnCouloirEnHaut()
- doorSortieSalle.isOpen = false;
- };
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 8550,
- y: 680
- },
- bodyB: mob[mob.length - 1],
- stiffness: 0.00015
- });
- World.add(engine.world, cons[cons.length - 1]);
- if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105);
- } else {
- spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss", "orbitalBoss"]);
- let me = mob[mob.length - 1];
- me.onDeath = function() {
- this.removeCons(); //remove constraint
- spawnCouloirEnHaut()
- doorSortieSalle.isOpen = false;
- };
- }
+ // if (Math.random() < 0.2) {
+ // // tether ball
+ // spawn.tetherBoss(8000, 630, { x: 8550, y: 680 })
+ // let me = mob[mob.length - 1];
+ // me.onDeath = function() {
+ // this.removeCons(); //remove constraint
+ // spawnCouloirEnHaut()
+ // doorSortieSalle.isOpen = false;
+ // };
+ // if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105);
+ // } else {
+ spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss", "orbitalBoss"]);
+ let me = mob[mob.length - 1];
+ me.onDeath = function() {
+ this.removeCons(); //remove constraint
+ spawnCouloirEnHaut()
+ doorSortieSalle.isOpen = false;
+ };
+ // }
} else {
spawn.randomLevelBoss(8000, 630, ["shooterBoss"]);
let me = mob[mob.length - 1];
@@ -4658,18 +4603,8 @@ const level = {
if (simulation.difficulty > 3) {
if (Math.random() < 0.16) {
- spawn.tetherBoss(3380, -1775)
- cons[cons.length] = Constraint.create({
- pointA: {
- x: 3775,
- y: -1775
- },
- bodyB: mob[mob.length - 1],
- stiffness: 0.00018 + 0.000007 * level.levelsCleared
- });
- World.add(engine.world, cons[cons.length - 1]);
+ spawn.tetherBoss(3380, -1775, { x: 3775, y: -1775 })
if (simulation.difficulty > 4) spawn.nodeGroup(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss
-
} else {
spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "snakeBoss", "laserBoss"]);
}
diff --git a/js/mob.js b/js/mob.js
index 28f3584..2e78b5c 100644
--- a/js/mob.js
+++ b/js/mob.js
@@ -651,25 +651,27 @@ const mobs = {
//cause all mobs, and bodies to rotate in a circle
applyCurl = function(center, array, isAntiGravity = true) {
for (let i = 0; i < array.length; ++i) {
- const sub = Vector.sub(center, array[i].position)
- const radius2 = Vector.magnitudeSquared(sub);
+ if (!array[i].isNotHoldable) {
+ const sub = Vector.sub(center, array[i].position)
+ const radius2 = Vector.magnitudeSquared(sub);
- //if too close, like center mob or shield, don't curl // if too far don't curl
- if (radius2 < range * range && radius2 > 10000) {
- const curlVector = Vector.mult(Vector.perp(Vector.normalise(sub)), mag)
- //apply curl force
- Matter.Body.setVelocity(array[i], {
- x: array[i].velocity.x * 0.94 + curlVector.x * 0.06,
- y: array[i].velocity.y * 0.94 + curlVector.y * 0.06
- })
- if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass
- // //draw curl, for debugging
- // ctx.beginPath();
- // ctx.moveTo(array[i].position.x, array[i].position.y);
- // ctx.lineTo(array[i].position.x + curlVector.x * 10, array[i].position.y + curlVector.y * 10);
- // ctx.lineWidth = 2;
- // ctx.strokeStyle = "#000";
- // ctx.stroke();
+ //if too close, like center mob or shield, don't curl // if too far don't curl
+ if (radius2 < range * range && radius2 > 10000) {
+ const curlVector = Vector.mult(Vector.perp(Vector.normalise(sub)), mag)
+ //apply curl force
+ Matter.Body.setVelocity(array[i], {
+ x: array[i].velocity.x * 0.94 + curlVector.x * 0.06,
+ y: array[i].velocity.y * 0.94 + curlVector.y * 0.06
+ })
+ if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass
+ // //draw curl, for debugging
+ // ctx.beginPath();
+ // ctx.moveTo(array[i].position.x, array[i].position.y);
+ // ctx.lineTo(array[i].position.x + curlVector.x * 10, array[i].position.y + curlVector.y * 10);
+ // ctx.lineWidth = 2;
+ // ctx.strokeStyle = "#000";
+ // ctx.stroke();
+ }
}
}
}
@@ -1050,7 +1052,7 @@ const mobs = {
bullet[bullet.length - 1].endCycle = simulation.cycle + 1000 + Math.floor(400 * Math.random())
this.leaveBody = false; // no body since it turned into the bot
}
- } else if (tech.isShieldAmmo && this.shield) {
+ } else if (tech.isShieldAmmo && this.shield && !this.isBonusShield) {
let type = tech.isEnergyNoAmmo ? "heal" : "ammo"
if (Math.random() < 0.4) {
type = "heal"
diff --git a/js/player.js b/js/player.js
index 92556bb..7f1a602 100644
--- a/js/player.js
+++ b/js/player.js
@@ -570,7 +570,7 @@ const m = {
}
}
m.energy = Math.max(m.energy - steps / 136, 0.01)
- m.immuneCycle = m.cycle + 30; //player is immune to collision damage for 30 cycles
+ if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
let isDrawPlayer = true
const shortPause = function() {
@@ -642,7 +642,7 @@ const m = {
simulation.makeTextLog(`m.research--
${powerUps.research.count}`)
for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x, m.pos.y, "heal", false);
m.energy = m.maxEnergy
- m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds
+ if (m.immuneCycle < m.cycle + 360) m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds
simulation.wipe = function() { //set wipe to have trails
ctx.fillStyle = "rgba(255,255,255,0.03)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
@@ -671,7 +671,7 @@ const m = {
simulation.makeTextLog(`m.research--
${powerUps.research.count}`)
for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "heal", false);
- m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds
+ if (m.immuneCycle < m.cycle + 360) m.immuneCycle = m.cycle + 360 //disable this.immuneCycle bonus seconds
simulation.wipe = function() { //set wipe to have trails
ctx.fillStyle = "rgba(255,255,255,0.03)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
@@ -1777,7 +1777,7 @@ const m = {
simulation.cycle--; //pause all functions that depend on game cycle increasing
if (tech.isTimeSkip) {
- m.immuneCycle = m.cycle + 10;
+ if (m.immuneCycle < m.cycle + 10) m.immuneCycle = m.cycle + 10;
simulation.isTimeSkipping = true;
m.cycle++;
simulation.gravity();
@@ -2537,7 +2537,7 @@ const m = {
x: velocity.x,
y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
});
- m.immuneCycle = m.cycle + 15; //player is immune to collision damage
+ if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage
// move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
@@ -2813,7 +2813,7 @@ const m = {
if (tech.isPiezo) m.energy += 20.48;
if (tech.isBayesian) powerUps.ejectTech()
if (mob[k].onHit) mob[k].onHit(k);
- m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
+ if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
//extra kick between player and mob //this section would be better with forces but they don't work...
let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x);
Matter.Body.setVelocity(player, {
diff --git a/js/powerup.js b/js/powerup.js
index 92c7863..6166064 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -70,7 +70,7 @@ const powerUps = {
document.body.style.overflow = "hidden"
simulation.paused = false;
simulation.isChoosing = false; //stops p from un pausing on key down
- m.immuneCycle = m.cycle + 60; //player is immune to collision damage for 30 cycles
+ if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
build.unPauseGrid()
requestAnimationFrame(cycle);
},
diff --git a/js/simulation.js b/js/simulation.js
index 9edb2ee..c783191 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -1002,7 +1002,7 @@ const simulation = {
//ctx.fillText(bodies[i].id,bodies[i].position.x,bodies[i].position.y); //shows the id of every body
let vertices = bodies[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
- for (let j = 1; j < vertices.length; j += 1) {
+ for (let j = 1; j < vertices.length; j++) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
diff --git a/js/spawn.js b/js/spawn.js
index 0d53a54..0dcda91 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -82,8 +82,8 @@ const spawn = {
}
}
},
- //, "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"
- randomLevelBoss(x, y, options = ["orbitalBoss"]) {
+ //
+ randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"]) {
// 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)
},
@@ -437,7 +437,7 @@ const spawn = {
vertexCollision(where, look, body);
if (!m.isCloak) vertexCollision(where, look, [player]);
if (best.who && best.who === player && m.immuneCycle < m.cycle) {
- m.immuneCycle = m.cycle + 60 + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
+ if (m.immuneCycle < m.cycle + 60 + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + 60 + tech.collisionImmuneCycles; //player is immune to collision damage extra time
m.damage(dmg);
simulation.drawList.push({ //add dmg to draw queue
x: best.x,
@@ -1623,7 +1623,7 @@ const spawn = {
vertexCollision(where, look, body);
if (!m.isCloak) vertexCollision(where, look, [player]);
if (best.who && best.who === player && m.immuneCycle < m.cycle) {
- m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
+ m.immuneCycle = m.cycle + tech.collisionImmuneCycles + 60; //player is immune to collision damage for an extra second
const dmg = 0.14 * simulation.dmgScale;
m.damage(dmg);
simulation.drawList.push({ //add dmg to draw queue
@@ -1776,9 +1776,8 @@ const spawn = {
};
},
sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 20)) {
- let me;
mobs.spawn(x, y, 5, radius, "transparent");
- me = mob[mob.length - 1];
+ let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
me.accelMag = 0.001 * simulation.accelScale;
me.frictionAir = 0.01;
@@ -1828,9 +1827,8 @@ const spawn = {
};
},
ghoster(x, y, radius = 40 + Math.ceil(Math.random() * 100)) {
- let me;
mobs.spawn(x, y, 7, radius, "transparent");
- me = mob[mob.length - 1];
+ let me = mob[mob.length - 1];
me.seeAtDistance2 = 300000;
me.accelMag = 0.00012 * simulation.accelScale;
if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
@@ -2321,6 +2319,62 @@ const spawn = {
}
};
},
+ shieldingBoss(x, y, radius = 210) {
+ mobs.spawn(x, y, 9, radius, "rgb(150, 150, 255)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, Math.random() * 2 * Math.PI)
+ // me.stroke = "rgb(220,220,255)"
+ me.isBoss = true;
+ me.cycle = 0
+ me.maxCycles = 120;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.5;
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
+
+ Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function() {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
+ };
+ me.onDamage = function() {};
+ me.do = function() {
+ this.checkStatus();
+
+ //draw cycle timer
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[this.vertices.length - 1].x, this.vertices[this.vertices.length - 1].y)
+ const phase = (this.vertices.length + 1) * this.cycle / this.maxCycles
+ if (phase > 1) ctx.lineTo(this.vertices[0].x, this.vertices[0].y)
+ for (let i = 1; i < phase - 1; i++) {
+ ctx.lineTo(this.vertices[i].x, this.vertices[i].y)
+ }
+ ctx.lineWidth = 5
+ ctx.strokeStyle = "rgb(255,255,255)"
+ ctx.stroke();
+
+ if (!m.isBodiesAsleep) {
+ this.cycle++
+ if (this.cycle > this.maxCycles) {
+ this.cycle = 0
+ ctx.beginPath();
+ for (let i = 0; i < mob.length; i++) {
+ if (!mob[i].isShielded && !mob[i].shield && mob[i].dropPowerUp) {
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.lineTo(mob[i].position.x, mob[i].position.y)
+
+ spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
+ }
+ }
+ ctx.lineWidth = 20
+ // ctx.lineCap = "round";
+ ctx.strokeStyle = "rgba(200,200,255,0.9)"
+ ctx.stroke();
+ }
+ }
+ };
+ },
streamBoss(x, y, radius = 110) {
mobs.spawn(x, y, 5, radius, "rgb(245,180,255)");
let me = mob[mob.length - 1];
@@ -2492,7 +2546,6 @@ const spawn = {
me.memory = 250;
me.laserRange = 500;
Matter.Body.setDensity(me, 0.0015 + 0.0005 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
- spawn.shield(me, x, y, 1);
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < mob.length; i++) { //wake up tail mobs
@@ -2532,9 +2585,10 @@ const spawn = {
stiffness: 0.05
});
World.add(engine.world, consBB[consBB.length - 1]);
+ spawn.shield(me, x, y, 1);
},
snakeBody(x, y, radius = 14) {
- mobs.spawn(x, y, 8, radius, "transparent");
+ mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
let me = mob[mob.length - 1];
// me.onHit = function() {
// //run this function on hitting player
@@ -2545,7 +2599,7 @@ const spawn = {
me.leaveBody = false;
me.frictionAir = 0.02;
me.isSnakeTail = true;
- me.stroke = "#099"
+ me.stroke = "transparent"
me.onDeath = function() {
if (this.isSnakeTail) { //wake up tail mobs
@@ -2567,7 +2621,7 @@ const spawn = {
this.attraction();
};
},
- tetherBoss(x, y, radius = 90) {
+ tetherBoss(x, y, constraint, radius = 90) {
// constrained mob boss for the towers level
// often has a ring of mobs around it
mobs.spawn(x, y, 8, radius, "rgb(0,60,80)");
@@ -2577,8 +2631,18 @@ const spawn = {
me.accelMag = 0.002 * simulation.accelScale;
me.memory = 20;
Matter.Body.setDensity(me, 0.001 + 0.0005 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
- spawn.shield(me, x, y, 1);
+
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: constraint.x,
+ y: constraint.y
+ },
+ bodyB: me,
+ stiffness: 0.00012
+ });
+ World.add(engine.world, cons[cons.length - 1]);
+ spawn.shield(me, x, y, 1);
setTimeout(() => { spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
@@ -2591,13 +2655,14 @@ const spawn = {
this.attraction();
};
},
- shield(target, x, y, chance = Math.min(0.02 + simulation.difficulty * 0.005, 0.2)) {
+ shield(target, x, y, chance = Math.min(0.02 + simulation.difficulty * 0.005, 0.2), isBonusShield = false) {
if (this.allowShields && Math.random() < chance) {
mobs.spawn(x, y, 9, target.radius + 30, "rgba(220,220,255,0.9)");
let me = mob[mob.length - 1];
me.stroke = "rgb(220,220,255)";
Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
me.shield = true;
+ me.isBonusShield = isBonusShield //this prevents spamming with tech.isShieldAmmo
me.collisionFilter.category = cat.mobShield
me.collisionFilter.mask = cat.bullet;
consBB[consBB.length] = Constraint.create({
@@ -2625,12 +2690,16 @@ const spawn = {
if (mob[i].id === this.shieldTargetID) mob[i].isShielded = false;
}
};
- //swap order of shield and mob, so that mob is behind shield graphically
- mob[mob.length - 1] = mob[mob.length - 2];
- mob[mob.length - 2] = me;
me.do = function() {
this.checkStatus();
};
+
+ //move shield to the front of the array, so that mob is behind shield graphically
+ mob.unshift(me);
+
+ //swap order of shield and mob, so that mob is behind shield graphically
+ // mob[mob.length - 1] = mob[mob.length - 2];
+ // mob[mob.length - 2] = me;
}
},
groupShield(targets, x, y, radius, stiffness = 0.4) {
diff --git a/js/tech.js b/js/tech.js
index 322c82b..1018090 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -95,13 +95,12 @@
haveGunCheck(name) {
if (
!build.isExperimentSelection &&
- b.inventory.length > 2 &&
+ b.inventory > 2 &&
name !== b.guns[b.activeGun].name &&
- Math.random() > 2 / (b.inventory.length + tech.isGunCycle * 3) //lower chance of tech specific to a gun if you have lots of guns
+ Math.random() > 2 - b.inventory.length * 0.5
) {
return false
}
-
for (i = 0, len = b.inventory.length; i < len; i++) {
if (b.guns[b.inventory[i]].name === name) return true
}
@@ -1164,10 +1163,10 @@
requires: "",
effect() {
tech.collisionImmuneCycles += 45;
- m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
+ if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
},
remove() {
- tech.collisionImmuneCycles = 25;
+ tech.collisionImmuneCycles = 30;
}
},
{
@@ -1186,6 +1185,84 @@
tech.cyclicImmunity = 0;
}
},
+ {
+ name: "flip-flop",
+ description: "after a collision take 25% more harm
but, on your next collision take 0 harm",
+ nameInfo: "",
+ addNameInfo() {
+ setTimeout(function() {
+ if (document.getElementById("tech-flip-flop")) {
+ if (tech.isAnthropicHarmImmune) {
+ document.getElementById("tech-flip-flop").innerHTML = ` = on`
+ } else {
+ document.getElementById("tech-flip-flop").innerHTML = ` = off`
+ }
+ }
+ }, 100);
+ },
+ maxCount: 1,
+ count: 0,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isAnthropicHarm = true //do you have this tech
+ tech.isAnthropicHarmImmune = false //are you immune to next collision
+ },
+ remove() {
+ tech.isAnthropicHarm = false
+ tech.isAnthropicHarmImmune = false
+ }
+ },
+ {
+ name: "clock gating",
+ description: `slow time by 50% after receiving harm
reduce harm by 20%`,
+ maxCount: 1,
+ count: 0,
+ allowed() {
+ return simulation.fpsCapDefault > 45 && !tech.isRailTimeSlow
+ },
+ requires: "FPS above 45",
+ effect() {
+ tech.isSlowFPS = true;
+ },
+ remove() {
+ tech.isSlowFPS = false;
+ }
+ },
+ {
+ name: "liquid cooling",
+ description: `freeze all mobs for 7 seconds
after receiving harm`,
+ maxCount: 1,
+ count: 0,
+ allowed() {
+ return tech.isSlowFPS
+ },
+ requires: "clock gating",
+ effect() {
+ tech.isHarmFreeze = true;
+ },
+ remove() {
+ tech.isHarmFreeze = false;
+ }
+ },
+ {
+ name: "osmoprotectant",
+ description: `collisions with stunned or frozen mobs
cause you no harm`,
+ maxCount: 1,
+ count: 0,
+ allowed() {
+ return tech.isStunField || tech.isPulseStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage
+ },
+ requires: "a freezing or stunning effect",
+ effect() {
+ tech.isFreezeHarmImmune = true;
+ },
+ remove() {
+ tech.isFreezeHarmImmune = false;
+ }
+ },
{
name: "ablative drones",
description: "rebuild your broken parts as drones
chance to occur after receiving harm",
@@ -1237,54 +1314,6 @@
tech.isHarmDamage = false;
}
},
- {
- name: "liquid cooling",
- description: `freeze all mobs for 7 seconds
after receiving harm`,
- maxCount: 1,
- count: 0,
- allowed() {
- return tech.isSlowFPS
- },
- requires: "clock gating",
- effect() {
- tech.isHarmFreeze = true;
- },
- remove() {
- tech.isHarmFreeze = false;
- }
- },
- {
- name: "osmoprotectant",
- description: `collisions with stunned or frozen mobs
cause you no harm`,
- maxCount: 1,
- count: 0,
- allowed() {
- return tech.isStunField || tech.isPulseStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage
- },
- requires: "a freezing or stunning effect",
- effect() {
- tech.isFreezeHarmImmune = true;
- },
- remove() {
- tech.isFreezeHarmImmune = false;
- }
- },
- {
- name: "clock gating",
- description: `slow time by 50% after receiving harm
reduce harm by 20%`,
- maxCount: 1,
- count: 0,
- allowed() {
- return simulation.fpsCapDefault > 45 && !tech.isRailTimeSlow
- },
- requires: "FPS above 45",
- effect() {
- tech.isSlowFPS = true;
- },
- remove() {
- tech.isSlowFPS = false;
- }
- },
{
name: "CPT reversal",
description: "charge, parity, and time invert to undo harm
rewind (1.5—5) seconds for (66—220) energy",
@@ -1339,7 +1368,7 @@
maxCount: 1,
count: 0,
allowed() {
- return !tech.isEnergyHealth && m.harmReduction() < 1
+ return !tech.isEnergyHealth && (m.harmReduction() < 1 || tech.isAnthropicHarm)
},
requires: "not mass-energy equivalence, some harm reduction",
effect() {
@@ -1860,7 +1889,7 @@
},
{
name: "decoherence",
- description: "enter an alternate reality after you research
spawn 9 research",
+ description: "enter an alternate reality after you research
spawn 11 research",
maxCount: 1,
count: 0,
allowed() {
@@ -1869,7 +1898,7 @@
requires: "not quantum immortality, many-worlds",
effect() {
tech.isResearchReality = true;
- for (let i = 0; i < 9; i++) powerUps.spawn(m.pos.x + Math.random() * 10, m.pos.y + Math.random() * 10, "research", false);
+ for (let i = 0; i < 11; i++) powerUps.spawn(m.pos.x + Math.random() * 10, m.pos.y + Math.random() * 10, "research", false);
},
remove() {
tech.isResearchReality = false;
@@ -2011,7 +2040,7 @@
},
{
name: "bubble fusion",
- description: "after destroying a mob's shield
spawn 1-2 heals, ammo, or research",
+ description: "after destroying a mob's natural shield
spawn 1-2 heals, ammo, or research",
maxCount: 1,
count: 0,
allowed() {
@@ -4307,7 +4336,7 @@
},
{
name: "ship",
- description: "experimental mode: fly around with no legs
aim by rotating with keyboard",
+ description: "experiment: fly around with no legs
aim by rotating with keyboard",
maxCount: 1,
count: 0,
isNonRefundable: true,
@@ -4324,7 +4353,7 @@
},
{
name: "quantum leap",
- description: "experimental mode: every 20 seconds
become an alternate version of yourself",
+ description: "experiment: every 20 seconds
become an alternate version of yourself",
maxCount: 1,
count: 0,
isNonRefundable: true,
@@ -5373,5 +5402,7 @@
isHarmReduceAfterKill: null,
isSwitchReality: null,
isResearchReality: null,
- isAnthropicDamage: null
+ isAnthropicDamage: null,
+ isAnthropicHarm: null,
+ isAnthropicHarmImmune: null
}
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index e9ef8f7..289f6ce 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,14 +1,19 @@
******************************************************** NEXT PATCH ********************************************************
-mob orbitals can now be destroyed, but it takes a very large amount of damage
+shieldingBoss - doesn't attack, but shields all mobs every 2.5s
-laser-bot upgrade: gives 75% damage, range, and energy efficiency (was 400% damage, but they ran out of energy too fast)
-boom-bots are now smart about not hurting the player with explosions while doing the most damage
+reworked how tetherBoss's constraint work
+ please, let me know if the tether boss is buggy on any of the levels
+ the chance for tether boss was removed from level: detours
+
+tech: flip-flop - collisions do 25% more harm, but you become immune to harm for the next collision
-tech: strong anthropic principle - after anthropic principle prevents your death do 137.03599 extra damage for the rest of the level
******************************************************** BUGS ********************************************************
+shields being put in front of mob array messes up some types of index = mob.length-1 uses
+adding orbitals puts a random # of mobs in front of target, and shield behind
+
use the floor of portal sensor on the player? to unstuck player
(only once on my computer) once every 7 second check isn't running code
@@ -35,9 +40,6 @@ use the floor of portal sensor on the player? to unstuck player
******************************************************** TODO ********************************************************
-tech: after using anthropic principle do 200% more damage for the rest of the level
-
-
use ship tech to make a mob mode
differences from ship to mob
graphics
@@ -58,12 +60,6 @@ bosses should have 2x health, but only do about 50 health damage
tech: spawn a bot after taking collision damage
-tech: standing wave freezes the mobs it hits
-
-tech: health becomes drones
- requires mass-energy?
- junk tech?
-
map: laboratory
rooms with switches that change physics
gravity room
@@ -373,7 +369,7 @@ possible names for tech
perturbation theory
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
chapter 1: bot can hear audio and learns testing mode
bot uses testing mode to exit room