From bf7a22f243ef9e052ac8b9862a8f23efa116c4cc Mon Sep 17 00:00:00 2001 From: landgreen Date: Wed, 22 Dec 2021 08:59:10 -0800 Subject: [PATCH] more training levels more training levels: "trainingWalk", "trainingCrouch", "trainingJump", "trainingHold", "trainingThrow", "trainingHit", "trainingHeal", "trainingFire", "trainingDeflect" tech: Bose Einstein condensate is removed until I can balance it bug fixes --- .DS_Store | Bin 6148 -> 6148 bytes js/bullet.js | 11 +- js/level.js | 640 +++++++++++++++++++++++++++++++++++++---------- js/lore.js | 12 + js/player.js | 63 ++--- js/simulation.js | 10 +- js/tech.js | 49 ++-- style.css | 9 +- todo.txt | 69 ++--- 9 files changed, 620 insertions(+), 243 deletions(-) diff --git a/.DS_Store b/.DS_Store index 3105f253b29803032143069fb786af59e5960c53..c8937b9596e21d79257fbcba1e2df80e3f8fc3c1 100644 GIT binary patch delta 21 ccmZoMXffEJ#mw|Ubg~Y!A7jGiYUWN6080-Bi~s-t delta 21 ccmZoMXffEJ#muy#YqAcrA7jJjYUWN608OI?*#H0l diff --git a/js/bullet.js b/js/bullet.js index f831f8e..094e361 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -376,7 +376,7 @@ const b = { if (m.immuneCycle < m.cycle) m.energy -= DRAIN if (m.energy < 0) { m.energy = 0 - m.damage(0.03 * (tech.isRadioactiveResistance ? 0.25 : 1)); + if (simulation.dmgScale) m.damage(0.03 * (tech.isRadioactiveResistance ? 0.25 : 1)); } } @@ -423,9 +423,9 @@ const b = { const harm = radius * (tech.isExplosionHarm ? 0.00055 : 0.00018) if (tech.isImmuneExplosion) { const mitigate = Math.min(1, Math.max(1 - m.energy * 0.5, 0)) - m.damage(mitigate * harm); + if (simulation.dmgScale) m.damage(mitigate * harm); } else { - m.damage(harm); + if (simulation.dmgScale) m.damage(harm); } knock = Vector.mult(Vector.normalise(sub), -Math.sqrt(dmg) * player.mass * 0.013); player.force.x += knock.x; @@ -1084,7 +1084,7 @@ const b = { if (m.immuneCycle < m.cycle) m.energy -= DRAIN } else { m.energy = 0; - m.damage(tech.isRadioactiveResistance ? 0.00016 * 0.25 : 0.00016) //0.00015 + if (simulation.dmgScale) m.damage(tech.isRadioactiveResistance ? 0.00016 * 0.25 : 0.00016) //0.00015 } } //aoe damage to mobs @@ -1929,7 +1929,6 @@ const b = { y: best.who.velocity.y * 0.7 }); //draw mob damage circle - console.log(dmg) simulation.drawList.push({ x: path[1].x, y: path[1].y, @@ -2928,7 +2927,7 @@ const b = { if (m.immuneCycle < m.cycle) m.energy -= DRAIN } else { m.energy = 0; - m.damage(tech.isRadioactiveResistance ? 0.00015 * 0.25 : 0.00015) //0.00015 + if (simulation.dmgScale) m.damage(tech.isRadioactiveResistance ? 0.00015 * 0.25 : 0.00015) //0.00015 } } //aoe damage to mobs diff --git a/js/level.js b/js/level.js index c16effd..5725304 100644 --- a/js/level.js +++ b/js/level.js @@ -8,7 +8,7 @@ const level = { onLevel: -1, levelsCleared: 0, playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber"], - trainingLevels: ["trainingHold", "trainingThrow", "trainingCrouch", "trainingJump"], + trainingLevels: ["trainingWalk", "trainingCrouch", "trainingJump", "trainingHold", "trainingThrow", "trainingHit", "trainingHeal", "trainingFire", "trainingDeflect"], levels: [], start() { if (level.levelsCleared === 0) { //this code only runs on the first level @@ -17,11 +17,9 @@ const level = { // localSettings.levelsClearedLastGame = 10 // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // simulation.isHorizontalFlipped = true - // m.setField("plasma torch") - // b.giveGuns("spores") - // b.giveGuns("nail gun") + // m.setField("pilot wave") // b.giveGuns("harpoon") - // tech.giveTech("nematodes") + // tech.giveTech("Bose Einstein condensate") // 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") @@ -29,9 +27,9 @@ const level = { // 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.trainingThrow(); + // level.trainingDeflect(); if (simulation.isTraining) { - level.trainingHold(); + level.trainingWalk(); } else { level.intro(); //starting level } @@ -136,7 +134,13 @@ 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 + trainingText(say) { + simulation.lastLogTime = 0; //clear previous messages + simulation.makeTextLog(`supervised.learning(${(Date.now()/1000).toFixed(0)} s):
${say}
`, Infinity) + // lore.trainer.text("Wow. Just a platform.") + }, + trainingBackgroundColor: "#e1e1e1", + trainingWalk() { //learn to walk m.addHealth(Infinity) document.getElementById("health").style.display = "none" //hide your health bar document.getElementById("health-bg").style.display = "none" @@ -149,20 +153,18 @@ const level = { simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) - document.body.style.backgroundColor = "#e1e1e1"; + document.body.style.backgroundColor = level.trainingBackgroundColor simulation.lastLogTime = 0; //clear previous messages let instruction = 0 - simulation.makeTextLog(`hold down ${input.key.up} longer to jump higher`, Infinity) + level.trainingText(`move with ${input.key.left.replace('Key', '').replace('Digit', '')} and ${input.key.right.replace('Key', '').replace('Digit', '')}`) level.custom = () => { - if (instruction === 0 && m.pos.x > 300) { + if (instruction === 0 && input.right) { instruction++ - simulation.lastLogTime = 0; //clear previous messages - simulation.makeTextLog(`hold down ${input.key.up} longer to jump higher`, Infinity) + level.trainingText(`move with ${input.key.left.replace('Key', '').replace('Digit', '')} and ${input.key.right.replace('Key', '').replace('Digit', '')} +
exit through the blue door`) } - - m.health = 1 //can't die //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) @@ -171,21 +173,20 @@ const level = { 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, 0, 3500, 1800); //floor + spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof - + spawn.mapRect(700, -8, 50, 25); + spawn.mapRect(725, -16, 75, 25); + spawn.mapRect(1375, -16, 50, 50); + spawn.mapRect(1400, -8, 50, 25); + spawn.mapRect(750, -24, 650, 100); spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, @@ -203,17 +204,14 @@ const level = { simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) - document.body.style.backgroundColor = "#e1e1e1"; + document.body.style.backgroundColor = level.trainingBackgroundColor - simulation.lastLogTime = 0; //clear previous messages let instruction = 0 - simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity) - + level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) level.custom = () => { if (instruction === 0 && input.down) { instruction++ - simulation.lastLogTime = 0; //clear previous messages - simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity) + level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) } //exit room ctx.fillStyle = "#f2f2f2" @@ -251,6 +249,131 @@ const level = { spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, + trainingJump() { //learn to jump + 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 = level.trainingBackgroundColor + + let instruction = 0 + level.trainingText(`hold down ${input.key.up.replace('Key', '').replace('Digit', '')} longer to jump higher`) + + level.custom = () => { + if (instruction === 0 && m.pos.x > 300) { + instruction++ + level.trainingText(`hold down ${input.key.up.replace('Key', '').replace('Digit', '')} longer to jump higher`) + } + 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.05)" + ctx.fillRect(1000, 0, 450, 1800) + ctx.fillRect(1000, -2800, 450, 2200) + //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); //floor + spawn.mapRect(1450, 0, 1075, 1800); //floor + spawn.mapRect(-250, -2800, 1250, 2200); //roof + spawn.mapRect(1450, -2800, 1075, 2200); //roof + spawn.mapVertex(375, 0, "150 0 -150 0 -100 -50 100 -50"); //base + + spawn.mapRect(1600, -1200, 500, 850); //exit roof + 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 = level.trainingBackgroundColor + + 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) + + let instruction = 0 + level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse`) + + level.custom = () => { + if (instruction === 0 && input.field) { + instruction++ + level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse
release your field on a block to pick it up`) + } else if (instruction === 1 && m.isHolding) { + instruction++ + level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse
release your field on a block to pick it up

drop the block on the red button to open the door`) + } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) { + instruction++ + level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse
release your field on a block to pick it up
drop the block on the red button to open the door
`) + } + //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.isClosing = true + } else { + door.isClosing = 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 + }, trainingThrow() { //throw a block on button to open door m.addHealth(Infinity) //hide your health bar @@ -265,37 +388,32 @@ const level = { simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) - document.body.style.backgroundColor = "#e1e1e1"; + document.body.style.backgroundColor = level.trainingBackgroundColor 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.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse +
pick up the block with your field`) 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) + level.trainingText(`pick up the block with your field +
hold your field down to charge up then release to throw a block`) } else if (instruction === 1 && m.throwCharge > 2) { instruction++ - simulation.lastLogTime = 0; //clear previous messages - simulation.makeTextLog(`pick up the block with your field + level.trainingText(`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) +
throw the block onto the button`) // 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 + level.trainingText(`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) +
throw the block onto the button
`) } //exit room ctx.fillStyle = "#f2f2f2" @@ -308,9 +426,9 @@ const level = { buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { - door.isOpen = true + door.isClosing = true } else { - door.isOpen = false + door.isClosing = false } door.openClose(); door.draw(); @@ -337,7 +455,7 @@ const level = { 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 + trainingHit() { //throw a block at mob to open door m.addHealth(Infinity) //hide your health bar document.getElementById("health").style.display = "none" @@ -351,29 +469,17 @@ const level = { simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) - document.body.style.backgroundColor = "#e1e1e1"; + document.body.style.backgroundColor = level.trainingBackgroundColor - 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.trainingText(`throw the block at the mobs to open the door`) level.custom = () => { - if (instruction === 0 && input.field) { + if (instruction === 0 && !mob.length) { 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) + level.trainingText(`throw the block at the mobs to open the door`) } //exit room ctx.fillStyle = "#f2f2f2" @@ -383,12 +489,10 @@ const level = { level.playerExitCheck(); }; level.customTopLayer = () => { - buttonDoor.query(); - buttonDoor.draw(); - if (buttonDoor.isUp) { - door.isOpen = true + if (mob.length > 0) { + door.isClosing = true } else { - door.isOpen = false + door.isClosing = false } door.openClose(); door.draw(); @@ -410,9 +514,251 @@ const level = { 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 + spawn.mapRect(1600, -600, 425, 250); + + spawn.bodyRect(1025, -75, 50, 50); //block to go on button + spawn.starter(425, -350, 35) + spawn.starter(800, -350, 44) + }, + trainingHeal() { //learn to heal + m.addHealth(Infinity) + m.health = 0; + m.addHealth(0.25) + document.getElementById("health").style.display = "inline" //show your health bar + document.getElementById("health-bg").style.display = "inline" + + 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 = level.trainingBackgroundColor + + + let instruction = 0 + level.trainingText(`your health is displayed in the top left corner +
use your field to pick up ${powerUps.orb.heal(3)} until your health is full`) + + level.custom = () => { + if (instruction === 0 && m.health === 1) { + instruction++ + level.trainingText(`use your field to pick up ${powerUps.orb.heal(3)} until your health is full`) + } + //exit room + ctx.fillStyle = "#f2f2f2" + ctx.fillRect(1600, -400, 400, 400) + level.exit.draw(); + level.enter.draw(); + level.playerExitCheck(); + }; + level.customTopLayer = () => { + if (m.health !== 1) { + door.isClosing = true + } else { + door.isClosing = 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, 0, 3500, 1800); //floor + + spawn.mapRect(1575, 0, 500, 100); + spawn.mapRect(-250, -2800, 3500, 2200); //roof + + spawn.mapRect(700, -8, 50, 25); + spawn.mapRect(725, -16, 75, 25); + spawn.mapRect(1375, -16, 50, 50); + spawn.mapRect(1400, -8, 50, 25); + spawn.mapRect(750, -24, 650, 100); + powerUps.directSpawn(875, -500, "heal", false, null, 15); + powerUps.directSpawn(1075, -500, "heal", false, null, 25); + powerUps.directSpawn(1275, -500, "heal", false, null, 35); + + const door = level.door(1612.5, -175, 25, 190, 185, 3) + spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, + trainingFire() { //throw a block at mob to open door + level.setPosToSpawn(60, -50); //normal spawn + spawn.mapRect(10, -10, 100, 20); //small platform for player + level.exit.x = 1775; + level.exit.y = 15; + 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 = level.trainingBackgroundColor + + const door = level.door(1612.5, -125, 25, 190, 185, 3) + const buttonDoor = level.button(400, 0) + + + let instruction = 0 + level.trainingText(`use your field to pick up the gun power up`) + + level.custom = () => { + if (instruction === 0 && simulation.isChoosing) { + instruction++ + level.trainingText(`use your field to pick up the gun power up +
choose a gun`) + } else if (instruction === 1 && !simulation.isChoosing) { + instruction++ + level.trainingText(`use your field to pick up the gun power up +
choose a gun
+
use the left mouse button to shoot the mobs`) + } else if (instruction === 2 && mob.length === 0) { + instruction++ + level.trainingText(`use your field to pick up the gun power up +
choose a gun +
use the left mouse button to shoot the mobs
+
drop a block on the red button to open the door`) + } else if (instruction === 3 && !door.isClosing) { + instruction++ + level.trainingText(`use your field to pick up the gun power up +
choose a gun +
use the left mouse button to shoot the mobs +
put a block on the red button to open the door
`) + } + //spawn ammo if you run out + if (!powerUp.length && b.activeGun && b.guns[b.activeGun].ammo === 0 && door.isClosing) { + powerUps.directSpawn(1275, -500, "ammo"); + } + //exit room + ctx.fillStyle = "#f2f2f2" + ctx.fillRect(1600, -350, 400, 400) + level.exit.draw(); + level.enter.draw(); + level.playerExitCheck(); + }; + level.customTopLayer = () => { + buttonDoor.query(); + buttonDoor.draw(); + if (buttonDoor.isUp) { + door.isClosing = true + } else { + door.isClosing = false + } + door.openClose(); + door.draw(); + //exit room glow + ctx.fillStyle = "rgba(0,255,255,0.05)" + ctx.fillRect(1600, -350, 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(-250, -2800, 3500, 2200); //roof + + //ceiling steps + spawn.mapRect(725, -588, 50, 25); + spawn.mapRect(725, -600, 75, 25); + spawn.mapRect(750, -612, 75, 25); + spawn.mapRect(-275, -650, 1025, 87); + + spawn.mapRect(725, 12, 50, 25); + spawn.mapRect(725, 25, 75, 25); + spawn.mapRect(750, 38, 75, 25); + + spawn.mapRect(1600, -600, 425, 300); + spawn.mapRect(1600, -400, 50, 275); + + powerUps.directSpawn(1275, -500, "gun", false); + spawn.starter(900, -300, 35) + spawn.starter(1400, -400, 44) + }, + trainingDeflect() { //learn to jump + m.addHealth(Infinity) + m.health = 1; + document.getElementById("health").style.display = "inline" //show your health bar + document.getElementById("health-bg").style.display = "inline" + + 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 = level.trainingBackgroundColor + + + let instruction = 0 + // activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse + level.trainingText(`use your field to deflect the mobs`) + + level.custom = () => { + if (instruction === 0 && m.pos.x > 1350) { + instruction++ + level.trainingText(`use your field to deflect the mobs`) + } + //teleport to start if hit + if (m.immuneCycle > m.cycle) { + m.energy = m.maxEnergy + Matter.Body.setPosition(player, { x: 60, y: -50 }) + } + //spawn bullets + if (!(simulation.cycle % 5)) { + spawn.sniperBullet(660 + 580 * Math.random(), -2000, 10, 4); + const who = mob[mob.length - 1] + Matter.Body.setVelocity(who, { x: 0, y: 8 }); + who.timeLeft = 300 + } + + + //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.05)" + // ctx.fillRect(450, -2800, 1025, 2200) + //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, 0, 3000, 1800); //floor + spawn.mapRect(-250, -2800, 900, 2200); //roof + spawn.mapRect(1250, -2800, 1275, 2200); //roof + spawn.mapVertex(950, 0, "400 0 -400 0 -300 -50 300 -50"); //base + + spawn.mapRect(1600, -1200, 500, 850); //exit roof + spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall + + //spawn bullets on load to avoid sprint + //spawn bullets + for (let i = 0; i < 32; i++) { + spawn.sniperBullet(660 + 580 * Math.random(), -2000 + 40 * i, 10, 4); + const who = mob[mob.length - 1] + Matter.Body.setVelocity(who, { x: 0, y: 8 }); + who.timeLeft = 300 + } + + }, trainingTemplate() { //learn to crouch m.addHealth(Infinity) document.getElementById("health").style.display = "none" //hide your health bar @@ -426,17 +772,17 @@ const level = { simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) - document.body.style.backgroundColor = "#e1e1e1"; + document.body.style.backgroundColor = level.trainingBackgroundColor + - simulation.lastLogTime = 0; //clear previous messages let instruction = 0 - simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity) + level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) level.custom = () => { if (instruction === 0 && input.down) { instruction++ - simulation.lastLogTime = 0; //clear previous messages - simulation.makeTextLog(`press ${input.key.down} to crouch`, Infinity) + + level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) } //exit room ctx.fillStyle = "#f2f2f2" @@ -530,24 +876,42 @@ const level = { //
m.field.description = "${m.fieldUpgrades[m.fieldMode].description}" // `, 1200); }, + disableExit: false, nextLevel() { - level.levelsCleared++; - // level.difficultyIncrease(simulation.difficultyMode) //increase difficulty based on modes + if (!level.disableExit) { + level.levelsCleared++; + level.onLevel++; //cycles map to next level + if (simulation.isTraining) { + if (level.onLevel > level.levels.length - 1) { + level.disableExit = true + document.getElementById("health").style.display = "none" + document.getElementById("health-bg").style.display = "none" + document.getElementById("text-log").style.opacity = 0; //fade out any active text logs + document.getElementById("fade-out").style.opacity = 1; //slowly fades out + setTimeout(function() { + simulation.paused = true; + level.disableExit = false; + engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) }) + Engine.clear(engine); + simulation.splashReturn(); + }, 6000); + return + } else { + level.setDifficulty() + } + } else { + if (level.onLevel > level.levels.length - 1) level.onLevel = 0; + level.difficultyIncrease(simulation.difficultyMode) + } - //difficulty is increased 5 times when finalBoss dies - // const len = level.levelsCleared / level.levels.length //add 1 extra difficulty step for each time you have cleared all the levels - // for (let i = 0; i < len; i++) - level.difficultyIncrease(simulation.difficultyMode) - - level.onLevel++; //cycles map to next level - if (level.onLevel > level.levels.length - 1) level.onLevel = 0; - //reset lost tech display - for (let i = 0; i < tech.tech.length; i++) { - if (tech.tech[i].isLost) tech.tech[i].isLost = false; + //reset lost tech display + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].isLost) tech.tech[i].isLost = false; + } + tech.isDeathAvoidedThisLevel = false; + simulation.updateTechHUD(); + simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map } - tech.isDeathAvoidedThisLevel = false; - simulation.updateTechHUD(); - simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map }, populateLevels() { if (simulation.isTraining) { @@ -1076,18 +1440,10 @@ const level = { friction: 1, frictionStatic: 1, restitution: 0, - isOpen: false, + isClosing: false, openClose() { if (!m.isBodiesAsleep) { - if (!this.isOpen) { - if (this.position.y > y - distance) { //try to open - const position = { - x: this.position.x, - y: this.position.y - speed - } - Matter.Body.setPosition(this, position) - } - } else { + if (this.isClosing) { if (this.position.y < y) { //try to close if ( Matter.Query.collides(this, [player]).length === 0 && @@ -1101,6 +1457,14 @@ const level = { Matter.Body.setPosition(this, position) } } + } else { + if (this.position.y > y - distance) { //try to open + const position = { + x: this.position.x, + y: this.position.y - speed + } + Matter.Body.setPosition(this, position) + } } } }, @@ -3178,9 +3542,9 @@ const level = { buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { - door.isOpen = true + door.isClosing = true } else { - door.isOpen = false + door.isClosing = false } door.openClose(); @@ -4927,9 +5291,9 @@ const level = { button.query(); button.draw(); if (button.isUp) { - door.isOpen = true + door.isClosing = true } else { - door.isOpen = false + door.isClosing = false } door.openClose(); ctx.fillStyle = "#ccc" @@ -5064,9 +5428,9 @@ const level = { button.query(); button.draw(); if (button.isUp) { - door.isOpen = true + door.isClosing = true } else { - door.isOpen = false + door.isClosing = false } door.openClose(); ctx.fillStyle = "#ccc" @@ -5320,15 +5684,15 @@ const level = { buttonPlateformEnd.query(); // hazard.query(); //bug reported from discord? if (buttonDoor.isUp) { - door.isOpen = false + door.isClosing = false } else { - door.isOpen = true + door.isClosing = true } door.openClose(); if (buttonPlateformEnd.isUp) { - doorPlateform.isOpen = true; + doorPlateform.isClosing = true; } else { - doorPlateform.isOpen = false; + doorPlateform.isClosing = false; } door.openClose(); doorPlateform.openClose(); @@ -5616,7 +5980,7 @@ const level = { let buttonSortieSalle let portalEnBas let portalEnHaut - let door3isOpen = false; + let door3isClosing = false; function drawOnTheMapMapRect(x, y, dx, dy) { spawn.mapRect(x, y, dx, dy); @@ -5839,7 +6203,7 @@ const level = { // me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs // this.removeCons(); //remove constraint // spawnCouloirEnHaut() - // doorSortieSalle.isOpen = false; + // doorSortieSalle.isClosing = false; // }; // if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105); // } else { @@ -5853,11 +6217,11 @@ const level = { if (me) { me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs spawnCouloirEnHaut() - doorSortieSalle.isOpen = false; + doorSortieSalle.isClosing = false; }; } else { spawnCouloirEnHaut() - doorSortieSalle.isOpen = false; + doorSortieSalle.isClosing = false; } // } } else { @@ -5869,11 +6233,11 @@ const level = { if (me) { me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs spawnCouloirEnHaut() - doorSortieSalle.isOpen = false; + doorSortieSalle.isClosing = false; }; } else { spawnCouloirEnHaut() - doorSortieSalle.isOpen = false; + doorSortieSalle.isClosing = false; } } }, @@ -5982,24 +6346,24 @@ const level = { buttonBedroom.draw(); if (buttonBedroom.isUp) { if (hasAlreadyBeenActivated == false) { - doorBedroom.isOpen = true; - doorGrenier.isOpen = true; - voletLucarne1.isOpen = true; - voletLucarne2.isOpen = true; - voletLucarne3.isOpen = true; - voletLucarne4.isOpen = true; - voletLucarne5.isOpen = true; - voletLucarne6.isOpen = true; + doorBedroom.isClosing = true; + doorGrenier.isClosing = true; + voletLucarne1.isClosing = true; + voletLucarne2.isClosing = true; + voletLucarne3.isClosing = true; + voletLucarne4.isClosing = true; + voletLucarne5.isClosing = true; + voletLucarne6.isClosing = true; } } else { - doorBedroom.isOpen = false; - doorGrenier.isOpen = false; - voletLucarne1.isOpen = false; - voletLucarne2.isOpen = false; - voletLucarne3.isOpen = false; - voletLucarne4.isOpen = false; - voletLucarne5.isOpen = false; - voletLucarne6.isOpen = false; + doorBedroom.isClosing = false; + doorGrenier.isClosing = false; + voletLucarne1.isClosing = false; + voletLucarne2.isClosing = false; + voletLucarne3.isClosing = false; + voletLucarne4.isClosing = false; + voletLucarne5.isClosing = false; + voletLucarne6.isClosing = false; if (hasAlreadyBeenActivated == false) { hasAlreadyBeenActivated = true; } @@ -6891,8 +7255,8 @@ const level = { const drip1 = level.drip(1875, -660, -400, 70) const drip2 = level.drip(3525, -940, -400, 150) const drip3 = level.drip(1975, 100, 1200, 100) - door.isOpen = true; - exitDoor.isOpen = true; + door.isClosing = true; + exitDoor.isClosing = true; // UPPER AREA // spawn.mapRect(4500, -2400, 1700, 2050) @@ -7031,7 +7395,7 @@ const level = { if (simulation.difficulty > 3) { spawn.randomLevelBoss(1900, 400, ["shieldingBoss", "shooterBoss", "launcherBoss", "streamBoss"]) } else { - exitDoor.isOpen = false; + exitDoor.isClosing = false; } spawn.secondaryBossChance(800, -800) @@ -7103,9 +7467,9 @@ const level = { } if (g && y && r) { - door.isOpen = false; + door.isClosing = false; } else { - door.isOpen = true; + door.isClosing = true; } door.openClose() @@ -7146,11 +7510,11 @@ const level = { nextBlockSpawn = simulation.cycle + Math.floor(Math.random() * 60 + 30) } - if (exitDoor.isOpen) { - exitDoor.isOpen = false; + if (exitDoor.isClosing) { + exitDoor.isClosing = false; for (i = 0; i < mob.length; i++) { if (mob[i].isBoss && 525 < mob[i].position.x < 3200 && -2500 < mob[i].position.y < 100) { - exitDoor.isOpen = true; + exitDoor.isClosing = true; } } } @@ -7858,7 +8222,7 @@ const level = { return a || ((Math.sqrt((i.position.x - 3600) * (i.position.x - 3600) + (i.position.y + 3600) * (i.position.y + 3600)) < 20000) && i.isDropPowerUp); }, false) && !emergencyActivated; - door.isOpen = hasMob; + door.isClosing = hasMob; door.openClose(); ctx.fillStyle = "#444444" + secretRoomTrans.toString(16); diff --git a/js/lore.js b/js/lore.js index aaae6fd..5256903 100644 --- a/js/lore.js +++ b/js/lore.js @@ -52,6 +52,18 @@ const lore = { sound.portamento(83.333) sound.portamento(166.666) }, + trainer: { + color: "#f20", + voice: undefined, + text: function(say) { + simulation.makeTextLog(`input.audio(${(Date.now()/1000).toFixed(0)} s): "${say}"`, Infinity); + lore.talkingColor = this.color + const utterance = new SpeechSynthesisUtterance(say); + utterance.lang = "en-AU" //"en-IN"; //de-DE en-GB fr-FR en-US en-AU + utterance.volume = 0.2; // 0 to 1 + speechSynthesis.speak(utterance); + }, + }, anand: { color: "#e0c", voice: undefined, diff --git a/js/player.js b/js/player.js index 06d869d..1b57385 100644 --- a/js/player.js +++ b/js/player.js @@ -1446,14 +1446,17 @@ const m = { } } } - if (tech.isFreezeMobs) { - for (let i = 0, len = mob.length; i < len; ++i) { - Matter.Sleeping.set(mob[i], false) - mobs.statusSlow(mob[i], 60) - } - } else { - wake(mob); - } + // if (tech.isFreezeMobs) { + // for (let i = 0, len = mob.length; i < len; ++i) { + // const ICE_DRAIN = 0.0005 + // if (m.energy > ICE_DRAIN) m.energy -= ICE_DRAIN; + // Matter.Sleeping.set(mob[i], false) + // mobs.statusSlow(mob[i], 60) + // } + // } else { + // wake(mob); + // } + wake(mob); wake(body); wake(bullet); for (let i = 0, len = cons.length; i < len; i++) { @@ -1909,20 +1912,20 @@ const m = { y: player.velocity.y * 0.98 }); } - if (tech.isFreezeMobs) { - const ICE_DRAIN = 0.0002 - for (let i = 0, len = mob.length; i < len; i++) { - if (((mob[i].distanceToPlayer() + mob[i].radius) < this.fieldDrawRadius) && !mob[i].shield && !mob[i].isShielded) { - if (m.energy > ICE_DRAIN * 2) { - m.energy -= ICE_DRAIN; - this.fieldDrawRadius -= 2; - mobs.statusSlow(mob[i], 60) - } else { - break; - } - } - } - } + // if (tech.isFreezeMobs) { + // const ICE_DRAIN = 0.0005 + // for (let i = 0, len = mob.length; i < len; i++) { + // if (!mob[i].isMobBullet && !mob[i].shield && !mob[i].isShielded && ((mob[i].distanceToPlayer() + mob[i].radius) < this.fieldDrawRadius)) { + // if (m.energy > ICE_DRAIN * 2) { + // m.energy -= ICE_DRAIN; + // this.fieldDrawRadius -= 2; + // mobs.statusSlow(mob[i], 60) + // } else { + // break; + // } + // } + // } + // } //draw zero-G range ctx.beginPath(); @@ -2809,13 +2812,15 @@ const m = { - if (tech.isFreezeMobs) { - for (let i = 0, len = mob.length; i < len; ++i) { - if (Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) < m.fieldRadius) { - mobs.statusSlow(mob[i], 180) - } - } - } + // if (tech.isFreezeMobs) { + // for (let i = 0, len = mob.length; i < len; ++i) { + // if (!mob[i].isMobBullet && !mob[i].shield && !mob[i].isShielded && Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) < m.fieldRadius + mob[i].radius) { + // const ICE_DRAIN = 0.0005 + // if (m.energy > ICE_DRAIN) m.energy -= ICE_DRAIN; + // mobs.statusSlow(mob[i], 180) + // } + // } + // } ctx.beginPath(); const rotate = m.cycle * 0.008; diff --git a/js/simulation.js b/js/simulation.js index 82ecb3e..dbfc8ae 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -598,6 +598,13 @@ const simulation = { document.body.style.cursor = "none"; document.body.style.overflow = "hidden" } + if (isTrainingRun) { + simulation.isTraining = true + simulation.isNoPowerUps = true + } else { + simulation.isTraining = false + simulation.isNoPowerUps = false; + } simulation.onTitlePage = false; // document.getElementById("choose-grid").style.display = "none" document.getElementById("choose-grid").style.visibility = "hidden" @@ -621,12 +628,11 @@ const simulation = { } else { Composite.add(engine.world, [player]) } - if (isTrainingRun) simulation.isTraining = true level.populateLevels() input.endKeySensing(); b.removeAllGuns(); - simulation.isNoPowerUps = false; + tech.setupAllTech(); //sets tech to default values tech.cancelCount = 0; for (i = 0, len = b.guns.length; i < len; i++) { //find which gun diff --git a/js/tech.js b/js/tech.js index 2423cea..1fe8add 100644 --- a/js/tech.js +++ b/js/tech.js @@ -3374,7 +3374,7 @@ const tech = { maxCount: 1, count: 0, frequency: 1, - frequencyDefault: 100, + frequencyDefault: 1, isNonRefundable: true, isBadRandomOption: true, allowed() { @@ -4972,7 +4972,7 @@ const tech = { }, { name: "mutualism", - description: "increase spore damage by 150%
spores borrow 0.5 health until they die", + description: "increase spore damage by 150%
spores borrow 0.5 health until they die", isGunTech: true, maxCount: 1, count: 0, @@ -6114,25 +6114,25 @@ const tech = { tech.isFlyFaster = false; } }, - { - name: "Bose Einstein condensate", - description: "mobs inside your field are frozen
pilot wave, negative mass, time dilation", - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || (m.fieldUpgrades[m.fieldMode].name === "time dilation" && !tech.isRewindField) - }, - requires: "pilot wave, negative mass, time dilation, not retrocausality", - effect() { - tech.isFreezeMobs = true - }, - remove() { - tech.isFreezeMobs = false - } - }, + // { + // name: "Bose Einstein condensate", + // description: "use energy to freeze mobs in your field
pilot wave, negative mass, time dilation", + // isFieldTech: true, + // maxCount: 1, + // count: 0, + // frequency: 2, + // frequencyDefault: 2, + // allowed() { + // return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || (m.fieldUpgrades[m.fieldMode].name === "time dilation" && !tech.isRewindField) + // }, + // requires: "pilot wave, negative mass, time dilation, not retrocausality", + // effect() { + // tech.isFreezeMobs = true + // }, + // remove() { + // tech.isFreezeMobs = false + // } + // }, { name: "pair production", description: "picking up a power up gives you 200 energy", @@ -7272,7 +7272,7 @@ const tech = { }, { name: "density", - description: `block are 100 times less dense`, + description: `block are 10 times less dense`, maxCount: 1, count: 0, frequency: 0, @@ -7282,14 +7282,15 @@ const tech = { allowed() { return true }, requires: "", effect() { - for (let i = 0; i < body.length; i++) Matter.Body.setDensity(body[i], 0.00001) //set current blocks to low density + for (let i = 0; i < body.length; i++) Matter.Body.setDensity(body[i], 0.0001) //set current blocks to low density + level.addToWorld = () => { for (let i = 0; i < body.length; i++) { if (body[i] !== m.holdingTarget && !body[i].isNoSetCollision) { body[i].collisionFilter.category = cat.body; body[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet } - Matter.Body.setDensity(body[i], 0.00001) //THIS IS THE ONLY ADDED LINE OF CODE + Matter.Body.setDensity(body[i], 0.0001) //THIS IS THE ONLY ADDED LINE OF CODE body[i].classType = "body"; Composite.add(engine.world, body[i]); //add to world } diff --git a/style.css b/style.css index 538701f..54e9dc5 100644 --- a/style.css +++ b/style.css @@ -131,10 +131,15 @@ summary { #training-button { position: absolute; - bottom: 58px; - right: 4px; + bottom: 4px; + right: 0px; + left: 0px; + margin: auto; + /* bottom: 58px; */ + /* right: 4px; */ z-index: 12; transition: opacity 5s ease-in; + } #construct { diff --git a/todo.txt b/todo.txt index 7c40a88..6a53623 100644 --- a/todo.txt +++ b/todo.txt @@ -1,50 +1,41 @@ ******************************************************** NEXT PATCH ************************************************** -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 +more training levels: "trainingWalk", "trainingCrouch", "trainingJump", "trainingHold", "trainingThrow", "trainingHit", "trainingHeal", "trainingFire", "trainingDeflect" -stunned and frozen mobs do no harm by default - removed tech: osmoprotectant - stunned and frozen mobs do no harm +tech: Bose Einstein condensate is removed until I can balance it -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 +bug fixes ******************************************************** TODO ******************************************************** -door.openClose(); is flipped T/F - balance time dilation with bose einstein (you can freeze everything and take no damage) + code is still there, need to balance + balance with energy drain? 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? + make the button more obvious if the account has only played 1-2 times 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? + add vertical tunnels for power ups spawns like in intro? + tutorial rooms: + done walk forwards and backwards + done crouch through tunnel + done jump over wall and gap + done pick up a block an drop onto a button to open door + done fire block at button to open door + done fire block at mob to open door + done pick up heal power ups with field to open door + done use a gun to kill a mob and use it's block body to activate a button to open a door + done use field to deflect bullets + use field to pick up a field and research + research once to open door + puzzle rooms + save training level progress as local variable if puzzles are added + combat rooms: boss gauntlet, spawn with nothing but a few power ups and fight 10 bosses +JUNK tech disable level exit for 5 minutes + level.disableExit = true + setTimeout( () => {level.disableExit = false;}, 5*60000); 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% @@ -67,6 +58,7 @@ electric motors: increases movement speed and jump height, but jumping and movin JUNK tech? mob that fires bullets in 4,5,6,7 different directions at once, no aiming + grow a bit before it fires to indicate state bug once: switching from shotgun to harpoon somehow set b.activeGun to not defined https://discord.com/channels/645222059647172618/646505973610971165/919116288008290324 @@ -103,13 +95,6 @@ mob/boss that fires a laser at player, but give player time to avoid they target where player was 1 second ago they turn to face player? -dart: a new bullet type for string-less harpoons - can turn harder - dart, draw quick line to indicate targeting - can get new targets? -tech: dart - alt fire several small harpoons, with guidance - requires not railgun - tech: open a new tab for n-gon, spawn things in the original game based on events in new game if you die in new die in original? new is n-gon classic? @@ -361,7 +346,7 @@ blue triangle boss can move backwards and aim away from you if set up properly mouse event e.which is deprecated -fix door.isOpen actually meaning isClosed? +fix door.isClosing actually meaning isClosed? make it so that when you are immune to harm you can either jump on mobs or you pass through them