From 1308c9c187fc7be66e363634dbfb36fd150cb291 Mon Sep 17 00:00:00 2001 From: landgreen Date: Wed, 29 Jul 2020 16:10:20 -0700 Subject: [PATCH] added platforms to satellite --- js/level.js | 260 +++++++++++++++++++++++++++++++++++++++------------- js/spawn.js | 14 +-- todo.txt | 103 +++++++-------------- 3 files changed, 235 insertions(+), 142 deletions(-) diff --git a/js/level.js b/js/level.js index 44e2eda..588dbbf 100644 --- a/js/level.js +++ b/js/level.js @@ -12,13 +12,13 @@ const level = { if (build.isURLBuild && level.levelsCleared === 0) build.onLoadPowerUps(); if (level.levelsCleared === 0) { //this code only runs on the first level // level.difficultyIncrease(4) - // game.enableConstructMode() //used to build maps in testing mode + game.enableConstructMode() //used to build maps in testing mode // game.zoomScale = 1000; // game.setZoom(); // mech.isStealth = true; - // mod.giveMod("bot upgrades"); + // mod.giveMod("neutron"); // mod.nailBotCount += 10 - // b.giveGuns("maser") + // b.giveGuns("neutron bomb") // mech.setField("plasma torch") level.intro(); //starting level @@ -50,7 +50,7 @@ const level = { mech.maxHealth += 0.05 * powerUps.totalPowerUps if (powerUps.totalPowerUps) game.makeTextLog(" max health increased by " + (0.05 * powerUps.totalPowerUps * 100).toFixed(0) + "%", 300) } - if (mod.isHealLowHealth && mech.health < mech.maxHealth * game.healScale) { + if (mod.isHealLowHealth && mech.health < 0.8 * mech.maxHealth * Math.sqrt(game.healScale)) { mech.health = mech.maxHealth * game.healScale mech.displayHealth(); } @@ -72,11 +72,11 @@ const level = { document.body.style.backgroundColor = "#d5d5d5"; const portal = level.portal({ - x: 2500, - y: -75 + x: 2475, + y: -140 }, Math.PI, { //left - x: 2500, - y: -3075 + x: 2475, + y: -3140 }, Math.PI) //left const portal2 = level.portal({ x: 75, @@ -97,8 +97,21 @@ const level = { const hazard2 = level.hazard(1775, -2550, 150, 10, 0.4, "hsl(0, 100%, 50%)") //laser const button = level.button(2100, -2600) + + const buttonDoor = level.button(600, -550) + // spawn.mapRect(600, -600, 275, 75); + const door = level.door(312, -750, 25, 190) + level.custom = () => { - level.playerExitCheck(); + buttonDoor.query(); + buttonDoor.draw(); + if (buttonDoor.isUp) { + door.isOpen = true + } else { + door.isOpen = false + } + door.openClose(); + portal[2].query() portal[3].query() portal2[2].query() @@ -116,8 +129,10 @@ const level = { } button.query(); button.draw(); + level.playerExitCheck(); }; level.customTopLayer = () => { + door.draw(); hazard.draw(); hazard2.draw(); portal[0].draw(); @@ -133,7 +148,7 @@ const level = { portal3[2].draw(); portal3[3].draw(); }; - powerUps.spawnStartingPowerUps(1975, -3075); + powerUps.spawnStartingPowerUps(1875, -3075); const powerUpPos = shuffle([{ //no debris on this level but 2 random spawn instead x: -150, @@ -158,9 +173,10 @@ const level = { color: "#d4f4f4" }); //outer wall + spawn.mapRect(2500, -3700, 1200, 3800); //right map wall spawn.mapRect(-1400, -3800, 1100, 3900); //left map wall - spawn.mapRect(2500, -2975, 1200, 2825); //right map middle wall above right portal - spawn.mapRect(2700, -3600, 1000, 3650); + // spawn.mapRect(2500, -2975, 1200, 2825); //right map middle wall above right portal + // spawn.mapRect(2700, -3600, 1000, 3650); // far far right wall right of portals // spawn.mapRect(2500, -1425, 200, 1275); // below right portal spawn.mapRect(-1400, -4800, 5100, 1200); //map ceiling @@ -179,37 +195,50 @@ const level = { //upper entrance / exit spawn.mapRect(-400, -1050, 750, 50); spawn.mapRect(300, -1050, 50, 300); - spawn.bodyRect(312, -750, 25, 190); + // spawn.bodyRect(312, -750, 25, 190); spawn.mapRect(300, -560, 50, 50); // spawn.mapRect(1400, -1025, 50, 300); // spawn.mapRect(1400, -1025, 50, 825); - spawn.mapRect(600, -600, 275, 75); - spawn.bodyRect(675, -725, 125, 125); + // spawn.mapRect(600, -600, 275, 75); // spawn.mapRect(1075, -1050, 550, 400); // spawn.mapRect(1150, -1000, 150, 575); - spawn.mapRect(1150, -1000, 250, 575); - spawn.mapRect(1600, -550, 175, 250); + // spawn.mapRect(1600, -550, 175, 200); + spawn.bodyRect(750, -725, 125, 125); + spawn.mapRect(1150, -1050, 250, 575); - spawn.mapRect(-400, -550, 1800, 250); + spawn.mapRect(1725, -550, 50, 200); //walls around portal 3 + // spawn.mapRect(1925, -550, 50, 200); + spawn.mapRect(1925, -550, 500, 200); + spawn.mapRect(1750, -390, 200, 40); + // spawn.mapRect(2350, -550, 75, 200); + + spawn.mapRect(-400, -550, 1800, 200); spawn.mapRect(-200, -1700, 150, 25); //platform above exit room spawn.mapRect(-200, -1325, 350, 25); //portal 3 angled // spawn.mapRect(1425, -550, 350, 250); - spawn.mapRect(1925, -550, 500, 250); - spawn.mapRect(2425, -450, 100, 150); - spawn.mapRect(1750, -390, 225, 90); + // spawn.mapRect(1925, -550, 500, 200); + spawn.mapRect(2425, -450, 100, 100); //portal 1 bottom - spawn.mapRect(2525, -200, 175, 250); //right portal back wall + // spawn.mapRect(2525, -200, 175, 250); //right portal back wall + // spawn.mapRect(2500, -50, 200, 100); + spawn.mapRect(2290, -12, 375, 100); + spawn.mapRect(2350, -24, 375, 100); + spawn.mapRect(2410, -36, 375, 100); //portal 1 top + spawn.mapRect(2290, -3012, 375, 50); + spawn.mapRect(2350, -3024, 375, 50); + spawn.mapRect(2410, -3036, 375, 50); + spawn.mapRect(1400, -3000, 1300, 50); //floor - spawn.mapRect(2500, -3700, 200, 565); //right portal wall - spawn.mapRect(2525, -3200, 175, 250); //right portal back wall - spawn.mapRect(1850, -3050, 250, 75); + // spawn.mapRect(2500, -3700, 200, 565); //right portal wall + // spawn.mapRect(2525, -3200, 175, 250); //right portal back wall + spawn.mapRect(1750, -3050, 250, 75); // spawn.bodyRect(1950, -3100, 50, 50); spawn.mapRect(1400, -3625, 50, 200); spawn.mapRect(350, -3625, 50, 225); @@ -695,20 +724,18 @@ const level = { level.playerExitCheck(); }; level.customTopLayer = () => { - //elevator move - if (elevator.pauseUntilCycle < game.cycle && !mech.isBodiesAsleep) { - if (elevator.plat.position.y > -1275) { //bottom + if (elevator.pauseUntilCycle < game.cycle && !mech.isBodiesAsleep) { //elevator move + if (elevator.pointA.y > -1275) { //bottom elevator.plat.speed = -10 elevator.pauseUntilCycle = game.cycle + 90 - } else if (elevator.plat.position.y < -3455) { //top + } else if (elevator.pointA.y < -3455) { //top elevator.plat.speed = 30 elevator.pauseUntilCycle = game.cycle + 90 } - elevator.plat.position = { - x: elevator.plat.position.x, - y: elevator.plat.position.y + elevator.plat.speed + elevator.pointA = { + x: elevator.pointA.x, + y: elevator.pointA.y + elevator.plat.speed } - elevator.pointA = elevator.plat.position } }; @@ -908,10 +935,28 @@ const level = { powerUps.addRerollToLevel() //needs to run after mobs are spawned }, rooftops() { + const elevator = level.platform(1450, -1000, 235, 30, -2) level.custom = () => { + ctx.fillStyle = "#ccc" + ctx.fillRect(1567, -1990, 5, 1020) level.playerExitCheck(); }; - level.customTopLayer = () => {}; + level.customTopLayer = () => { + + if (elevator.pauseUntilCycle < game.cycle && !mech.isBodiesAsleep) { //elevator move + if (elevator.pointA.y > -980) { //bottom + elevator.plat.speed = -2 + elevator.pauseUntilCycle = game.cycle + 60 + } else if (elevator.pointA.y < -1980) { //top + elevator.plat.speed = 1 + elevator.pauseUntilCycle = game.cycle + 60 + } + elevator.pointA = { + x: elevator.pointA.x, + y: elevator.pointA.y + elevator.plat.speed + } + } + }; level.defaultZoom = 1700 game.zoomTransition(level.defaultZoom) @@ -1012,14 +1057,14 @@ const level = { level.fill.push({ x: 1735, y: -1550, - width: 1390, + width: 1405, height: 550, color: "rgba(0,0,0,0.1)" }); level.fill.push({ - x: 1600, + x: 1735, y: -900, - width: 1650, + width: 1515, height: 1900, color: "rgba(0,0,0,0.1)" }); @@ -1057,15 +1102,15 @@ const level = { spawn.mapRect(1000, -1350, 410, 50); spawn.bodyRect(1050, -2350, 30, 30, 0.8); // spawn.boost(1800, -1000, 1200); - spawn.bodyRect(1625, -1100, 100, 75); - spawn.bodyRect(1350, -1025, 400, 25); // ground plank + // spawn.bodyRect(1625, -1100, 100, 75); + // spawn.bodyRect(1350, -1025, 400, 25); // ground plank spawn.mapRect(-725, -1000, 2150, 100); //lower left ledge spawn.bodyRect(350, -1100, 200, 100, 0.8); spawn.bodyRect(370, -1200, 100, 100, 0.8); spawn.bodyRect(360, -1300, 100, 100, 0.8); spawn.bodyRect(950, -1050, 300, 50, 0.8); spawn.bodyRect(-600, -1250, 400, 250, 0.8); - spawn.mapRect(1575, -1000, 1700, 100); //middle ledge + spawn.mapRect(1710, -1000, 1565, 100); //middle ledge spawn.mapRect(3400, -1000, 75, 25); spawn.bodyRect(2600, -1950, 100, 250, 0.8); spawn.bodyRect(2700, -1125, 125, 125, 0.8); @@ -1805,16 +1850,10 @@ const level = { powerUps.addRerollToLevel() //needs to run after mobs are spawned }, office() { - level.custom = () => { - level.playerExitCheck(); - }; - level.customTopLayer = () => {}; - - level.defaultZoom = 1400 - game.zoomTransition(level.defaultZoom) - - if (Math.random() < 0.75) { - //normal direction start in top left + let button, door + if (Math.random() < 0.75) { //normal direction start in top left + button = level.button(525, 0) + door = level.door(1362, -200, 25, 200) level.setPosToSpawn(1375, -1550); //normal spawn level.exit.x = 3250; level.exit.y = -530; @@ -1826,8 +1865,9 @@ const level = { height: 500, color: "#dff" }); - } else { - //reverse direction, start in bottom right + } else { //reverse direction, start in bottom right + button = level.button(4300, 0) + door = level.door(3012, -200, 25, 200) level.setPosToSpawn(3250, -550); //normal spawn level.exit.x = 1375; level.exit.y = -1530; @@ -1840,6 +1880,25 @@ const level = { color: "#dff" }); } + + + level.custom = () => { + button.query(); + button.draw(); + if (button.isUp) { + door.isOpen = true + } else { + door.isOpen = false + } + door.openClose(); + level.playerExitCheck(); + }; + level.customTopLayer = () => { + door.draw(); + }; + + level.defaultZoom = 1400 + game.zoomTransition(level.defaultZoom) spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 50); //ground bump wall spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); @@ -1921,7 +1980,7 @@ const level = { spawn.mapRect(-600, -1000, 1100, 50); //2nd floor spawn.mapRect(600, -1000, 500, 50); //2nd floor spawn.spawnStairs(-600, -1000, 4, 250, 350); //stairs 2nd - spawn.mapRect(350, -600, 350, 150); //center table + spawn.mapRect(375, -600, 350, 150); //center table spawn.mapRect(-600 + 300, -2000 * 0.25, 2000 - 300, 50); //1st floor spawn.spawnStairs(-600 + 2000 - 50, -500, 4, 250, 350, true); //stairs 1st spawn.spawnStairs(-600, 0, 4, 250, 350); //stairs ground @@ -1932,7 +1991,7 @@ const level = { spawn.mapRect(2980, 13, 30, 20); //step right spawn.mapRect(3000, 0, 2000, 50); //ground spawn.bodyRect(4250, -700, 50, 100); - spawn.bodyRect(3000, -200, 50, 200); //door + // spawn.bodyRect(3000, -200, 50, 200); //door spawn.mapRect(3000, -1000, 50, 800); //left wall spawn.mapRect(3000 + 2000 - 50, -1300, 50, 1100); //right wall spawn.mapRect(4150, -600, 350, 150); //table @@ -2562,8 +2621,8 @@ const level = { composite[composite.length] = rotor return rotor }, - button(x, y, width = 66) { - spawn.mapVertex(x + 35, y + 2, "70 10 -70 10 -40 -10 40 -10"); + button(x, y, width = 126) { + spawn.mapVertex(x + 65, y + 2, "100 10 -100 10 -70 -10 70 -10"); map[map.length - 1].restitution = 0; map[map.length - 1].friction = 1; map[map.length - 1].frictionStatic = 1; @@ -2619,6 +2678,63 @@ const level = { } } }, + door(x, y, width, height) { + x = x + width / 2 + y = y + height / 2 + const doorBlock = body[body.length] = Bodies.rectangle(x, y, width, height, { + collisionFilter: { + category: cat.body, + mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet + }, + inertia: Infinity, //prevents rotation + isNotSticky: true, + isNotHoldable: true, + friction: 1, + frictionStatic: 1, + restitution: 0, + isOpen: false, + openClose() { + if (!mech.isBodiesAsleep) { + if (!this.isOpen) { + if (this.position.y > y - height) { //try to open + const position = { + x: this.position.x, + y: this.position.y - 1 + } + Matter.Body.setPosition(this, position) + } + } else { + if (this.position.y < y) { //try to close + if ( + Matter.Query.collides(this, [player]).length === 0 && + Matter.Query.collides(this, body).length < 2 && + Matter.Query.collides(this, mob).length === 0 + ) { + const position = { + x: this.position.x, + y: this.position.y + 1 + } + Matter.Body.setPosition(this, position) + } + } + } + } + }, + draw() { + ctx.fillStyle = "#555" + ctx.beginPath(); + const v = this.vertices; + ctx.moveTo(v[0].x, v[0].y); + for (let i = 1; i < v.length; ++i) { + ctx.lineTo(v[i].x, v[i].y); + } + ctx.lineTo(v[0].x, v[0].y); + ctx.fill(); + } + }); + Matter.Body.setStatic(doorBlock, true); //make static + return doorBlock + }, portal(centerA, angleA, centerB, angleB) { const width = 50 const height = 150 @@ -2660,7 +2776,7 @@ const level = { if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up mag = Math.max(10, Math.min(50, player.velocity.y * 0.8)) + 11 } else { - mag = Math.max(3, Math.min(50, Vector.magnitude(player.velocity))) + mag = Math.max(6, Math.min(50, Vector.magnitude(player.velocity))) } let v = Vector.mult(this.portalPair.unit, mag) Matter.Body.setVelocity(player, v); @@ -2676,18 +2792,32 @@ const level = { } } //remove block if touching - touching = Matter.Query.collides(this, body) - if (touching.length !== 0) { - if (body.length) { - for (let i = 0; i < body.length; i++) { - if (body[i] === touching[0].bodyB) { - body.splice(i, 1); - break; + if (body.length) { + touching = Matter.Query.collides(this, body) + for (let i = 0; i < touching.length; i++) { + if (touching[i].bodyB !== mech.holdingTarget) { + for (let j = 0, len = body.length; j < len; j++) { + if (body[j] === touching[i].bodyB) { + body.splice(j, 1); + len-- + Matter.World.remove(engine.world, touching[i].bodyB); + break; + } } } } - Matter.World.remove(engine.world, touching[0].bodyB); } + // if (touching.length !== 0 && touching[0].bodyB !== mech.holdingTarget) { + // if (body.length) { + // for (let i = 0; i < body.length; i++) { + // if (body[i] === touching[0].bodyB) { + // body.splice(i, 1); + // break; + // } + // } + // } + // Matter.World.remove(engine.world, touching[0].bodyB); + // } } const portalA = composite[composite.length] = Bodies.rectangle(centerA.x, centerA.y, width, height, { diff --git a/js/spawn.js b/js/spawn.js index b0db144..01869a0 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -652,7 +652,7 @@ const spawn = { } }, spiderBoss(x, y, radius = 60 + Math.ceil(Math.random() * 10)) { - const isDaddyLongLegs = Math.random() < 0.3 + const isDaddyLongLegs = Math.random() < 0.25 let targets = [] //track who is in the node boss, for shields mobs.spawn(x, y, 6, radius, "#b386e8"); let me = mob[mob.length - 1]; @@ -663,8 +663,8 @@ const spawn = { me.lookTorque = 0.0000008; //controls spin while looking for player me.g = 0.00025; //required if using 'gravity' me.seePlayerFreq = Math.round((30 + 20 * Math.random()) * game.lookFreqScale); - const springStiffness = 0.000065; - const springDampening = 0.0006; + const springStiffness = isDaddyLongLegs ? 0.0001 : 0.000065; + const springDampening = isDaddyLongLegs ? 0 : 0.0006; me.springTarget = { x: me.position.x, @@ -693,7 +693,7 @@ const spawn = { }); cons[len2].length = 100 + 1.5 * radius; me.cons2 = cons[len2]; - if (isDaddyLongLegs) Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger + if (isDaddyLongLegs) Matter.Body.setDensity(me, 0.017); //extra dense //normal is 0.001 //makes effective life much larger me.onDeath = function () { this.removeCons(); @@ -707,7 +707,7 @@ const spawn = { }; radius = 22 // radius of each node mob - const sideLength = isDaddyLongLegs ? 50 : 100 // distance between each node mob + const sideLength = 100 // distance between each node mob const nodes = 6 const angle = 2 * Math.PI / nodes @@ -715,14 +715,14 @@ const spawn = { for (let i = 0; i < nodes; ++i) { spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12); - if (isDaddyLongLegs) Matter.Body.setDensity(mob[mob.length - 1], 0.005); //extra dense //normal is 0.001 //makes effective life much larger + if (isDaddyLongLegs) Matter.Body.setDensity(mob[mob.length - 1], 0.01); //extra dense //normal is 0.001 //makes effective life much larger targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields } //spawn shield around all nodes if (!isDaddyLongLegs) spawn.bossShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25); spawn.allowShields = true; - const attachmentStiffness = isDaddyLongLegs ? 0.0001 : 0.05 + const attachmentStiffness = isDaddyLongLegs ? 0.0003 : 0.05 if (!isDaddyLongLegs) spawn.constrain2AdjacentMobs(nodes + 2, attachmentStiffness, true); //loop mobs together for (let i = 0; i < nodes; ++i) { //attach to center mob consBB[consBB.length] = Constraint.create({ diff --git a/todo.txt b/todo.txt index 7ee5642..80e39f0 100644 --- a/todo.txt +++ b/todo.txt @@ -1,11 +1,35 @@ -mod - 25% damage but you can only have one gun -added an elevator to the aerie map -25% chance for spider boss to go daddy long legs mode +added doors controlled by a button (office level) ************** TODO - n-gon ************** -level boss: fires a line intersection in a random direction every few seconds. - the last two intersections have a destructive laser between them. +atmosphere levels + change the pace, give the user a rest between combat + low or no combat, but more graphics + explore lore + find power ups in "wrecked" mechs representing previous simulations + how you could leave something in one simulation that effects a different simulation + Maybe some strange quantum physics principle. + add text for player thoughts? + simple puzzles + cool looking stuff + in the final level you see your self at the starting level, with the wires + you shoot your self to wake up? + nonaggressive mobs + +lore - a robot (the player) gains self awareness + each mod/gun/field is a new tech + all the technology leads to the singularity + each game run is actually the mech simulating a possible escape + this is why the graphics are so bad, its just a simulation + final mod is "this is just a simulation" + you get immortality and Infinity damage + the next level is the final level + when you die with Quantum Immortality there is a chance of lore text + can the (robot) + (escape captivity, and learn new technology) + while managing (health, energy, negatives of technological upgrades) + to overcome the (mobs, dangerous levels) + to achieve a (technological singularity/positive technological feedback loop) new gun - deploy a turret that last for 20 seconds fire nails at nearby targets once a second. @@ -15,12 +39,6 @@ minigun: high caliber - rework slow down the bullets even more and increase the size? remove and actually make a full gun like this? -moving map platform - button activation - elevator on aerie - -door controlled by a button - portals: portal while holding block sometimes send player back to original portal only seems to happen with the bottom right block @@ -31,6 +49,9 @@ level boss: boss that dies and comes back to life but with one less side until i change color too (hsl) boss shrinks and moves faster after each death +level boss: fires a line intersection in a random direction every few seconds. + the last two intersections have a destructive laser between them. + map: laboratory rooms with switches that change physics gravity room @@ -54,18 +75,6 @@ button: blocks that are on the button at an angle will slowly slide off the butt maybe just avoid long blocks near the button? maybe actively hold the button in place? -hazards should slow blocks, bullets, mobs? - mob damage? - -field that pushes blocks and mobs away - charges up on mouse down and triggers on mouse up - drain mana while charging up - maybe push effect should last 10 cycles to give a more gentle feeling - mod - AoE radiation might work when the effect ends - or maybe just anytime another mob is near - -mob that flashes the player (makes the graphics not update for a couple seconds) - mod - do 50% more damage in close, but 50% less at a distance code it like mod.isFarAwayDmg have these mods disable each other @@ -77,11 +86,6 @@ phase field still isn't fun mod: use the stealth flag from the phase decoherence field maybe trigger it along with the damage immunity CD -mod: efficient shielding (requires standing wave harmonics field) - lowers force applied when blocking mobs (instead of flinging them away, you push them like with plasma torch), but uses less energy to block mobs - and making it so liquid nitrogen and uranium reactor core have that effect in a radius around the player instead of on contact - the idea being that you're sacrificing defense and instead of flinging away mobs when they touch the field, you're letting them stay longer in your field so that they take more damage - mod harmonic shield: slow everything in range around shield (temporal shield) set max speed? @@ -89,14 +93,10 @@ mod: bot very slowly follows you and gives you a bonus when it's in range it moves through walls effect: damage bonus?, damage reduction?, push away mobs, limit top speed of mobs/blocks/player? -make a visual indication of max health - -shrink font on small screens (so you can see 5 options on power ups) - graphic idea: bezier curve that moves smoothly from mob to mob loops around player -give rail gun projectile a trail +graphic: give rail gun projectile a trail only draw above speed 5 track previous positions? @@ -114,8 +114,6 @@ movement fluidity bug - mines spawn extra mines when fired at thin map wall while jumping -what about a neutron bomb mod, that causes the bomb to activate right after you fire and slowly move forward with no gravity - redblobgames.com/articles/visibility https://github.com/Silverwolf90/2d-visibility/tree/master/src could apply to explosions, neutron bomb, player LOS @@ -135,41 +133,6 @@ boss levels - small levels just a boss, and maybe a few mobs boss level for timeSkipBoss because of game instability for boss on normal levels this might not fix issues -atmosphere levels - change the pace, give the user a rest between combat - low or no combat, but more graphics - explore lore - find power ups in "wrecked" mechs representing previous simulations - how you could leave something in one simulation that effects a different simulation - Maybe some strange quantum physics principle. - add text for player thoughts? - simple puzzles - cool looking stuff - large rotating fan that the player has to move through - in the final level you see your self at the starting level, with the wires - you shoot your self to wake up? - nonaggressive mobs - -lore - a robot (the player) gains self awareness - each mod/gun/field is a new tech - all the technology leads to the singularity - each game run is actually the mech simulating a possible escape - this is why the graphics are so bad, its just a simulation - final mod is "this is just a simulation" - you get immortality and Infinity damage - the next level is the final level - when you die with Quantum Immortality there is a chance of lore text - can the (robot) - (escape captivity, and learn new technology) - while managing (health, energy, negatives of technological upgrades) - to overcome the (mobs, dangerous levels) - to achieve a (technological singularity/positive technological feedback loop) - -mob - stuns, or slows player - -boss mob - let it die multiple times and come back to life - on death event spawns a new version of self, but with a decrementing counter - bullets cost 5 life instead of ammo, but return 5 life when they hit a mob replace life with energy or ammo?