From 9dc5c8d456af4c9934970d12ecfc373e84ee9def Mon Sep 17 00:00:00 2001 From: landgreen Date: Mon, 20 Dec 2021 12:03:38 -0800 Subject: [PATCH] training maps 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 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 --- .DS_Store | Bin 6148 -> 6148 bytes index.html | 5 + js/bullet.js | 12 +- js/engine.js | 2 +- js/index.js | 14 +- js/level.js | 404 +++++++++++++++++++++++-- js/lore.js | 2 +- js/player.js | 7 +- js/simulation.js | 12 +- js/spawn.js | 4 +- js/tech.js | 762 ++++++++++++++++++++++++----------------------- style.css | 8 + todo.txt | 58 +++- 13 files changed, 860 insertions(+), 430 deletions(-) diff --git a/.DS_Store b/.DS_Store index 2d627628af64461e39cfdcacb69b8d35fbbbbffc..3105f253b29803032143069fb786af59e5960c53 100644 GIT binary patch delta 21 ccmZoMXffEJ#muy#YqAcrA7jJjYUWN608OI?*#H0l delta 21 ccmZoMXffEJ#mp36KUs&_k8#1~YUWN607@zbr2qf` diff --git a/index.html b/index.html index 35e9b36..7c463e8 100644 --- a/index.html +++ b/index.html @@ -93,6 +93,11 @@ experiment + + + training + +
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