diff --git a/.DS_Store b/.DS_Store
index 2d62762..3105f25 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/index.html b/index.html
index 35e9b36..7c463e8 100644
--- a/index.html
+++ b/index.html
@@ -93,6 +93,11 @@
experiment
+
diff --git a/js/bullet.js b/js/bullet.js
index 4f26954..f831f8e 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -2361,9 +2361,9 @@ const b = {
},
worm(where, isFreeze = tech.isSporeFreeze) { //used with the tech upgrade in mob.death()
const bIndex = bullet.length;
- const size = 3
+ const wormSize = 6 + tech.wormSize * 7.2 * Math.random()
if (bIndex < 500) { //can't make over 500 spores
- bullet[bIndex] = Bodies.polygon(where.x, where.y, size, size, {
+ bullet[bIndex] = Bodies.polygon(where.x, where.y, 3, 3, {
inertia: Infinity,
isFreeze: isFreeze,
restitution: 0.5,
@@ -2371,7 +2371,9 @@ const b = {
friction: 0,
frictionAir: 0.025,
thrust: (tech.isFastSpores ? 0.001 : 0.0005) * (1 + 0.5 * (Math.random() - 0.5)),
- dmg: (tech.isMutualism ? 16.8 : 7) * 2.5, //bonus damage from tech.isMutualism //2.5 is extra damage as worm
+ wormSize: wormSize,
+ wormTail: 1 + wormSize,
+ dmg: (tech.isMutualism ? 7 : 2.9) * wormSize, //bonus damage from tech.isMutualism //2.5 is extra damage as worm
lookFrequency: 100 + Math.floor(37 * Math.random()),
classType: "bullet",
collisionFilter: {
@@ -2408,10 +2410,10 @@ const b = {
do() {
ctx.beginPath(); //draw nematode
ctx.moveTo(this.position.x, this.position.y);
- const dir = Vector.mult(Vector.normalise(this.velocity), -Math.min(45, 7 * this.speed))
+ const dir = Vector.mult(Vector.normalise(this.velocity), -Math.min(100, this.wormTail * this.speed))
const tail = Vector.add(this.position, dir)
ctx.lineTo(tail.x, tail.y);
- ctx.lineWidth = 6;
+ ctx.lineWidth = this.wormSize;
ctx.strokeStyle = "#000";
ctx.stroke();
diff --git a/js/engine.js b/js/engine.js
index f8467e6..8bee772 100644
--- a/js/engine.js
+++ b/js/engine.js
@@ -103,7 +103,7 @@ function collisionChecks(event) {
if (
m.immuneCycle < m.cycle &&
(obj === playerBody || obj === playerHead) &&
- !(tech.isFreezeHarmImmune && (mob[k].isSlowed || mob[k].isStunned))
+ !mob[k].isSlowed && !mob[k].isStunned
) {
let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * simulation.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0
if (m.isCloak) dmg *= 0.5
diff --git a/js/index.js b/js/index.js
index 0e68cca..f51c175 100644
--- a/js/index.js
+++ b/js/index.js
@@ -622,6 +622,7 @@ ${simulation.isCheating ? "
lore disabled": ""}
function openExperimentMenu() {
document.getElementById("experiment-button").style.display = "none";
+ document.getElementById("training-button").style.display = "none";
const el = document.getElementById("experiment-grid")
el.style.display = "grid"
document.body.style.overflowY = "scroll";
@@ -1295,16 +1296,5 @@ function cycle() {
level.start();
}
simulation.loop();
- // if (isNaN(m.health) || isNaN(m.energy)) {
- // console.log(`m.health = ${m.health}`)
- // simulation.paused = true;
- // build.pauseGrid()
- // document.body.style.cursor = "auto";
- // alert("health is NaN, please report this bug to the discord \n https://discordapp.com/invite/2eC9pgJ")
- // }
- // for (let i = 0, len = loop.length; i < len; i++) {
- // loop[i]()
- // }
}
-}
-// simulation.introPlayer()
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/js/level.js b/js/level.js
index 7581318..c16effd 100644
--- a/js/level.js
+++ b/js/level.js
@@ -8,6 +8,7 @@ const level = {
onLevel: -1,
levelsCleared: 0,
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber"],
+ trainingLevels: ["trainingHold", "trainingThrow", "trainingCrouch", "trainingJump"],
levels: [],
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
@@ -17,19 +18,23 @@ const level = {
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true
// m.setField("plasma torch")
- // b.giveGuns("drones")
+ // b.giveGuns("spores")
// b.giveGuns("nail gun")
// b.giveGuns("harpoon")
- // tech.giveTech("brainstorming")
- // tech.giveTech("nanowires")
- // tech.giveTech("relativistic momentum")
+ // tech.giveTech("nematodes")
+ // for (let i = 0; i < 9; i++) tech.giveTech("annelids")
+ // tech.giveTech("tinsellated flagella")
// for (let i = 0; i < 2; i++) tech.giveTech("refractory metal")
// tech.giveTech("antiscience")
// for (let i = 0; i < 1; i++) tech.giveTech("reticulum")
// for (let i = 0; i < 2; i++) tech.giveTech("laser-bot")
// tech.tech[297].frequency = 100
-
- level.intro(); //starting level
+ // level.trainingThrow();
+ if (simulation.isTraining) {
+ level.trainingHold();
+ } else {
+ level.intro(); //starting level
+ }
// level.testing(); //not in rotation, used for testing
// level.template(); //not in rotation, blank start new map development
// level.final() //final boss level
@@ -68,13 +73,13 @@ const level = {
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// spawn.pickList = ["focuser", "focuser"]
level[level.levels[level.onLevel]](); //picks the current map from the the levels array
- if (!simulation.isCheating && !build.isExperimentRun) {
+ if (!simulation.isCheating && !build.isExperimentRun && !simulation.isTraining) {
localSettings.runCount += level.levelsCleared //track the number of total runs locally
localSettings.levelsClearedLastGame = level.levelsCleared
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
}
- level.levelAnnounce();
+ if (!simulation.isTraining) level.levelAnnounce();
simulation.noCameraScroll();
simulation.setZoom();
level.addToWorld(); //add bodies to game engine
@@ -131,6 +136,337 @@ const level = {
// for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "tech", false); //start
}
},
+ trainingJump() { //learn to crouch
+ m.addHealth(Infinity)
+ document.getElementById("health").style.display = "none" //hide your health bar
+ document.getElementById("health-bg").style.display = "none"
+
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = "#e1e1e1";
+
+ simulation.lastLogTime = 0; //clear previous messages
+ let instruction = 0
+ simulation.makeTextLog(`hold down ${input.key.up} longer to jump higher`, Infinity)
+
+ level.custom = () => {
+ if (instruction === 0 && m.pos.x > 300) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`hold down ${input.key.up} longer to jump higher`, Infinity)
+ }
+
+ m.health = 1 //can't die
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+ level.exit.draw();
+ level.enter.draw();
+ level.playerExitCheck();
+ };
+ level.customTopLayer = () => {
+ //dark
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(1000, 0, 450, 1800)
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(275, -350, 200, 375);
+ spawn.mapRect(-250, 0, 1250, 1800);
+ spawn.mapRect(1450, 0, 1075, 1800);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ trainingCrouch() { //learn to crouch
+ m.addHealth(Infinity)
+ //hide your health bar
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = "#e1e1e1";
+
+ simulation.lastLogTime = 0; //clear previous messages
+ let instruction = 0
+ simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity)
+
+ level.custom = () => {
+ if (instruction === 0 && input.down) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1650, -400, 400, 400)
+ level.exit.draw();
+ level.enter.draw();
+ level.playerExitCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1650, -400, 400, 400)
+ //dark
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(625, -100, 1025, 175)
+ };
+
+ // spawn.mapRect(1025, -675, 300, 623); //crouch wall
+ spawn.mapRect(625, -650, 1025, 550);
+ spawn.mapRect(-200, -650, 875, 300);
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ trainingThrow() { //throw a block on button to open door
+ m.addHealth(Infinity)
+ //hide your health bar
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = "#e1e1e1";
+
+ spawn.bodyRect(1025, -75, 50, 50); //block to go on button
+ const buttonDoor = level.button(1635, -400)
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+
+ simulation.lastLogTime = 0; //clear previous messages
+ let instruction = 0
+ simulation.makeTextLog(`activate your field with space or right mouse
+
pick up the block with your field`, Infinity)
+
+ level.custom = () => {
+ console.log(m.throwCharge)
+ if (instruction === 0 && m.isHolding) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`pick up the block with your field
+
hold your field down to charge up then release to throw a block`, Infinity)
+ } else if (instruction === 1 && m.throwCharge > 2) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`pick up the block with your field
+
hold your field down to charge up then release to throw a block
+
throw the block onto the button`, Infinity)
+ // the block at the button
+ } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`pick up the block with your field
+
hold your field down to charge up then release to throw a block
+
throw the block onto the button`, Infinity)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+ level.exit.draw();
+ level.enter.draw();
+ level.playerExitCheck();
+ };
+ level.customTopLayer = () => {
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isOpen = true
+ } else {
+ door.isOpen = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ // spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1790, -600, 250, 225); //button left wall
+ spawn.mapRect(1625, -400, 400, 50);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ trainingHold() { //put block on button to open door
+ m.addHealth(Infinity)
+ //hide your health bar
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = "#e1e1e1";
+
+ spawn.bodyRect(1025, -75, 50, 50); //block to go on button
+ const buttonDoor = level.button(500, 0)
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+
+ simulation.lastLogTime = 0; //clear previous messages
+ let instruction = 0
+ simulation.makeTextLog(`activate your field with space or right mouse`, Infinity)
+
+ level.custom = () => {
+ if (instruction === 0 && input.field) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`activate your field with space or right mouse
release your field on a block to pick it up`, Infinity)
+ } else if (instruction === 1 && m.isHolding) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`activate your field with space or right mouse
release your field on a block to pick it up
drop the block on the red button to open the door`, Infinity)
+ } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`activate your field with space or right mouse
release your field on a block to pick it up
drop the block on the red button to open the door`, Infinity)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+ level.exit.draw();
+ level.enter.draw();
+ level.playerExitCheck();
+ };
+ level.customTopLayer = () => {
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isOpen = true
+ } else {
+ door.isOpen = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ trainingTemplate() { //learn to crouch
+ m.addHealth(Infinity)
+ document.getElementById("health").style.display = "none" //hide your health bar
+ document.getElementById("health-bg").style.display = "none"
+
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = "#e1e1e1";
+
+ simulation.lastLogTime = 0; //clear previous messages
+ let instruction = 0
+ simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity)
+
+ level.custom = () => {
+ if (instruction === 0 && input.down) {
+ instruction++
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+ level.exit.draw();
+ level.enter.draw();
+ level.playerExitCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
custom() {},
customTopLayer() {},
setDifficulty() {
@@ -214,27 +550,31 @@ const level = {
simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map
},
populateLevels() {
- simulation.isHorizontalFlipped = (Math.random() < 0.5) ? true : false //if true, some maps are flipped horizontally
- level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
- if (simulation.isCommunityMaps) {
- level.levels.push("stronghold");
- level.levels.push("basement");
- level.levels.push("crossfire");
- level.levels.push("vats")
- level.levels.push("n-gon")
- level.levels.push("house");
- level.levels.push("perplex");
- level.levels.push("coliseum");
- level.levels.push("tunnel");
- level.levels = shuffle(level.levels); //shuffles order of maps
- level.levels.splice(0, 9); //remove some random levels to make up for adding the community levels
+ if (simulation.isTraining) {
+ level.levels = level.trainingLevels.slice(0) //copy array, not by just by assignment
} else {
- level.levels = shuffle(level.levels); //shuffles order of maps
- }
- if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech
- level.levels.unshift("intro"); //add level to the start of the randomized levels list
- level.levels.push("gauntlet"); //add level to the end of the randomized levels list
- level.levels.push("final"); //add level to the end of the randomized levels list
+ simulation.isHorizontalFlipped = (Math.random() < 0.5) ? true : false //if true, some maps are flipped horizontally
+ level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
+ if (simulation.isCommunityMaps) {
+ level.levels.push("stronghold");
+ level.levels.push("basement");
+ level.levels.push("crossfire");
+ level.levels.push("vats")
+ level.levels.push("n-gon")
+ level.levels.push("house");
+ level.levels.push("perplex");
+ level.levels.push("coliseum");
+ level.levels.push("tunnel");
+ level.levels = shuffle(level.levels); //shuffles order of maps
+ level.levels.splice(0, 9); //remove some random levels to make up for adding the community levels
+ } else {
+ level.levels = shuffle(level.levels); //shuffles order of maps
+ }
+ if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech
+ level.levels.unshift("intro"); //add level to the start of the randomized levels list
+ level.levels.push("gauntlet"); //add level to the end of the randomized levels list
+ level.levels.push("final"); //add level to the end of the randomized levels list
+ }
}
},
flipHorizontal() {
@@ -723,7 +1063,7 @@ const level = {
}
}
},
- door(x, y, width, height, distance) {
+ door(x, y, width, height, distance, speed = 1) {
x = x + width / 2
y = y + height / 2
const doorBlock = body[body.length] = Bodies.rectangle(x, y, width, height, {
@@ -743,7 +1083,7 @@ const level = {
if (this.position.y > y - distance) { //try to open
const position = {
x: this.position.x,
- y: this.position.y - 1
+ y: this.position.y - speed
}
Matter.Body.setPosition(this, position)
}
@@ -756,7 +1096,7 @@ const level = {
) {
const position = {
x: this.position.x,
- y: this.position.y + 1
+ y: this.position.y + speed
}
Matter.Body.setPosition(this, position)
}
@@ -1228,7 +1568,7 @@ const level = {
spawn.randomMob(x + 1175, y - 725, mobSpawnChance);
spawn.randomMob(x + 1450, y - 725, mobSpawnChance);
spawn.randomMob(x + 425, y - 100, mobSpawnChance);
- spawn.randomMob(x + 1200, y - 125, mobSpawnChance);
+ spawn.randomMob(x + 1700, y - 300, mobSpawnChance);
spawn.randomMob(x + 1300, y - 375, mobSpawnChance);
}
ctx.fillStyle = "#d4f4f4"
diff --git a/js/lore.js b/js/lore.js
index 4d3e28d..aaae6fd 100644
--- a/js/lore.js
+++ b/js/lore.js
@@ -45,7 +45,7 @@ const lore = {
if (localSettings.loreCount < 1) localSettings.loreCount = 1
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
- document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
+ // document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
simulation.makeTextLog(`lore.unlockTesting()`, Infinity);
sound.portamento(50)
diff --git a/js/player.js b/js/player.js
index fa2e169..06d869d 100644
--- a/js/player.js
+++ b/js/player.js
@@ -647,7 +647,7 @@ const m = {
}
if (tech.isEnergyHealth) {
- m.energy -= dmg * 1.1;
+ m.energy -= dmg
if (m.energy < 0 || isNaN(m.energy)) { //taking deadly damage
if (tech.isDeathAvoid && powerUps.research.count && !tech.isDeathAvoidedThisLevel) {
tech.isDeathAvoidedThisLevel = true
@@ -1248,7 +1248,6 @@ const m = {
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, range, m.angle - Math.PI * m.fieldArc, m.angle + Math.PI * m.fieldArc, false);
ctx.lineWidth = 2;
- ctx.lineCap = "butt"
ctx.stroke();
let eye = 13;
let aMag = 0.75 * Math.PI * m.fieldArc
@@ -1741,7 +1740,6 @@ const m = {
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, m.fieldRange, m.angle - Math.PI * m.fieldArc, m.angle + Math.PI * m.fieldArc, false);
ctx.lineWidth = 2.5 - 1.5 * wave;
- ctx.lineCap = "butt"
ctx.stroke();
const curve = 0.57 + 0.04 * wave
const aMag = (1 - curve * 1.2) * Math.PI * m.fieldArc
@@ -1766,7 +1764,6 @@ const m = {
ctx.beginPath();
ctx.arc(m.fieldPosition.x, m.fieldPosition.y, m.fieldRange, m.fieldAngle - Math.PI * m.fieldArc, m.fieldAngle + Math.PI * m.fieldArc, false);
ctx.lineWidth = 2.5 - 1.5 * wave;
- ctx.lineCap = "butt"
ctx.stroke();
const curve = 0.8 + 0.06 * wave
const aMag = (1 - curve * 1.2) * Math.PI * m.fieldArc
@@ -3564,7 +3561,7 @@ const m = {
m.immuneCycle < m.cycle &&
// (obj === playerBody || obj === playerHead) &&
(obj === player) &&
- !(tech.isFreezeHarmImmune && (mob[k].isSlowed || mob[k].isStunned))
+ !mob[k].isSlowed && !mob[k].isStunned
) {
mob[k].foundPlayer();
let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * simulation.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0
diff --git a/js/simulation.js b/js/simulation.js
index 9245e9c..82ecb3e 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -110,6 +110,7 @@ const simulation = {
g: 0.0024, // applies to player, bodies, and power ups (not mobs)
onTitlePage: true,
isCheating: false,
+ isTraining: false,
paused: false,
isChoosing: false,
testing: false, //testing mode: shows wire frame and some variables
@@ -530,6 +531,8 @@ const simulation = {
document.getElementById("info").style.opacity = "0";
document.getElementById("experiment-button").style.display = "inline"
document.getElementById("experiment-button").style.opacity = "0";
+ document.getElementById("training-button").style.display = "inline"
+ document.getElementById("training-button").style.opacity = "0";
document.getElementById("experiment-grid").style.display = "none"
document.getElementById("pause-grid-left").style.display = "none"
document.getElementById("pause-grid-right").style.display = "none"
@@ -540,6 +543,7 @@ const simulation = {
document.body.style.cursor = "auto";
setTimeout(() => {
document.getElementById("experiment-button").style.opacity = "1";
+ document.getElementById("training-button").style.opacity = "1";
document.getElementById("info").style.opacity = "1";
document.getElementById("splash").style.opacity = "1";
}, 200);
@@ -588,7 +592,7 @@ const simulation = {
requestAnimationFrame(cycle)
}, 1000);
},
- startGame(isBuildRun = false) {
+ startGame(isBuildRun = false, isTrainingRun = false) {
simulation.clearMap()
if (!isBuildRun) { //if a build run logic flow returns to "experiment-button").addEventListener
document.body.style.cursor = "none";
@@ -601,6 +605,7 @@ const simulation = {
document.getElementById("experiment-grid").style.display = "none"
document.getElementById("info").style.display = "none";
document.getElementById("experiment-button").style.display = "none";
+ document.getElementById("training-button").style.display = "none";
// document.getElementById("experiment-button").style.opacity = "0";
document.getElementById("splash").onclick = null; //removes the onclick effect so the function only runs once
document.getElementById("splash").style.display = "none"; //hides the element that spawned the function
@@ -616,7 +621,7 @@ const simulation = {
} else {
Composite.add(engine.world, [player])
}
-
+ if (isTrainingRun) simulation.isTraining = true
level.populateLevels()
input.endKeySensing();
@@ -694,6 +699,7 @@ const simulation = {
tech.healMaxEnergyBonus = 0
m.setMaxEnergy();
m.energy = 0
+ m.immuneCycle = 0;
// simulation.makeTextLog(`${simulation.SVGrightMouse} ${m.fieldUpgrades[m.fieldMode].name}
${m.fieldUpgrades[m.fieldMode].description}`, 600);
// simulation.makeTextLog(`
// input.key.up = ["${input.key.up}", "ArrowUp"]
@@ -751,6 +757,7 @@ const simulation = {
if (b.guns[i].name === "mine") {
if (tech.isCrouchAmmo) count = Math.ceil(count / 2)
b.guns[i].ammo += count
+ if (tech.ammoCap) b.guns[i].ammo = Math.min(tech.ammoCap, b.guns[i].ammo)
simulation.updateGunHUD();
break;
}
@@ -779,6 +786,7 @@ const simulation = {
}
}
}
+ simulation.lastLogTime = 0; //clear previous messages
powerUps.totalPowerUps = powerUp.length
let holdTarget = (m.holdingTarget) ? m.holdingTarget : undefined //if player is holding something this remembers it before it gets deleted
tech.deathSpawnsFromBoss = 0;
diff --git a/js/spawn.js b/js/spawn.js
index a781905..d87316f 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -140,7 +140,9 @@ const spawn = {
me.chaseSpeed = 3.3
me.isMACHO = true;
me.frictionAir = 0.006
-
+ me.onDeath = function() {
+ tech.isHarmMACHO = false;
+ }
me.do = function() {
const sine = Math.sin(simulation.cycle * 0.015)
this.radius = 370 * (1 + 0.1 * sine)
diff --git a/js/tech.js b/js/tech.js
index 3562d29..2423cea 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -13,8 +13,10 @@ const tech = {
tech.tech[i].frequency = 2
}
}
+ //remove lore if it's your first time playing since it's confusing
+ //also remove lore if cheating
lore.techCount = 0;
- if (simulation.isCheating) { //simulation.isCommunityMaps ||
+ if (simulation.isCheating || localSettings.runCount > 1) { //simulation.isCommunityMaps ||
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0;
@@ -219,14 +221,14 @@ const tech = {
if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
if (tech.isLowEnergyDamage) dmg *= 1 + 0.7 * Math.max(0, 1 - m.energy)
if (tech.isMaxEnergyTech) dmg *= 1.5
- if (tech.isEnergyNoAmmo) dmg *= 1.6
- if (tech.isDamageForGuns) dmg *= 1 + 0.14 * b.inventory.length
+ if (tech.isEnergyNoAmmo) dmg *= 1.66
+ if (tech.isDamageForGuns) dmg *= 1 + 0.12 * b.inventory.length
if (tech.isLowHealthDmg) dmg *= 1 + Math.max(0, 1 - m.health) * 0.5
if (tech.isHarmDamage && m.lastHarmCycle + 600 > m.cycle) dmg *= 3;
if (tech.isEnergyLoss) dmg *= 1.55;
if (tech.isAcidDmg && m.health > 1) dmg *= 1.35;
if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage
- if (tech.isEnergyDamage) dmg *= 1 + m.energy / 11;
+ if (tech.isEnergyDamage) dmg *= 1 + m.energy * 0.1;
if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.007
if (tech.isRerollDamage) dmg *= 1 + 0.037 * powerUps.research.count
if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25
@@ -237,7 +239,7 @@ const tech = {
return dmg * tech.slowFire * tech.aimDamage
},
duplicationChance() {
- return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.042 + tech.duplicateChance + m.duplicateChance + tech.wormDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.45 : 0))
+ return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.042 + tech.duplicateChance + m.duplicateChance + tech.wormDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0))
},
isScaleMobsWithDuplication: false,
maxDuplicationEvent() {
@@ -457,7 +459,7 @@ const tech = {
// descriptionFunction() {
// return `increase damage by ${14 * b.inventory.length}%
14% for each gun in your inventory`
// },
- description: "increase damage by 14%
for each gun in your inventory",
+ description: "increase damage by 12%
for each gun in your inventory",
maxCount: 1,
count: 0,
frequency: 1,
@@ -493,24 +495,6 @@ const tech = {
b.setFireCD();
}
},
- {
- name: "logistics",
- description: `${powerUps.orb.ammo()} give 80% more ammo, but
it's only added to your current gun`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isEnergyNoAmmo
- },
- requires: "not exciton",
- effect() {
- tech.isAmmoForGun = true;
- },
- remove() {
- tech.isAmmoForGun = false;
- }
- },
{
name: "supply chain",
junk: 0.05,
@@ -542,10 +526,31 @@ const tech = {
}
}
},
+ {
+ name: "logistics",
+ description: `${powerUps.orb.ammo()} give 80% more ammo, but
it's only added to your current gun`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
+ },
+ requires: "not exciton",
+ effect() {
+ tech.isAmmoForGun = true;
+ },
+ remove() {
+ tech.isAmmoForGun = false;
+ }
+ },
{
name: "cache",
link: `cache`,
description: `${powerUps.orb.ammo()} give 13x more ammo, but
you can't store any more ammo than that`,
+ // ammo powerups always max out your gun,
+ // but the maximum ammo ti limited
+ // description: `${powerUps.orb.ammo()} give 13x more ammo, but
you can't store any more ammo than that`,
maxCount: 1,
count: 0,
frequency: 1,
@@ -580,6 +585,24 @@ const tech = {
tech.isAmmoFromHealth = false;
}
},
+ {
+ name: "exciton",
+ description: `increase damage by 66%, but
${powerUps.orb.ammo()} will no longer spawn`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isAmmoFromHealth
+ },
+ requires: "not catabolism",
+ effect() {
+ tech.isEnergyNoAmmo = true;
+ },
+ remove() {
+ tech.isEnergyNoAmmo = false;
+ }
+ },
{
name: "desublimated ammunition",
link: `desublimated ammunition`,
@@ -743,7 +766,23 @@ const tech = {
tech.isLessDamageReduction = false
}
},
-
+ {
+ name: "microstates",
+ link: `microstates`,
+ description: "increase damage by 7%
for every 10 active projectiles",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ tech.isDamageFromBulletCount = true
+ },
+ remove() {
+ tech.isDamageFromBulletCount = false
+ }
+ },
{
name: "simulated annealing",
description: "increase damage by 20%
20% increased delay after firing",
@@ -798,23 +837,6 @@ const tech = {
tech.isCrit = false;
}
},
- {
- name: "microstates",
- link: `microstates`,
- description: "increase damage by 7%
for every 10 active projectiles",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() { return true },
- requires: "",
- effect() {
- tech.isDamageFromBulletCount = true
- },
- remove() {
- tech.isDamageFromBulletCount = false
- }
- },
{
name: "thermal runaway",
description: "mobs explode when they die",
@@ -1620,7 +1642,7 @@ const tech = {
},
{
name: "complex spin-statistics",
- description: `become immune to harm for 1.5 seconds
once every 7 seconds`,
+ description: `become immune to harm for 1.8 seconds
once every 7 seconds`,
maxCount: 3,
count: 0,
frequency: 1,
@@ -1630,7 +1652,7 @@ const tech = {
},
requires: "",
effect() {
- tech.cyclicImmunity += 90;
+ tech.cyclicImmunity += 108;
},
remove() {
tech.cyclicImmunity = 0;
@@ -1857,24 +1879,24 @@ const tech = {
tech.isAoESlow = false
}
},
- {
- name: "osmoprotectant",
- description: `collisions with stunned or frozen mobs
cause you no harm`,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.isStunField || tech.isExplosionStun || tech.isMineStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isNeedleIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 || tech.iceIXOnDeath || tech.isIceShot
- },
- requires: "a freezing or stunning effect",
- effect() {
- tech.isFreezeHarmImmune = true;
- },
- remove() {
- tech.isFreezeHarmImmune = false;
- }
- },
+ // {
+ // name: "osmoprotectant",
+ // description: `collisions with stunned or frozen mobs
cause you no harm`,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return tech.isStunField || tech.isExplosionStun || tech.isMineStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isNeedleIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 || tech.iceIXOnDeath || tech.isIceShot
+ // },
+ // requires: "a freezing or stunning effect",
+ // effect() {
+ // tech.isFreezeHarmImmune = true;
+ // },
+ // remove() {
+ // tech.isFreezeHarmImmune = false;
+ // }
+ // },
{
name: "liquid cooling",
description: `freeze all mobs for 7 seconds
after receiving harm`,
@@ -1911,22 +1933,6 @@ const tech = {
tech.isSlowFPS = false;
}
},
- {
- name: "quantum immortality",
- description: "reduce harm by 33%
after dying, continue in an alternate reality",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() { return true },
- requires: "",
- effect() {
- tech.isImmortal = true;
- },
- remove() {
- tech.isImmortal = false;
- }
- },
{
name: "MACHO",
description: "a massive but compact object slowly follows you
take 66% less harm inside it's halo",
@@ -1944,6 +1950,7 @@ const tech = {
},
remove() {
tech.isMACHO = false;
+ tech.isHarmMACHO = false;
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isMACHO) mob[i].alive = false;
}
@@ -2218,7 +2225,7 @@ const tech = {
},
{
name: "electronegativity",
- description: "increase damage by 1%
for every 11 stored energy",
+ description: "increase damage by 1%
for every 10 stored energy",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2232,22 +2239,6 @@ const tech = {
tech.isEnergyDamage = false;
}
},
- {
- name: "exciton",
- description: `increase damage by 60%, but
${powerUps.orb.ammo()} will no longer spawn`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() { return true },
- requires: "",
- effect() {
- tech.isEnergyNoAmmo = true;
- },
- remove() {
- tech.isEnergyNoAmmo = false;
- }
- },
{
name: "exothermic process",
description: "increase damage by 50%
if a mob dies drain energy by 25%",
@@ -2426,7 +2417,7 @@ const tech = {
},
{
name: "predator",
- description: "if a mob has died in the last 5 seconds
increase damage 50% and inhibit energy regen",
+ description: "if a mob has died in the last 5 seconds inhibit
passive energy regen and increase damage 50%",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2686,7 +2677,7 @@ const tech = {
},
{
name: "weak anthropic principle",
- description: "after anthropic principle prevents your death
add 45% duplication chance for that level",
+ description: "after anthropic principle prevents your death
add 50% duplication chance for that level",
maxCount: 1,
count: 0,
frequency: 3,
@@ -2722,6 +2713,22 @@ const tech = {
tech.isAnthropicDamage = false
}
},
+ {
+ name: "quantum immortality",
+ description: "reduce harm by 33%
after dying, continue in an alternate reality",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ tech.isImmortal = true;
+ },
+ remove() {
+ tech.isImmortal = false;
+ }
+ },
{
name: "non-unitary operator",
link: `non-unitary operator`,
@@ -2903,7 +2910,7 @@ const tech = {
},
{
name: "brainstorming",
- description: "the tech choice menu randomizes
every 2 seconds for 10 seconds",
+ description: "tech choices randomize
every 2 seconds for 10 seconds",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2922,144 +2929,6 @@ const tech = {
tech.isBrainstormActive = false
}
},
- {
- name: "Born rule",
- description: "remove all current tech
spawn new tech to replace them",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return (tech.totalCount > 6)
- },
- requires: "NOT EXPERIMENT MODE, more than 6 tech",
- effect: () => {
- //remove active bullets //to get rid of bots
- for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
- bullet = [];
- let count = 1 //count tech
- for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
- if (!tech.tech[i].isNonRefundable) count += tech.tech[i].count
- }
- if (tech.isDeterminism) count -= 4 //remove the bonus tech
- if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech
-
- tech.setupAllTech(); // remove all tech
- if (simulation.isCheating) tech.setCheating();
- lore.techCount = 0;
- // tech.addLoreTechToPool();
- for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups
- //have state is checked in m.death()
- },
- remove() {}
- },
- {
- name: "Occam's razor",
- descriptionFunction() {
- return `randomly remove ${this.removePercent * 100}% of your tech
for each removed gain ${this.damagePerRemoved * 100}% damage`
- },
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isNonRefundable: true,
- isBadRandomOption: true,
- allowed() {
- return (tech.totalCount > 6)
- },
- requires: "NOT EXPERIMENT MODE, more than 6 tech",
- removePercent: 0.5,
- damagePerRemoved: 0.5,
- effect() {
- let pool = []
- for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
- if (tech.tech[i].count && !tech.tech[i].isNonRefundable) pool.push(i)
- }
- pool = shuffle(pool); //shuffles order of maps
- let removeCount = 0
- for (let i = 0, len = pool.length * this.removePercent; i < len; i++) removeCount += tech.removeTech(pool[i])
- tech.OccamDamage = 1 + this.damagePerRemoved * removeCount
- // tech.OccamDamage = Math.pow(1.25, removeCount)
- },
- remove() {
- tech.OccamDamage = 0;
- }
- },
- {
- name: "abiogenesis",
- description: `at the start of a level spawn a 2nd boss
use ${powerUps.orb.research(4)}or add 49% JUNK to the tech pool`,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 3) && !tech.isDuplicateBoss
- },
- requires: "at least 4 research and not parthenogenesis",
- effect() {
- tech.isResearchBoss = true; //abiogenesis
- },
- remove() {
- tech.isResearchBoss = false;
- }
- },
- {
- name: "bubble fusion",
- description: `after destroying a mob's natural shield
spawn 1-2 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() { return true },
- requires: "",
- effect() {
- tech.isShieldAmmo = true;
- },
- remove() {
- tech.isShieldAmmo = false;
- }
- },
- {
- name: "meta-analysis",
- description: `if you choose a JUNK tech you instead get a
random normal tech and ${powerUps.orb.research(3)}`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() { return true },
- requires: "",
- effect() {
- tech.isMetaAnalysis = true
- },
- remove() {
- tech.isMetaAnalysis = false
- }
- },
- {
- name: "unified field theory",
- description: `spawn ${powerUps.orb.research(6)}and when paused
clicking the field box switches your field`,
- // description: `in the pause menu, change your field
by clicking on your field's box`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return true
- },
- requires: "not superdeterminism",
- effect() {
- tech.isPauseSwitchField = true;
- for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
- },
- remove() {
- if (tech.isPauseSwitchField) {
- tech.isPauseSwitchField = false;
- powerUps.research.changeRerolls(-6)
- }
- }
- },
{
name: "cross disciplinary",
description: "tech have an extra field or gun choice",
@@ -3117,7 +2986,7 @@ const tech = {
allowed() {
return !tech.isExtraChoice && !tech.isExtraGunField
},
- requires: "not emergence, cross disciplinary",
+ requires: "NOT EXPERIMENT MODE, not emergence, cross disciplinary",
effect: () => {
tech.isDeterminism = true;
//if you change the number spawned also change it in Born rule
@@ -3154,7 +3023,7 @@ const tech = {
allowed() {
return tech.isDeterminism && !tech.isAnsatz
},
- requires: "determinism, not ansatz",
+ requires: "NOT EXPERIMENT MODE, determinism, not ansatz",
effect: () => {
tech.isSuperDeterminism = true;
//if you change the number spawned also change it in Born rule
@@ -3168,6 +3037,174 @@ const tech = {
// }
}
},
+ {
+ name: "unified field theory",
+ description: `spawn ${powerUps.orb.research(6)}and when paused
clicking the field box switches your field`,
+ // description: `in the pause menu, change your field
by clicking on your field's box`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isPauseSwitchField = true;
+ for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ },
+ remove() {
+ if (tech.isPauseSwitchField) {
+ tech.isPauseSwitchField = false;
+ powerUps.research.changeRerolls(-6)
+ }
+ }
+ },
+ {
+ name: "abiogenesis",
+ description: `at the start of a level spawn a 2nd boss
use ${powerUps.orb.research(4)}or add 49% JUNK to the tech pool`,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (build.isExperimentSelection || powerUps.research.count > 3) && !tech.isDuplicateBoss
+ },
+ requires: "at least 4 research and not parthenogenesis",
+ effect() {
+ tech.isResearchBoss = true; //abiogenesis
+ },
+ remove() {
+ tech.isResearchBoss = false;
+ }
+ },
+ {
+ name: "meta-analysis",
+ description: `if you choose a JUNK tech you instead get a
random normal tech and ${powerUps.orb.research(3)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ tech.isMetaAnalysis = true
+ },
+ remove() {
+ tech.isMetaAnalysis = false
+ }
+ },
+ {
+ name: "dark patterns",
+ description: "reduce combat difficulty by 1 level
+31% JUNK to the potential tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return level.onLevel < 8 && level.onLevel > 0
+ },
+ requires: "on levels 1 through 7",
+ effect() {
+ level.difficultyDecrease(simulation.difficultyMode)
+ // simulation.difficulty-=
+ simulation.makeTextLog(`level.difficultyDecrease(simulation.difficultyMode)`)
+ this.refundAmount += tech.addJunkTechToPool(0.31)
+ // for (let i = 0; i < tech.junk.length; i++) tech.tech.push(tech.junk[i])
+ },
+ refundAmount: 0,
+ remove() {
+ if (this.count > 0) {
+ if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
+ level.difficultyIncrease(simulation.difficultyMode)
+ }
+ }
+ },
+ {
+ name: "ergodicity",
+ description: `reduce combat difficulty by 2 levels
${powerUps.orb.heal()} have no effect`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return level.onLevel > 1 && !tech.isEnergyHealth
+ },
+ requires: "past levels 1, not mass-energy",
+ effect() {
+ tech.isNoHeals = true;
+ level.difficultyDecrease(simulation.difficultyMode * 2)
+ simulation.makeTextLog(`level.difficultyDecrease(simulation.difficultyMode * 2)`)
+ powerUps.heal.color = "#abb"
+ for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
+ if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
+ }
+ },
+ remove() {
+ if (tech.isNoHeals) {
+ powerUps.heal.color = "#0eb"
+ for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
+ if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
+ }
+ }
+ tech.isNoHeals = false;
+ if (this.count > 0) level.difficultyIncrease(simulation.difficultyMode * 2)
+ }
+ },
+ {
+ name: "bubble fusion",
+ description: `after destroying a mob's natural shield
spawn 1-2 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ tech.isShieldAmmo = true;
+ },
+ remove() {
+ tech.isShieldAmmo = false;
+ }
+ },
+ {
+ name: "commodities exchange",
+ description: `clicking × to cancel a field, tech, or gun
spawns 5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isCancelRerolls = true
+ },
+ remove() {
+ tech.isCancelRerolls = false
+ }
+ },
+ {
+ name: "futures exchange",
+ description: "clicking × to cancel a field, tech, or gun
adds 4.2% power up duplication chance",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1 && !tech.isSuperDeterminism
+ },
+ requires: "below 100% duplication chance, not superdeterminism",
+ effect() {
+ tech.isCancelDuplication = true //search for tech.cancelCount to balance
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ },
+ remove() {
+ tech.isCancelDuplication = false
+ powerUps.setDupChance(); //needed after adjusting duplication chance
+ }
+ },
{
name: "replication",
description: "10% chance to duplicate spawned power ups
+40% JUNK to the potential tech pool",
@@ -3237,44 +3274,6 @@ const tech = {
powerUps.setDupChance(); //needed after adjusting duplication chance
}
},
- {
- name: "futures exchange",
- description: "clicking × to cancel a field, tech, or gun
adds 4.2% power up duplication chance",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.duplicationChance() < 1 && !tech.isSuperDeterminism
- },
- requires: "below 100% duplication chance, not superdeterminism",
- effect() {
- tech.isCancelDuplication = true //search for tech.cancelCount to balance
- powerUps.setDupChance(); //needed after adjusting duplication chance
- },
- remove() {
- tech.isCancelDuplication = false
- powerUps.setDupChance(); //needed after adjusting duplication chance
- }
- },
- {
- name: "commodities exchange",
- description: `clicking × to cancel a field, tech, or gun
spawns 5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isSuperDeterminism
- },
- requires: "not superdeterminism",
- effect() {
- tech.isCancelRerolls = true
- },
- remove() {
- tech.isCancelRerolls = false
- }
- },
{
name: "correlated damage",
description: "your chance to duplicate power ups
increases your damage by the same percent",
@@ -3331,9 +3330,77 @@ const tech = {
tech.is111Duplicate = false;
}
},
+ {
+ name: "Born rule",
+ description: "remove all current tech
spawn new tech to replace them",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 6)
+ },
+ requires: "NOT EXPERIMENT MODE, more than 6 tech",
+ effect: () => {
+ //remove active bullets //to get rid of bots
+ for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
+ bullet = [];
+ let count = 1 //count tech
+ for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
+ if (!tech.tech[i].isNonRefundable) count += tech.tech[i].count
+ }
+ if (tech.isDeterminism) count -= 4 //remove the bonus tech
+ if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech
+
+ tech.setupAllTech(); // remove all tech
+ if (simulation.isCheating) tech.setCheating();
+ lore.techCount = 0;
+ // tech.addLoreTechToPool();
+ for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups
+ //have state is checked in m.death()
+ },
+ remove() {}
+ },
+ {
+ name: "Occam's razor",
+ // descriptionFunction() {
+ // return `randomly remove ${this.removePercent * 100}% of your tech
for each removed gain ${this.damagePerRemoved * 100}% damage`
+ // },
+ descriptionFunction() {
+ return `randomly remove half your tech
for each removed gain ${this.damagePerRemoved * 100}% damage (~${this.damagePerRemoved * 50 * tech.totalCount}%)`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 100,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 6)
+ },
+ requires: "NOT EXPERIMENT MODE, more than 6 tech",
+ removePercent: 0.5,
+ damagePerRemoved: 0.5,
+ effect() {
+ let pool = []
+ for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
+ if (tech.tech[i].count && !tech.tech[i].isNonRefundable) pool.push(i)
+ }
+ pool = shuffle(pool); //shuffles order of maps
+ let removeCount = 0
+ for (let i = 0, len = pool.length * this.removePercent; i < len; i++) removeCount += tech.removeTech(pool[i])
+ tech.OccamDamage = 1 + this.damagePerRemoved * removeCount
+ // tech.OccamDamage = Math.pow(1.25, removeCount)
+ },
+ remove() {
+ tech.OccamDamage = 0;
+ }
+ },
{
name: "exchange symmetry",
- description: "convert 1 random tech into 2 new guns
recursive tech lose all stacks",
+ description: "remove 1 random tech
spawn 2 new guns",
maxCount: 1,
count: 0,
frequency: 1,
@@ -3365,7 +3432,7 @@ const tech = {
},
{
name: "monte carlo experiment",
- description: "spawn 2 tech
remove 1 random tech",
+ description: "remove 1 random tech
spawn 2 tech",
maxCount: 1,
count: 0,
frequency: 1,
@@ -3496,63 +3563,6 @@ const tech = {
// },
// remove() {}
// },
- {
- name: "dark patterns",
- description: "reduce combat difficulty by 1 level
+31% JUNK to the potential tech pool",
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return level.onLevel < 8 && level.onLevel > 0
- },
- requires: "on levels 1 through 7",
- effect() {
- level.difficultyDecrease(simulation.difficultyMode)
- // simulation.difficulty-=
- simulation.makeTextLog(`level.difficultyDecrease(simulation.difficultyMode)`)
- this.refundAmount += tech.addJunkTechToPool(0.31)
- // for (let i = 0; i < tech.junk.length; i++) tech.tech.push(tech.junk[i])
- },
- refundAmount: 0,
- remove() {
- if (this.count > 0) {
- if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
- level.difficultyIncrease(simulation.difficultyMode)
- }
- }
- },
- {
- name: "ergodicity",
- description: `reduce combat difficulty by 2 levels
${powerUps.orb.heal()} have no effect`,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return level.onLevel > 1 && !tech.isEnergyHealth
- },
- requires: "past levels 1, not mass-energy",
- effect() {
- tech.isNoHeals = true;
- level.difficultyDecrease(simulation.difficultyMode * 2)
- simulation.makeTextLog(`level.difficultyDecrease(simulation.difficultyMode * 2)`)
- powerUps.heal.color = "#abb"
- for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
- if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
- }
- },
- remove() {
- if (tech.isNoHeals) {
- powerUps.heal.color = "#0eb"
- for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
- if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
- }
- }
- tech.isNoHeals = false;
- if (this.count > 0) level.difficultyIncrease(simulation.difficultyMode * 2)
- }
- },
//**************************************************
//************************************************** gun
//************************************************** tech
@@ -4985,8 +4995,8 @@ const tech = {
isGunTech: true,
maxCount: 1,
count: 0,
- frequency: 4,
- frequencyDefault: 4,
+ frequency: 3,
+ frequencyDefault: 3,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormholeSpores
},
@@ -4998,6 +5008,25 @@ const tech = {
tech.isSporeWorm = false
}
},
+ {
+ name: "annelids",
+ description: "increase worm size and damage
between 10% and 120%",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isSporeWorm || tech.isWormShot
+ },
+ requires: "spore gun, shotgun, worms",
+ effect() {
+ tech.wormSize++
+ },
+ remove() {
+ tech.wormSize = 0
+ }
+ },
{
name: "necrophage",
description: "if worms kill their target
they reset their lifespan",
@@ -5009,7 +5038,7 @@ const tech = {
allowed() {
return tech.isSporeWorm || tech.isWormShot
},
- requires: "spore gun, worms",
+ requires: "spore gun, shotgun, worms",
effect() {
tech.wormSurviveDmg = true
},
@@ -5447,7 +5476,7 @@ const tech = {
{
name: "unaaq",
link: `unaaq`, //https://en.wikipedia.org/wiki/Weapon
- description: "increase the size of your harpoon
by 10% of the square root of its ammo",
+ description: "increase the size of your harpoon
by 10% of the square root of harpoon ammo",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -5881,7 +5910,7 @@ const tech = {
},
{
name: "expansion",
- description: "using standing wave field temporarily
expands its radius",
+ description: "using standing wave field
temporarily expands its radius",
// description: "use energy to expand standing wave
the field slowly contracts when not used",
isFieldTech: true,
maxCount: 1,
@@ -6104,6 +6133,26 @@ const tech = {
tech.isFreezeMobs = false
}
},
+ {
+ name: "pair production",
+ description: "picking up a power up gives you 200 energy",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
+ },
+ requires: "molecular assembler or pilot wave",
+ effect: () => {
+ tech.isMassEnergy = true // used in m.grabPowerUp
+ m.energy += 2
+ },
+ remove() {
+ tech.isMassEnergy = false;
+ }
+ },
{
name: "bot manufacturing",
description: `use molecular assembler and ${powerUps.orb.research(2)}
to build 3 random bots`,
@@ -6288,26 +6337,6 @@ const tech = {
if (this.count > 0) powerUps.research.changeRerolls(1)
}
},
- {
- name: "pair production",
- description: "picking up a power up gives you 200 energy",
- isFieldTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
- },
- requires: "molecular assembler or pilot wave",
- effect: () => {
- tech.isMassEnergy = true // used in m.grabPowerUp
- m.energy += 2
- },
- remove() {
- tech.isMassEnergy = false;
- }
- },
// {
// name: "thermal reservoir",
// description: "increase your plasma damage by 100%
plasma temporarily lowers health not energy",
@@ -8790,9 +8819,11 @@ const tech = {
effect() {
const unit = { x: 1, y: 0 }
for (let i = 0; i < 30; i++) {
- const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 600 + 200 * Math.random()))
- spawn.sucker(where.x, where.y, 250)
- mob[mob.length - 1].damageReduction = 0.2
+ const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random()))
+ spawn.sucker(where.x, where.y, 200)
+ const who = mob[mob.length - 1]
+ who.locatePlayer()
+ // who.damageReduction = 0.2
}
},
remove() {}
@@ -8993,7 +9024,7 @@ const tech = {
nailInstantFireRate: null,
isCapacitor: null,
isEnergyNoAmmo: null,
- isFreezeHarmImmune: null,
+ // isFreezeHarmImmune: null,
isSmallExplosion: null,
isExplosionHarm: null,
extraMaxHealth: null,
@@ -9163,5 +9194,6 @@ const tech = {
needleTunnel: null,
isBrainstorm: null,
isBrainstormActive: null,
- brainStormDelay: null
+ brainStormDelay: null,
+ wormSize: null
}
\ No newline at end of file
diff --git a/style.css b/style.css
index 301d9e9..538701f 100644
--- a/style.css
+++ b/style.css
@@ -129,6 +129,14 @@ summary {
transition: opacity 5s ease-in;
}
+#training-button {
+ position: absolute;
+ bottom: 58px;
+ right: 4px;
+ z-index: 12;
+ transition: opacity 5s ease-in;
+}
+
#construct {
display: none;
position: absolute;
diff --git a/todo.txt b/todo.txt
index 437ca4a..7c40a88 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,20 +1,67 @@
******************************************************** NEXT PATCH **************************************************
-powerUpBoss no longer gets invulnerability after death
- but powerUpBossBaby still has it
+first 4 levels of the training maps are live
+ this is very much a work in progress, but I'm putting it up for feedback
-tech: brainstorming - randomize your tech choice menu every 2s for 10s
-JUNK tech: brainstorm - randomize your tech choice menu every 0.5s for 10s
+stunned and frozen mobs do no harm by default
+ removed tech: osmoprotectant - stunned and frozen mobs do no harm
+tech: annelids - randomly increase worm size and damage up to 100%
+
+weak anthropic principle gives 45->50% duplication chance after almost dieing
+complex spin-statistics immune to harm for 1.5->1.8 s every 7 s
+exciton gives 60->66% damage
+electronegativity gives 1% dmg for every 11->10 stored energy
+arsenal gives 14->12% more damage per gun
+pair production is now also a standing wave field tech
+mass-energy takes 10% less damage
+JUNK tech black hole cluster spawns mobs farther away, so you have a better chance to survive
+undefinded tech no longer shows up on your first couple times playing, since it's a distraction for new players
******************************************************** TODO ********************************************************
+door.openClose(); is flipped T/F
+
+balance time dilation with bose einstein (you can freeze everything and take no damage)
+
+training
+ button takes you to a series of levels that teach simple game mechanics
+ make the button more obvious if the account has only played 1-2 times
+ at high levels has some puzzle aspects?
+ uses the lore voice/text code?
+ save training level progress as local variable
+ rooms:
+ jump over wall and gap
+ crouch through tunnel
+ push block onto button to open door
+ pick up a block an drop onto a button to open door
+ fire block at button to open door
+ fire block at mob to open door
+ pick up power ups with field to open door
+ use gun to kill a mob and use it's block body to activate a button to open a door
+ use field to deflect a mob that is stationary, but blocking a passage
+ set health to very low
+ final room, takes you back to the menu, like when winning the game
+ puzzle or combat rooms?
+ boss gauntlet, spawn with nothing but a few power ups and fight 10 bosses
+
+
tech: basic research - heal power ups spawn as research power ups instead, and using research heals you (needs to be pretty low, like 3% health)
tech: maintenance - heals no longer spawn, but using research heals you 100%
+tech reversed regression - mobs take less damage after each time you hit them, but you get +100% damage
+ maybe a gun tech only?
+ what gun?
+
+tech extend fracture analysis to give bonus damage to frozen also, but reduce the 400%->300%?
+
pulsar mobs retarget too easily
also they drift around too much
+convert blocked mobs into bullets
+ only for the very small bullets that move fast after being blocked
+ delete bulletmob and spawn a nail-like bullet with the same properties as the bulletmob
+
electric motors: increases movement speed and jump height, but jumping and moving costs energy
overwrite the key event listeners?
JUNK tech?
@@ -81,8 +128,7 @@ animate going to next level?
Plasma Burner: upgrade for plasma torch, basically just a jet engine. does high damage, but short range, mostly for player movement.
maybe reduce gravity to really low then apply a vector away from mouse direction
-game idea - auto battler with n-gon mob AI and tech
- name: auto-gon
+auto-gon - auto battler with n-gon mob AI and tech
you build a group of mobs and bosses from n-gon
they fight other mobs and bosses
similar research and tech system to n-gon