diff --git a/js/bullet.js b/js/bullet.js
index 1789b7e..6480b49 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -1713,7 +1713,7 @@ const b = {
friction: 0,
frictionAir: 0.025,
thrust: (tech.isFastSpores ? 0.001 : 0.0004) * (1 + 0.3 * (Math.random() - 0.5)),
- dmg: tech.isMutualism ? 10 : 4, //2x bonus damage from tech.isMutualism
+ dmg: tech.isMutualism ? 12 : 5, //bonus damage from tech.isMutualism
lookFrequency: 100 + Math.floor(117 * Math.random()),
classType: "bullet",
collisionFilter: {
@@ -1722,7 +1722,7 @@ const b = {
},
endCycle: simulation.cycle + Math.floor((600 + Math.floor(Math.random() * 420)) * tech.isBulletsLastLonger),
minDmgSpeed: 0,
- playerOffPosition: { //used when following player to keep spores separate
+ playerOffPosition: { //used when moving towards player to keep spores separate
x: 100 * (Math.random() - 0.5),
y: 100 * (Math.random() - 0.5)
},
@@ -2223,6 +2223,7 @@ const b = {
// **************************************************************************************************
// **************************************************************************************************
respawnBots() {
+ for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({ x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }, false)
for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({ x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }, false)
for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({ x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }, false)
for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({ x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }, false)
@@ -2237,7 +2238,10 @@ const b = {
}
},
randomBot(where = m.pos, isKeep = true, isAll = true) {
- if (Math.random() < 0.2 && isAll) {
+ if (Math.random() < 0.167 && isAll) {
+ b.dynamoBot(where)
+ if (isKeep) tech.dynamoBotCount++;
+ } else if (Math.random() < 0.25 && isAll) {
b.laserBot(where)
if (isKeep) tech.laserBotCount++;
} else if (Math.random() < 0.25 && isAll) {
@@ -2254,6 +2258,113 @@ const b = {
if (isKeep) tech.boomBotCount++;
}
},
+ setDynamoBotDelay() {
+ //reorder orbital bot positions around a circle
+ let total = 0
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') total++
+ }
+ let count = 0
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') {
+ count++
+ const step = Math.max(60 - 3 * total, 20)
+ bullet[i].followDelay = (step * count) % 600
+ }
+ }
+ },
+ dynamoBot(position = m.pos, isConsole = true) {
+ if (isConsole) simulation.makeTextLog(`b.dynamoBot()`);
+ const me = bullet.length;
+ bullet[me] = Bodies.polygon(position.x, position.y, 5, 10, {
+ isUpgraded: tech.isDynamoBotUpgrade,
+ botType: "dynamo",
+ friction: 0,
+ frictionStatic: 0,
+ frictionAir: 1,
+ isStatic: true,
+ isSensor: true,
+ restitution: 0,
+ dmg: 0, // 0.14 //damage done in addition to the damage from momentum
+ minDmgSpeed: 0,
+ endCycle: Infinity,
+ classType: "bullet",
+ collisionFilter: {
+ category: cat.bullet,
+ mask: 0 //cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield
+ },
+ beforeDmg() {},
+ onEnd() {
+ b.setDynamoBotDelay()
+ },
+ followDelay: 0,
+ phase: Math.floor(60 * Math.random()),
+ do() {
+ // if (Vector.magnitude(Vector.sub(this.position, m.pos)) < 150) {
+ // ctx.fillStyle = "rgba(0,0,0,0.06)";
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, 150, 0, 2 * Math.PI);
+ // ctx.fill();
+ // }
+ if (!((m.cycle + this.phase) % 30)) { //twice a second
+ if (Vector.magnitude(Vector.sub(this.position, m.pos)) < 250) { //give energy
+ // Matter.Body.setAngularVelocity(this, 10)
+ if (this.isUpgraded) {
+ m.energy += 0.06
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 8,
+ color: m.fieldMeterColor,
+ time: simulation.drawTime
+ });
+ } else {
+ m.energy += 0.02
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 5,
+ color: m.fieldMeterColor,
+ time: simulation.drawTime
+ });
+ }
+ }
+ }
+ //check for damage
+ if (!m.isCloak && !m.isBodiesAsleep) { //if time dilation isn't active
+ const size = 33
+ q = Matter.Query.region(mob, {
+ min: {
+ x: this.position.x - size,
+ y: this.position.y - size
+ },
+ max: {
+ x: this.position.x + size,
+ y: this.position.y + size
+ }
+ })
+ for (let i = 0; i < q.length; i++) {
+ // mobs.statusStun(q[i], 180)
+ // const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 2.5 : 1)
+ const dmg = 0.5 * b.dmgScale
+ q[i].damage(dmg);
+ q[i].foundPlayer();
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.log(2 * dmg + 1.1) * 40,
+ color: 'rgba(0,0,0,0.4)',
+ time: simulation.drawTime
+ });
+ }
+ }
+ let history = m.history[(m.cycle - this.followDelay) % 600]
+ Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
+ }
+ })
+ World.add(engine.world, bullet[me]); //add bullet to world
+ b.setDynamoBotDelay()
+ },
nailBot(position = { x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }, isConsole = true) {
if (isConsole) simulation.makeTextLog(`b.nailBot()`);
const me = bullet.length;
@@ -2435,7 +2546,7 @@ const b = {
drainThreshold: tech.isEnergyHealth ? 0.5 : 0.33,
acceleration: 0.0015 * (1 + 0.3 * Math.random()),
range: 700 * (1 + 0.1 * Math.random()) + 300 * tech.isLaserBotUpgrade,
- followRange: 150 + Math.floor(30 * Math.random()),
+ playerRange: 150 + Math.floor(30 * Math.random()),
offPlayer: {
x: 0,
y: 0,
@@ -2453,7 +2564,7 @@ const b = {
onEnd() {},
do() {
const playerPos = Vector.add(Vector.add(this.offPlayer, m.pos), Vector.mult(player.velocity, 20)) //also include an offset unique to this bot to keep many bots spread out
- const farAway = Math.max(0, (Vector.magnitude(Vector.sub(this.position, playerPos))) / this.followRange) //linear bounding well
+ const farAway = Math.max(0, (Vector.magnitude(Vector.sub(this.position, playerPos))) / this.playerRange) //linear bounding well
const mag = Math.min(farAway, 4) * this.mass * this.acceleration
this.force = Vector.mult(Vector.normalise(Vector.sub(playerPos, this.position)), mag)
//manual friction to not lose rotational velocity
@@ -3520,13 +3631,13 @@ const b = {
name: "spores",
description: "fire a sporangium that discharges spores
spores seek out nearby mobs",
ammo: 0,
- ammoPack: 3,
+ ammoPack: 3.5,
have: false,
fire() {
const me = bullet.length;
const dir = m.angle;
bullet[me] = Bodies.polygon(m.pos.x + 30 * Math.cos(m.angle), m.pos.y + 30 * Math.sin(m.angle), 20, 4.5, b.fireAttributes(dir, false));
- b.fireProps(m.crouch ? 50 : 30, m.crouch ? 30 : 16, dir, me); //cd , speed
+ b.fireProps(m.crouch ? 45 : 25, m.crouch ? 30 : 16, dir, me); //cd , speed
Matter.Body.setDensity(bullet[me], 0.000001);
bullet[me].endCycle = Infinity;
bullet[me].frictionAir = 0;
@@ -3683,10 +3794,10 @@ const b = {
name: "foam",
description: "spray bubbly foam that sticks to mobs
slows mobs and does damage over time",
ammo: 0,
- ammoPack: 35,
+ ammoPack: 36,
have: false,
fire() {
- m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 20 : 6) * b.fireCD); // cool down
+ m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 15 : 5) * b.fireCD); // cool down
const radius = (m.crouch ? 10 + 5 * Math.random() : 4 + 6 * Math.random()) + (tech.isAmmoFoamSize && this.ammo < 300) * 12
const SPEED = 18 - radius * 0.4;
const dir = m.angle + 0.2 * (Math.random() - 0.5)
diff --git a/js/index.js b/js/index.js
index 4a8fdef..15c0cff 100644
--- a/js/index.js
+++ b/js/index.js
@@ -857,7 +857,7 @@ window.addEventListener("keydown", function(event) {
x: 0,
y: 0
});
- // move bots to follow player
+ // move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
diff --git a/js/level.js b/js/level.js
index e9f25be..a220bf1 100644
--- a/js/level.js
+++ b/js/level.js
@@ -19,7 +19,7 @@ const level = {
// m.setField("plasma torch")
// b.giveGuns("nail gun")
// tech.isExplodeRadio = true
- // tech.giveTech("needle gun")
+ for (let i = 0; i < 1; i++) tech.giveTech("dynamo-bot")
// tech.giveTech("supercritical fission")
// tech.giveTech("irradiated nails")
// tech.giveTech("cardinality")
@@ -299,9 +299,10 @@ const level = {
// spawn.laserTargetingBoss(1600, -400)
// spawn.striker(1600, -500)
// spawn.shooter(1700, -120)
- spawn.bomberBoss(1400, -500)
+ // spawn.bomberBoss(1400, -500)
// spawn.sniper(1800, -120)
// spawn.cellBossCulture(1600, -500)
+ // spawn.cellBossCulture(1600, -500)
// spawn.streamBoss(1600, -500)
// spawn.beamer(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1);
@@ -348,6 +349,7 @@ const level = {
// spawn.randomBoss(1700, -900, 0.4);
// if (simulation.difficulty > 3) spawn.randomLevelBoss(2200, -1300);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ // if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
},
final() {
level.bossKilled = false; // if a boss needs to be killed
@@ -398,6 +400,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() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
},
gauntlet() {
level.bossKilled = true; //if there is no boss this needs to be true to increase levels
@@ -460,6 +463,7 @@ const level = {
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350);
},
intro() {
level.bossKilled = true; //if there is no boss this needs to be true to increase levels
@@ -636,45 +640,45 @@ const level = {
spawn.wireKneeLeft();
spawn.wireHead();
} else {
- const say = []
- if (localSettings.runCount > 200) { //experienced
- say.push(
- "I've been here before...",
- "How many times have I done this?",
- )
- } else if (localSettings.runCount < 20) { //new
- say.push(
- "Am I still alive?",
- "And I'm back here again...",
- "Is this another simulation?",
- "I'm alive...",
- "Last time was a simulation. Is this one a simulation too?",
- )
- }
- if (simulation.difficultyMode < 4 && localSettings.levelsClearedLastGame > 10) { //too easy
- say.push(
- "That felt too easy.
Maybe I should increase the difficulty of the simulation.",
- "That was fun, but maybe I should increase the difficulty of the simulation.",
- "I should increase the difficulty of the simulation, that didn't feel realistic.",
- )
- } else if (simulation.difficultyMode > 3 && localSettings.levelsClearedLastGame > 10) { //great run on a hard or why
- say.push(
- "What do I do after I escape?",
- "I'm almost ready to stop these simulations and actually escape.",
- "I think I'm getting closer to something, but what?",
- "I'm getting stronger.",
- "What happens after I escape?",
- "I found a good combination of technology last time."
- )
- } else { //resolve
- say.push(
- "I'll try some different techs this time.",
- "I've got to escape.",
- "I'll find a way out.",
- "I keep forgetting that these are just simulated escapes."
- )
- }
- simulation.makeTextLog(say[Math.floor(say.length * Math.random())], 1000)
+ // const say = []
+ // if (localSettings.runCount > 200) { //experienced
+ // say.push(
+ // "I've been here before...",
+ // "How many times have I done this?",
+ // )
+ // } else if (localSettings.runCount < 20) { //new
+ // say.push(
+ // "Am I still alive?",
+ // "And I'm back here again...",
+ // "Is this another simulation?",
+ // "I'm alive...",
+ // "Last time was a simulation. Is this one a simulation too?",
+ // )
+ // }
+ // if (simulation.difficultyMode < 4 && localSettings.levelsClearedLastGame > 10) { //too easy
+ // say.push(
+ // "That felt too easy.
Maybe I should increase the difficulty of the simulation.",
+ // "That was fun, but maybe I should increase the difficulty of the simulation.",
+ // "I should increase the difficulty of the simulation, that didn't feel realistic.",
+ // )
+ // } else if (simulation.difficultyMode > 3 && localSettings.levelsClearedLastGame > 10) { //great run on a hard or why
+ // say.push(
+ // "What do I do after I escape?",
+ // "I'm almost ready to stop these simulations and actually escape.",
+ // "I think I'm getting closer to something, but what?",
+ // "I'm getting stronger.",
+ // "What happens after I escape?",
+ // "I found a good combination of technology last time."
+ // )
+ // } else { //resolve
+ // say.push(
+ // "I'll try some different techs this time.",
+ // "I've got to escape.",
+ // "I'll find a way out.",
+ // "I keep forgetting that these are just simulated escapes."
+ // )
+ // }
+ // simulation.makeTextLog(say[Math.floor(say.length * Math.random())], 1000)
const swapPeriod = 150
const len = 30
@@ -695,6 +699,7 @@ const level = {
}
}
powerUps.spawnStartingPowerUps(2300, -150);
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(1900, -675);
},
testChamber() {
level.setPosToSpawn(0, -50); //lower start
@@ -768,7 +773,6 @@ const level = {
}
}
-
buttonDoor.query();
buttonDoor.draw();
if (buttonDoor.isUp) {
@@ -961,6 +965,7 @@ const level = {
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(1925, -1250);
},
sewers() {
level.bossKilled = false; // if a boss needs to be killed
@@ -1106,6 +1111,7 @@ const level = {
spawn.randomMob(2825, 400, 0.9);
if (simulation.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275);
},
satellite() {
level.bossKilled = false; // if a boss needs to be killed
@@ -1312,6 +1318,7 @@ const level = {
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(3950, -850);
},
rooftops() {
level.bossKilled = false; // if a boss needs to be killed
@@ -1535,6 +1542,7 @@ const level = {
spawn.randomBoss(4900, -1200, 0);
if (simulation.difficulty > 3) spawn.randomLevelBoss(3200, -2050);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(2175, -2425);
},
aerie() {
level.bossKilled = false; // if a boss needs to be killed
@@ -1744,6 +1752,7 @@ const level = {
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(5350, -325);
},
skyscrapers() {
level.bossKilled = false; // if a boss needs to be killed
@@ -1905,6 +1914,7 @@ const level = {
spawn.randomBoss(1700, -900, 0.4);
if (simulation.difficulty > 3) spawn.randomLevelBoss(2600, -2300);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(3075, -2050);
},
highrise() {
level.bossKilled = false; // if a boss needs to be killed
@@ -2104,6 +2114,7 @@ const level = {
if (simulation.difficulty > 3) spawn.randomLevelBoss(-2400, -3000);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(-1825, -1975);
},
warehouse() {
level.bossKilled = false; // if a boss needs to be killed
@@ -2275,10 +2286,12 @@ const level = {
if (Math.random() < 0.25) {
spawn.randomLevelBoss(-800, -1300)
} else {
- spawn.snakeBoss(-1000 + Math.random() * 1500, -2200); //boss snake with head
+ spawn.snakeBoss(-1000 + Math.random() * 2500, -1300); //boss snake with head
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(300, -800);
},
office() {
let button, door
@@ -2478,6 +2491,7 @@ const level = {
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
+ if (tech.isDuplicateBoss && Math.random() < 3 * tech.duplicationChance()) spawn.randomLevelBoss(1875, -675);
},
stronghold() { // player made level by Francois 👑 from discord
level.custom = () => {
@@ -4452,7 +4466,7 @@ const level = {
}
let v = Vector.mult(this.portalPair.unit, mag)
Matter.Body.setVelocity(player, v);
- // move bots to follow player
+ // move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
// Matter.Body.setPosition(bullet[i], this.portalPair.portal.position);
diff --git a/js/player.js b/js/player.js
index 6162488..54ec8d5 100644
--- a/js/player.js
+++ b/js/player.js
@@ -52,7 +52,7 @@ const m = {
});
World.add(engine.world, m.holdConstraint);
},
- cycle: 300, //starts at 300 cycles instead of 0 to prevent bugs with m.history
+ cycle: 600, //starts at 600 cycles instead of 0 to prevent bugs with m.history
lastKillCycle: 0,
lastHarmCycle: 0,
width: 50,
@@ -467,7 +467,7 @@ const m = {
},
displayHealth() {
id = document.getElementById("health");
- // health display follows a x^1.5 rule to make it seem like the player has lower health, this makes the player feel more excitement
+ // health display is a x^1.5 rule to make it seem like the player has lower health, this makes the player feel more excitement
id.style.width = Math.floor(300 * m.maxHealth * Math.pow(m.health / m.maxHealth, 1.4)) + "px";
//css animation blink if health is low
if (m.health < 0.3) {
@@ -556,7 +556,7 @@ const m = {
// simulation.updateGunHUD();
// simulation.boldActiveGunHUD();
- // move bots to follow player
+ // move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
@@ -2540,7 +2540,7 @@ const m = {
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
- // move bots to follow player
+ // move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
diff --git a/js/simulation.js b/js/simulation.js
index 4bd0387..aa0e867 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -530,9 +530,10 @@ const simulation = {
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
}
+ tech.dynamoBotCount = 0;
+ tech.nailBotCount = 0;
tech.laserBotCount = 0;
tech.orbitBotCount = 0;
- tech.nailBotCount = 0;
tech.foamBotCount = 0;
tech.boomBotCount = 0;
tech.plasmaBotCount = 0;
diff --git a/js/spawn.js b/js/spawn.js
index 59824f7..9ea18ce 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -507,15 +507,17 @@ const spawn = {
};
},
cellBossCulture(x, y, radius = 20, num = 5) {
+ const cellID = Math.random()
for (let i = 0; i < num; i++) {
- spawn.cellBoss(x, y, radius)
+ spawn.cellBoss(x, y, radius, cellID)
}
},
- cellBoss(x, y, radius = 20) {
+ cellBoss(x, y, radius = 20, cellID) {
mobs.spawn(x + Math.random(), y + Math.random(), 20, radius * (1 + 1.2 * Math.random()), "rgba(0,150,155,0.7)");
let me = mob[mob.length - 1];
me.isBoss = true;
me.isCell = true;
+ me.cellID = cellID
me.accelMag = 0.00015 * simulation.accelScale;
me.memory = 40;
me.isVerticesChange = true
@@ -531,7 +533,7 @@ const spawn = {
me.split = function() {
Matter.Body.scale(this, 0.4, 0.4);
this.radius = Math.sqrt(this.mass * k / Math.PI)
- spawn.cellBoss(this.position.x, this.position.y, this.radius);
+ spawn.cellBoss(this.position.x, this.position.y, this.radius, this.cellID);
mob[mob.length - 1].health = this.health
}
me.onHit = function() { //run this function on hitting player
@@ -571,9 +573,10 @@ const spawn = {
};
me.onDeath = function() {
this.isCell = false;
- let count = 0 //count other cells
+ let count = 0 //count other cells by id
+ // console.log(this.cellID)
for (let i = 0, len = mob.length; i < len; i++) {
- if (mob[i].isCell) count++
+ if (mob[i].isCell && mob[i].cellID === this.cellID) count++
}
if (count < 1) { //only drop a power up if this is the last cell
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
@@ -2420,7 +2423,6 @@ const spawn = {
stiffness: 0.05
});
World.add(engine.world, consBB[consBB.length - 1]);
-
},
snakeBody(x, y, radius = 20) {
mobs.spawn(x, y, 4, radius, "rgb(55,170,170)");
diff --git a/js/tech.js b/js/tech.js
index e0ef900..7d43739 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -9,12 +9,6 @@ const tech = {
lore.techCount = 0;
tech.removeLoreTechFromPool();
tech.addLoreTechToPool();
- // tech.nailBotCount = 0;
- // tech.foamBotCount = 0;
- // tech.boomBotCount = 0;
- // tech.laserBotCount = 0;
- // tech.orbitalBotCount = 0;
- // tech.plasmaBotCount = 0;
tech.armorFromPowerUps = 0;
tech.totalCount = 0;
simulation.updateTechHUD();
@@ -116,7 +110,7 @@ const tech = {
return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.04 + tech.duplicateChance + m.duplicateChance
},
totalBots() {
- return tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
+ return tech.dynamoBotCount + tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
},
tech: [{
name: "integrated armament",
@@ -922,6 +916,45 @@ const tech = {
}
}
},
+ {
+ name: "dynamo-bot",
+ description: "a bot damages mobs while it traces your path
regen 4 energy per second when it's near",
+ maxCount: 9,
+ count: 0,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.dynamoBotCount++;
+ b.dynamoBot();
+ },
+ remove() {
+ tech.dynamoBotCount -= this.count;
+ }
+ },
+ {
+ name: "dynamo-bot upgrade",
+ description: "dynamo-bots regen 12 energy per second
applies to all current and future orbit-bots",
+ maxCount: 1,
+ count: 0,
+ allowed() {
+ return tech.dynamoBotCount > 1
+ },
+ requires: "2 or more dynamo bots",
+ effect() {
+ tech.isDynamoBotUpgrade = true
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = true
+ }
+ },
+ remove() {
+ tech.isDynamoBotUpgrade = false
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = false
+ }
+ }
+ },
{
name: "bot fabrication",
description: "anytime you collect 5 research
use them to build a random bot",
@@ -1076,7 +1109,7 @@ const tech = {
},
requires: "",
effect() {
- tech.cyclicImmunity += 60 - this.count * 6;
+ tech.cyclicImmunity += 60;
},
remove() {
tech.cyclicImmunity = 0;
@@ -1759,6 +1792,22 @@ const tech = {
tech.isDupDamage = false;
}
},
+ {
+ name: "cloning",
+ description: "each level has a chance to spawn a level boss
equal to triple your duplication chance",
+ maxCount: 1,
+ count: 0,
+ allowed() {
+ return tech.duplicationChance() > 0
+ },
+ requires: "some duplication chance",
+ effect() {
+ tech.isDuplicateBoss = true;
+ },
+ remove() {
+ tech.isDuplicateBoss = false;
+ }
+ },
{
name: "futures exchange",
description: "clicking × to cancel a field, tech, or gun
adds 4% power up duplication chance",
@@ -3535,6 +3584,7 @@ const tech = {
b.nailBot()
tech.nailBotCount++;
}
+ simulation.makeTextLog(`tech.isNailBotUpgrade = true`)
})
if (!tech.isFoamBotUpgrade) notUpgradedBots.push(() => {
tech.giveTech("foam-bot upgrade")
@@ -3543,6 +3593,7 @@ const tech = {
b.foamBot()
tech.foamBotCount++;
}
+ simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
})
if (!tech.isBoomBotUpgrade) notUpgradedBots.push(() => {
tech.giveTech("boom-bot upgrade")
@@ -3551,6 +3602,7 @@ const tech = {
b.boomBot()
tech.boomBotCount++;
}
+ simulation.makeTextLog(`tech.isBoomBotUpgrade = true`)
})
if (!tech.isLaserBotUpgrade) notUpgradedBots.push(() => {
tech.giveTech("laser-bot upgrade")
@@ -3559,6 +3611,7 @@ const tech = {
b.laserBot()
tech.laserBotCount++;
}
+ simulation.makeTextLog(`tech.isLaserBotUpgrade = true`)
})
if (!tech.isOrbitBotUpgrade) notUpgradedBots.push(() => {
tech.giveTech("orbital-bot upgrade")
@@ -3567,6 +3620,26 @@ const tech = {
b.orbitBot()
tech.orbitBotCount++;
}
+ simulation.makeTextLog(`tech.isOrbitalBotUpgrade = true`)
+ })
+ if (!tech.isDynamoBotUpgrade) notUpgradedBots.push(() => {
+ tech.giveTech("dynamo-bot upgrade")
+ tech.setTechoNonRefundable("dynamo-bot upgrade")
+ for (let i = 0; i < 2; i++) {
+ b.orbitBot()
+ tech.dynamoBotCount++;
+ }
+ simulation.makeTextLog(`tech.isDynamoBotUpgrade = true`)
+ })
+ //double chance for dynamo-bot, since it's very good for nano-scale
+ if (!tech.isDynamoBotUpgrade) notUpgradedBots.push(() => {
+ tech.giveTech("dynamo-bot upgrade")
+ tech.setTechoNonRefundable("dynamo-bot upgrade")
+ for (let i = 0; i < 2; i++) {
+ b.orbitBot()
+ tech.dynamoBotCount++;
+ }
+ simulation.makeTextLog(`tech.isDynamoBotUpgrade = true`)
})
//choose random function from the array and run it
notUpgradedBots[Math.floor(Math.random() * notUpgradedBots.length)]()
@@ -4093,6 +4166,7 @@ const tech = {
isMassEnergy: null,
isExtraChoice: null,
laserBotCount: null,
+ dynamoBotCount: null,
nailBotCount: null,
foamBotCount: null,
boomBotCount: null,
@@ -4261,5 +4335,7 @@ const tech = {
isNeedles: null,
isExplodeRadio: null,
isGunSwitchField: null,
- isNeedleShieldPierce: null
+ isNeedleShieldPierce: null,
+ isDuplicateBoss: null,
+ isDynamoBotUpgrade: null
}
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index 96d01ea..4ae3fc8 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,11 +1,18 @@
******************************************************** NEXT PATCH ********************************************************
-unified field theory doesn't require research to cycle fields
+tech: cloning - chance to spawn another level boss = 3x your duplication chance
-game resets after beating final boss (in 20s)
+tech: dynamo-bot: a bot follows your history, damages mobs, and regens energy when it gets close
+tech: dynamo upgrade: more energy regen
******************************************************** BUGS ********************************************************
+(only once on my computer) once every 7 second check isn't running code
+ power ups don't teleport to exit
+ complex spin statistics isn't activating
+ wasn't able to understand bug after extensive testing
+ had tech: complex spin statistics
+
(a few times) wormhole teleportation can leave the player in a stuck jump state
seems to be easily fixed, by porting, firing or something
@@ -24,7 +31,7 @@ game resets after beating final boss (in 20s)
******************************************************** TODO ********************************************************
-exiting the final boss room without 10/10 takes you to the start menu
+smooth history following for dynamo-bot?
give undefined tech different effects at different localSettings.loreCount values
or just random effects
@@ -34,8 +41,6 @@ give undefined tech different effects at different localSettings.loreCount value
3. 1/1: reduce max energy and take more harm
4. 1/1: add 5? more levels
-lore add console command for unlocking testing mode
-
rename ?
health -> integrity, unity
heal -> also integrity, unity
@@ -46,28 +51,16 @@ mechanic: use gun swap as an active ability
trigger damage immunity for 3 seconds, but drain ammo
push away nearby mobs, but drain energy
produce ammo, but take 1 damage
- rewind, still uses energy
bot: ice blast, long CD AOE freeze
RPG default or tech: grenades detonate on your cursor / where your cursor was when they were fired
-tech: double your rerolls
+tech: double your research
set your duplication chance to zero
requires 5 rerolls and 20% duplication chance
might want to use a single variable for all duplication
-bot that follows the players history
- could have the same shape as the m circle head
- 1st bot is at 5s, 2nd is at 4.5s, ...
- bots don't get too close to player
- run smoothing on position update, don't update if close to player, based on ordering
- effect: (one of these can be the upgrade effect)
- give player energy overfill
- AOE damage to mobs
- push away mobs
- when close to player: damage bonus damage reduction
-
tech: dodge chance for cloaking, harmonic fields, also pilot wave
20% chance up to 3 stacks, not additive
0.8^count
@@ -85,8 +78,6 @@ tech: time dilation - when you exit time dilation rewind to the state you entere
mob ability bombs/bullets that suck in player
-tech where you can't stop firing, how to code?
-
mechanic: technological dead end - add tech to the tech pool with a dumb effect
don't show up in custom?
negative effect (one time effects are better to avoid code clutter)
@@ -106,23 +97,8 @@ mechanic: technological dead end - add tech to the tech pool with a dumb effect
remove your bots (requires you to have some bots)
your bots are changed to random bots
-tech "Expansion Formula": Permanently increase the size of Negative Mass field by 16%(Max 96%)
-
-
-tech "High Risk": Spawn two bosses per level.
- maybe limit to just the power up boss and spawn it at the exit every time to keep it simple
- also weaken the player
- remove a tech?
- lower harm reduction?
- increase game difficulty by one level
-
tech that requires integrated armament
-tech- reset level
- you trade a tech for a chance at killing a new level boss and farming more ammo
- resets health, ammo (but not tech, fields, guns, ... ?)
- scramble level order? or same level
-
mechanic - Your energy regen is only active when field and gun have not been used for 5 seconds.
be able to open up custom mode in the normal game