RPG + rocket jump

tech: RPG - gains the rocket jumping effects from electric armor

eternalism no longer makes tech options have 50% opacity when choosing

some new images for cloaking tech
and some images were made brighter

bug fixes
  safari media rules css fixed
This commit is contained in:
landgreen
2023-01-14 19:58:59 -08:00
parent 9206d47f40
commit 43f3cfbae5
31 changed files with 223 additions and 427 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -114,7 +114,7 @@ const b = {
}
},
refundAmmo() { //triggers after firing when you removed ammo for a gun, but didn't need to
if (tech.crouchAmmoCount && input.down) {
if (tech.crouchAmmoCount && input.down && b.activeGun !== null) {
tech.crouchAmmoCount--
if ((tech.crouchAmmoCount) % 2) {
b.guns[b.activeGun].ammo++;
@@ -144,13 +144,13 @@ const b = {
gun = options[Math.floor(Math.random() * options.length)]
}
if (gun === "all") {
b.inventoryGun = 0;
for (let i = 0; i < b.guns.length; i++) {
b.inventory[i] = i;
b.guns[i].have = true;
if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = Math.ceil(b.guns[i].ammoPack * ammoPacks);
}
b.activeGun = 0;
b.inventoryGun = 0;
b.activeGun = b.inventory[0];
} else {
if (isNaN(gun)) { //find gun by name
let found = false;
@@ -167,7 +167,8 @@ const b = {
b.guns[gun].have = true;
if (b.guns[gun].ammo !== Infinity) b.guns[gun].ammo = Math.ceil(b.guns[gun].ammoPack * ammoPacks);
if (b.activeGun === null) {
b.activeGun = gun //if no active gun switch to new gun
b.inventoryGun = 0;
b.activeGun = b.inventory[0] //if no active gun switch to new gun
if (b.guns[b.activeGun].charge) b.guns[b.activeGun].charge = 0; //set foam charge to zero if foam is a new gun
}
// if (tech.infiniteWaveAmmo === 2) b.guns[3].ammo = Infinity
@@ -219,11 +220,10 @@ const b = {
}
if (b.inventory.length > 0) {
b.activeGun = b.inventory[0];
b.inventoryGun = 0;
} else {
b.activeGun = null;
b.inventoryGun = 0;
}
b.inventoryGun = 0;
simulation.makeGunHUD();
break
}
@@ -237,7 +237,10 @@ const b = {
b.guns[i].have = false;
if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0;
}
tech.buffedGun = 0
b.activeGun = null;
b.inventoryGun = 0;
simulation.drawCursor = simulation.drawCursorBasic //set cross hairs
},
bulletRemove() { //run in main loop
//remove bullet if at end cycle for that bullet
@@ -445,9 +448,9 @@ const b = {
if (dist < radius) {
if (simulation.dmgScale) {
const harm = tech.isExplosionHarm ? 0.07 : 0.05
if (tech.isImmuneExplosion && m.energy > 0.12) {
if (tech.isImmuneExplosion && m.energy > 0.25) {
// const mitigate = Math.min(1, Math.max(1 - m.energy * 0.5, 0))
m.energy -= 0.12
m.energy -= 0.25
// m.damage(0.01 * harm); //remove 99% of the damage 1-0.99
knock = Vector.mult(Vector.normalise(sub), -0.6 * player.mass * Math.max(0, Math.min(0.15 - 0.002 * player.speed, 0.15)));
player.force.x = knock.x; // not += so crazy forces can't build up with MIRV
@@ -2759,26 +2762,17 @@ const b = {
if (collide.length > 0) {
for (let i = 0; i < collide.length; i++) {
if (collide[i].bodyA.collisionFilter.category === cat.map) { // || collide[i].bodyB.collisionFilter.category === cat.map) {
const angle = Vector.angle(collide[i].normal, {
x: 1,
y: 0
})
const angle = Vector.angle(collide[i].normal, { x: 1, y: 0 })
Matter.Body.setAngle(this, Math.atan2(collide[i].tangent.y, collide[i].tangent.x))
for (let j = 0; j < 10; j++) { //move until touching map again after rotation
if (Matter.Query.collides(this, map).length > 0) { //touching map
if (angle > -0.2 || angle < -1.5) { //don't stick to level ground
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
Matter.Body.setVelocity(this, { x: 0, y: 0 });
Matter.Body.setStatic(this, true) //don't set to static if not touching map
this.collisionFilter.category = 0
this.collisionFilter.mask = 0 //cat.map | cat.bullet
} else {
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
Matter.Body.setVelocity(this, { x: 0, y: 0 });
Matter.Body.setAngularVelocity(this, 0)
}
this.arm();
@@ -3764,6 +3758,7 @@ const b = {
bullet[me].friction = 0;
if (tech.superHarm) {
bullet[me].collidePlayerDo = function() {
this.force.y += this.mass * 0.0012;
if (Matter.Query.collides(this, [player]).length) {
this.endCycle = 0
let dmg = 0.02 * this.mass * tech.superHarm
@@ -3779,7 +3774,8 @@ const b = {
}
bullet[me].cycle = 0
bullet[me].do = function() {
if (this.cycle > 6) this.do = this.collidePlayerDo
this.cycle++
if (this.cycle > 2) this.do = this.collidePlayerDo
this.force.y += this.mass * 0.0012;
};
} else {

View File

@@ -382,7 +382,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
}
let el = document.getElementById("pause-grid-left")
el.style.display = tech.isNoDraftPause ? "none" : "grid" //disabled for eternalism because eternalism lets the player play while this menu is up but the menu doesn't update
el.style.display = "grid"
el.innerHTML = text
//right side
text = "";
@@ -433,7 +433,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
}
}
el = document.getElementById("pause-grid-right")
el.style.display = tech.isNoDraftPause ? "none" : "grid" //disabled for eternalism because eternalism lets the player play while this menu is up but the menu doesn't update
el.style.display = "grid"
el.innerHTML = text
document.getElementById("tech").style.display = "none"
@@ -500,7 +500,10 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
b.guns[index].count = 0;
b.guns[index].have = false;
if (b.guns[index].ammo != Infinity) b.guns[index].ammo = 0;
if (b.inventory.length === 0) b.activeGun = null;
if (b.inventory.length === 0) {
b.activeGun = null;
b.inventoryGun = 0;
}
simulation.makeGunHUD();
break
}
@@ -698,6 +701,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0;
}
b.activeGun = null;
b.inventoryGun = 0;
simulation.makeGunHUD();
tech.setupAllTech();
build.populateGrid();
@@ -765,6 +769,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
spawn.setSpawnList();
if (b.inventory.length > 0) {
b.activeGun = b.inventory[0] //set first gun to active gun
b.inventoryGun = 0;
simulation.makeGunHUD();
}
for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);

View File

@@ -25,14 +25,14 @@ const level = {
// m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100
// m.couplingChange(5)
// m.setField("perfect diamagnetism") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave plasma torch
// m.setField("metamaterial cloaking") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave plasma torch
// simulation.molecularMode = 2
// m.damage(0.1);
// b.giveGuns("shotgun") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("wave") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.guns[0].ammo = 10000
// tech.giveTech("needle gun")
// tech.giveTech("repeater")
// tech.giveTech("eternalism")
// tech.giveTech("ice-shot")
// for (let i = 0; i < 1; ++i) tech.giveTech("super ball")
// tech.isFoamBall = true
@@ -42,7 +42,8 @@ const level = {
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "boost");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
// level.testing();
// level.testChamber2();
// spawn.nodeGroup(1200, 0, "slasher")
// spawn.blinkBoss(1900, -500)
// spawn.sneakBoss(1900, -500)
// spawn.starter(1900, -500, 200)
@@ -56,12 +57,7 @@ const level = {
// for (let i = 0; i < 40; ++i) tech.giveTech()
// for (let i = 0; i < 13; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research");
//normal starting level ************************************************
if (simulation.isTraining) {
level.walk()
} else {
level.intro()
}
level[simulation.isTraining ? "walk" : "intro"]() //normal starting level ************************************************
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "gun");
@@ -156,7 +152,7 @@ const level = {
//used for generalist and pigeonhole principle
tech.buffedGun++
if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0;
if (tech.isGunCycle) {
if (tech.isGunCycle && b.activeGun !== null && b.inventory.length) {
b.inventoryGun = tech.buffedGun;
simulation.switchGun();
}
@@ -1264,22 +1260,13 @@ const level = {
const width = 50
const height = 150
const mapWidth = 200
const unitA = Matter.Vector.rotate({
x: 1,
y: 0
}, angleA)
const unitB = Matter.Vector.rotate({
x: 1,
y: 0
}, angleB)
const unitA = Matter.Vector.rotate({ x: 1, y: 0 }, angleA)
const unitB = Matter.Vector.rotate({ x: 1, y: 0 }, angleB)
draw = function() {
ctx.beginPath(); //portal
let 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);
}
for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
ctx.fillStyle = this.color
ctx.fill();
}
@@ -1315,10 +1302,7 @@ const level = {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 });
}
}
}
@@ -2827,7 +2811,7 @@ const level = {
}
// const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)")
level.isHazardRise = false //this is set to true to make the slime rise up
const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004, "hsla(160, 100%, 35%,0.75)")
const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004)
hazardSlime.height -= 950
hazardSlime.min.y += 950
hazardSlime.max.y = hazardSlime.min.y + hazardSlime.height
@@ -4464,261 +4448,70 @@ const level = {
},
testChamber2() {
level.setPosToSpawn(0, -50); //lower start
level.exit.y = level.enter.y - 550;
level.setPosToSpawn(0, -65); //lower start
level.exit.y = -1550;
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = level.enter.x;
level.exit.x = -1000;
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
level.defaultZoom = 2200
simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#d0d5d5";
color.map = "#444"
spawn.mapRect(0, -1955, 175, 30);
const removeIndex1 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals
spawn.mapRect(1225, -1955, 175, 30);
const removeIndex2 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals
let portal, portal2, portal3
const hazard = level.hazard((simulation.isHorizontalFlipped ? -350 - 700 : 350), -2025, 700, 10, 0.4) //laser
spawn.mapRect(340, -2032.5, 20, 25); //laser nose
const hazard2 = level.hazard((simulation.isHorizontalFlipped ? -1775 - 150 : 1775), -2550, 150, 10, 0.4) //laser
spawn.mapRect(1920, -2557.5, 20, 25); //laser nose
const button = level.button(2100, -2600)
const buttonDoor = level.button(600, -550)
const door = level.door(312, -750, 25, 190, 185)
const portal = level.portal({ x: 1070, y: -1485 }, -0.9, { x: 475, y: 50 }, -Math.PI / 2)
const hazardSlime = level.hazard(900, -300, 3625, 2550) //hazard(x, y, width, height, damage = 0.002) {
const button = level.button(3975, -1425)
level.custom = () => {
if (!(m.cycle % 60)) { //so much work to catch blocks caught at the bottom of the vertical portals
let touching = Matter.Query.collides(map[removeIndex1], body)
if (touching.length) {
Matter.Composite.remove(engine.world, touching[0].bodyB);
for (let i = 0, len = body.length; i < len; i++) {
if (body[i].id === touching[0].bodyB.id) {
body.splice(i, 1);
break
}
}
}
touching = Matter.Query.collides(map[removeIndex2], body)
if (touching.length) {
Matter.Composite.remove(engine.world, touching[0].bodyB);
for (let i = 0, len = body.length; i < len; i++) {
if (body[i].id === touching[0].bodyB.id) {
body.splice(i, 1);
break
}
}
}
}
buttonDoor.query();
buttonDoor.draw();
if (buttonDoor.isUp) {
door.isClosing = true
} else {
door.isClosing = false
}
door.openClose();
portal[2].query()
portal[3].query()
portal2[2].query()
portal2[3].query()
portal3[2].query()
portal3[3].query()
if (button.isUp) {
hazard.isOn = false;
hazard2.isOn = false;
} else {
hazard.isOn = true;
hazard2.isOn = true;
}
level.exit.drawAndCheck();
level.enter.draw();
button.query();
button.draw();
ctx.fillStyle = "#d4f4f4"
ctx.fillRect(-300, -1000, 650, 500)
level.exit.drawAndCheck();
level.enter.draw();
};
level.customTopLayer = () => {
door.draw();
hazard.opticalQuery();
hazard2.opticalQuery();
hazardSlime.query();
portal[0].draw();
portal[1].draw();
portal[2].draw();
portal[3].draw();
portal2[0].draw();
portal2[1].draw();
portal2[2].draw();
portal2[3].draw();
portal3[0].draw();
portal3[1].draw();
portal3[2].draw();
portal3[3].draw();
ctx.fillStyle = "#444" //below portal
ctx.fillRect(375, 150, 200, 2525);
ctx.fillStyle = "rgba(0,0,0,0.1)" //shadows
ctx.fillRect(-250, -1550, 1250, 1575);
for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query()
};
powerUps.spawnStartingPowerUps(1875, -3075);
const powerUpPos = shuffle([{ //no debris on this level but 2 random spawn instead
x: -150,
y: -1775
}, {
x: 2400,
y: -2650
}, {
x: -175,
y: -1375
}, {
x: 1325,
y: -150
}]);
powerUps.chooseRandomPowerUp(powerUpPos[0].x, powerUpPos[0].y);
powerUps.chooseRandomPowerUp(powerUpPos[1].x, powerUpPos[1].y);
//outer wall
spawn.mapRect(2500, -3700, 1200, 3800); //right map wall
spawn.mapRect(-1400, -3800, 1100, 3900); //left map wall
spawn.mapRect(-1400, -4800, 5100, 1200); //map ceiling
spawn.mapRect(-1400, 0, 5100, 1200); //floor
//lower entrance /exit
spawn.mapRect(300, -375, 50, 225);
spawn.bodyRect(312, -150, 25, 140);
spawn.mapRect(300, -10, 50, 50);
spawn.mapVertex(1555, 0, "625 0 75 0 200 -100 500 -100"); //entrance ramp
//upper entrance / exit
spawn.mapRect(-400, -1050, 750, 50);
spawn.mapRect(300, -1050, 50, 300);
// spawn.bodyRect(312, -750, 25, 190);
spawn.mapRect(300, -560, 50, 50);
spawn.bodyRect(750, -725, 125, 125);
spawn.mapRect(1150, -1050, 250, 575);
spawn.mapRect(1725, -550, 50, 200); //walls around portal 3
spawn.mapRect(1925, -550, 500, 200);
spawn.mapRect(1750, -390, 200, 40);
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(2425, -450, 100, 100);
//portal 1 bottom
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(1750, -3050, 250, 75);
spawn.mapRect(1400, -3625, 50, 200);
spawn.mapRect(350, -3625, 50, 225);
spawn.mapRect(350, -3260, 50, 60);
spawn.mapRect(200, -3250, 1240, 50);
spawn.mapRect(1400, -3260, 50, 310);
spawn.bodyRect(1412, -3425, 25, 165);
spawn.mapRect(-150, -2925, 150, 25);
//portal 2
spawn.mapRect(-300, -2600, 300, 675); //left platform
spawn.mapRect(1400, -2600, 375, 675); //right platform
spawn.mapRect(1925, -2600, 775, 675); //far right platform
spawn.bodyRect(2130, -2660, 50, 50); //button's block
spawn.mapRect(150, -2100, 200, 175);
spawn.mapRect(1050, -2100, 200, 175);
//mobs
spawn.randomMob(1075, -3500, -0.3);
spawn.randomMob(2175, -700, -0.2);
spawn.randomMob(-75, -850, -0.1);
spawn.randomMob(550, -3400, 0);
spawn.randomMob(0, -1175, 0.5);
spawn.randomMob(-75, -1150, 0.5);
spawn.randomMob(1075, -625, 0.5);
spawn.randomMob(800, -3400, -0.3);
spawn.randomMob(1225, -3375, -0.2);
spawn.randomMob(1200, -1125, -0.1);
spawn.randomMob(2050, -950, 0.5);
if (simulation.difficulty > 40) {
spawn.randomMob(2300, -2775, -0.5);
spawn.randomMob(600, -925, -0.5);
spawn.randomMob(1550, -2750, -0.5);
spawn.randomMob(1350, -1150, -0.5);
spawn.randomMob(-75, -1475, 0);
spawn.randomGroup(600, -2600, 0);
}
if (simulation.difficulty > 1) {
if (Math.random() < 0.5) {
spawn.randomLevelBoss(700, -1550);
} else {
spawn.randomLevelBoss(675, -2775); //["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "grenadierBoss"]
}
}
powerUps.addResearchToLevel() //needs to run after mobs are spawned
spawn.secondaryBossChance(1925, -1250)
// spawn.mapRect(-1400, 0, 1800, 1200); //floor
spawn.mapRect(-1400, 0, 1800, 2675);
spawn.mapRect(-1400, -1025, 1225, 1500);
spawn.mapRect(-325, -15, 525, 225);
spawn.mapRect(150, -350, 50, 175);
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
// level.setPosToSpawn(0, -50); //-x // no need since 0
button.min.x = -button.min.x - 126 // flip the button horizontally
button.max.x = -button.max.x + 126 // flip the button horizontally
buttonDoor.min.x = -buttonDoor.min.x - 126 // flip the button horizontally
buttonDoor.max.x = -buttonDoor.max.x + 126 // flip the button horizontally
spawn.mapRect(-1400, -3525, 1600, 3225);
spawn.mapRect(550, 0, 450, 2675);
//this makes the hazard draw, but not collide for reasons I don't understand
//so don't use it, instead just call the hazard differently based on this flip flag
// hazard.min.x = -hazard.min.x - hazard.width //-x-width
// hazard.max.x = -hazard.max.x - hazard.width //-x-width
// hazard2.min.x = -hazard2.min.x - hazard2.width //-x-width
// hazard2.max.x = -hazard2.max.x - hazard2.width //-x-width
portal = level.portal({
x: -2475,
y: -140
}, 2 * Math.PI, { //right
x: -2475,
y: -3140
}, 2 * Math.PI) //right
spawn.mapRect(550, -1550, 450, 125);
spawn.mapRect(150, -1550, 250, 125);
spawn.mapRect(750, -1425, 1100, 175);
spawn.mapRect(750, -1400, 250, 825);
spawn.mapRect(750, -350, 250, 575);
// spawn.mapRect(750, -1275, 250, 600);
// spawn.mapRect(3550, -1850, 1200, 600);
portal2 = level.portal({
x: -75,
y: -2150
}, -Math.PI / 2, { //up
x: -1325,
y: -2150
}, -Math.PI / 2) //up
spawn.mapRect(3825, -1425, 975, 175);
spawn.mapRect(625, 2050, 4300, 625);
spawn.mapRect(4450, -3525, 1400, 6200);
//the pit
const vanish = []
vanish.push(level.vanish(400, -1512, 150, 50))
vanish.push(level.vanish(2625, -675, 300, 175))
vanish.push(level.vanish(1775, -675, 325, 150))
//blocks at entrance
spawn.bodyRect(150, -175, 50, 165);
spawn.bodyRect(825, -425, 155, 75, 0.5);
portal3 = level.portal({
x: -1850,
y: -585
}, -Math.PI / 2, { //up
x: -2425,
y: -600
}, -1 * Math.PI / 3) //up left
// level.custom = () => { };
// level.customTopLayer = () => {};
} else {
portal = level.portal({
x: 2475,
y: -140
}, Math.PI, { //left
x: 2475,
y: -3140
}, Math.PI) //left
portal2 = level.portal({
x: 75,
y: -2150
}, -Math.PI / 2, { //up
x: 1325,
y: -2150
}, -Math.PI / 2) //up
portal3 = level.portal({
x: 1850,
y: -585
}, -Math.PI / 2, { //up
x: 2425,
y: -600
}, -2 * Math.PI / 3) //up left
}
},
sewers() {
@@ -8219,8 +8012,8 @@ const level = {
let r = false;
const deliverySlime = level.hazard(3700, -940, 100, 480)
const deliverySlime2 = level.hazard(3700, -461, 100, 1141)
const slimePit = level.hazard(700, 1200, 2500, 1300, 0.004, "hsla(160, 100%, 35%,0.75)")
const topSlime = level.hazard(800, -460, 2900, 90, 0.004, "hsla(160, 100%, 35%,0.75)")
const slimePit = level.hazard(700, 1200, 2500, 1300, 0.004)
const topSlime = level.hazard(800, -460, 2900, 90, 0.004)
// const rotor = level.rotor(0, -725, 0.001)
const rotor = level.rotor(-400, -725, 800, 50, 0.001, 0, 0.01, 0, 0.001)
@@ -11869,7 +11662,7 @@ const level = {
const hazard3 = level.hazard(740, -1050, 10, 700, 0.4)
const hazard4 = level.hazard(3400, -380, 350, 6, 0.2)
const hazard5 = level.hazard(3425, -1420, 400, 8, 0.2)
const slimePit = level.hazard(2250, -100, 2700, 200, 0.004, "hsla(160, 100%, 35%,0.75)")
const slimePit = level.hazard(2250, -100, 2700, 200, 0.004)
const door2 = level.door(3131, -898, 40, 520, 522)
const buttonDoor2 = level.button(2495, -270)
const toggle = level.toggle(1463, -708, true)

View File

@@ -3016,20 +3016,10 @@ const m = {
//not shooting (or using field) enable cloak
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing
const drain = 0.05
if (!m.isCloak && m.energy > drain + 0.05) {
const drain = 0.03
if (!m.isCloak && m.energy > drain + 0.03) {
m.energy -= drain
m.isCloak = true //enter cloak
// m.color = {
// hue: 0,
// sat: 0,
// light: 100
// }
// m.setFillColorsAlpha(0)
m.enterCloakCycle = m.cycle
if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy)
@@ -3063,7 +3053,7 @@ const m = {
if (tech.isCloakStun) { //stun nearby mobs after exiting cloak
let isMobsAround = false
const stunRange = m.fieldDrawRadius * 1.5
const drain = 0.2
const drain = 0.15
if (m.energy > drain) {
for (let i = 0, len = mob.length; i < len; ++i) {
if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) < stunRange && Matter.Query.ray(map, mob[i].position, m.pos).length === 0 && !mob[i].isBadTarget) {
@@ -3085,11 +3075,11 @@ const m = {
}
}
if (m.isCloak) {
m.fieldRange = m.fieldRange * 0.9 + 80
m.fieldDrawRadius = m.fieldRange * 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.fieldRange = m.fieldRange * 0.85 + 115
m.fieldDrawRadius = m.fieldRange * 1.1 //* 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak()
} else if (m.fieldRange < 4000) {
m.fieldRange += 50
m.fieldRange += 90
m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak()
}

View File

@@ -305,7 +305,8 @@ const powerUps = {
document.getElementById("choose-grid").style.pointerEvents = "none";
document.body.style.cursor = "none";
setTimeout(() => {
if (!tech.isNoDraftPause) document.body.style.cursor = "auto";
// if (!tech.isNoDraftPause)
document.body.style.cursor = "auto";
document.getElementById("choose-grid").style.pointerEvents = "auto";
document.getElementById("choose-grid").style.transitionDuration = "0s";
}, 400);
@@ -313,7 +314,7 @@ const powerUps = {
if (!simulation.paused) {
if (tech.isNoDraftPause) {
document.getElementById("choose-grid").style.opacity = "0.92"
document.getElementById("choose-grid").style.opacity = "1"
} else {
simulation.paused = true;
document.getElementById("choose-grid").style.opacity = "1"
@@ -565,7 +566,7 @@ const powerUps = {
},
effect() {
if (b.inventory.length > 0) {
if (tech.isAmmoForGun && b.activeGun) { //give extra ammo to one gun only with tech logistics
if (tech.isAmmoForGun && b.activeGun !== null) { //give extra ammo to one gun only with tech logistics
const target = b.guns[b.activeGun]
if (target.ammo !== Infinity) {
if (tech.ammoCap) {
@@ -1164,10 +1165,7 @@ const powerUps = {
if (tech.isLaserMine && input.down) {
b.laserMine(who.position)
} else {
b.mine(who.position, {
x: 0,
y: 0
}, 0)
b.mine(who.position, { x: 0, y: 0 }, 0)
}
}
if (tech.isRelay) {

View File

@@ -314,7 +314,7 @@ const simulation = {
ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
ctx.beginPath();
if (m.fireCDcycle > m.cycle) {
ctx.strokeStyle = "#777"; //'rgba(0,0,0,0.4)'
ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
ctx.arc(simulation.mouse.x, simulation.mouse.y, size + 1, 0, 2 * Math.PI);
} else {
ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
@@ -474,10 +474,8 @@ const simulation = {
switchGun() {
if (tech.isLongitudinal && b.activeGun === 3) b.guns[3].waves = []; //empty array of wave bullets
if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1 //this prevents hacking the tech by switching guns
if (b.inventory.length > 0) {
b.activeGun = b.inventory[b.inventoryGun];
if (b.guns[b.activeGun].charge) b.guns[b.activeGun].charge = 0; //if switching into foam set charge to 0
}
if (b.inventory.length > 0) b.activeGun = b.inventory[b.inventoryGun];
b.guns[8].charge = 0; // foam charge to 0
simulation.updateGunHUD();
simulation.boldActiveGunHUD();
//set crosshairs
@@ -774,8 +772,6 @@ const simulation = {
input.endKeySensing();
b.removeAllGuns();
simulation.switchGun();
tech.setupAllTech(); //sets tech to default values
tech.cancelCount = 0;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -904,28 +900,30 @@ const simulation = {
clearMap() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
if (m.alive) {
if (tech.isLongitudinal) {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "wave") {
b.guns[i].waves = []; //empty array of wave bullets
break;
if (tech.isLongitudinal) b.guns[3].waves = []; //empty array of wave bullets
if (b.guns[10].have) { //do you have mines as a gun
let count = 0;
for (i = 0, len = bullet.length; i < len; i++) { //count mines left on map
if (
(bullet[i].bulletType === "mine" && (!tech.isMineSentry || bullet[i].shots === undefined)) ||
bullet[i].bulletType === "laser mine") {
count++
}
}
if (tech.crouchAmmoCount) count = Math.ceil(count / 2)
b.guns[10].ammo += count
if (tech.ammoCap) b.guns[10].ammo = Math.min(tech.ammoCap, b.guns[10].ammo)
simulation.updateGunHUD();
}
let count = 0;
for (i = 0, len = bullet.length; i < len; i++) { //count mines left on map
if ((bullet[i].bulletType === "mine" || bullet[i].bulletType === "laser mine") && !bullet[i].isArmed) count++
}
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun is mine
if (b.guns[i].name === "mine") {
if (tech.crouchAmmoCount) 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;
}
}
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun is mine
// if (b.guns[i].name === "mine") {
// b.guns[i].ammo += count
// if (tech.ammoCap) b.guns[i].ammo = Math.min(tech.ammoCap, b.guns[i].ammo)
// simulation.updateGunHUD();
// break;
// }
// }
if (tech.isMutualism && !tech.isEnergyHealth) {
for (let i = 0; i < bullet.length; i++) {

View File

@@ -578,7 +578,7 @@ const spawn = {
},
{
name: "laser",
spinForce: 0.00000012, // * (Math.random() < 0.5 ? -1 : 1),
spinForce: 0.00000008, // * (Math.random() < 0.5 ? -1 : 1),
fadeCycle: 0, //fades in over 4 seconds
do() {
this.fadeCycle++

View File

@@ -381,6 +381,14 @@ const tech = {
if (regex !== -1 && (not === -1 || not > regex)) gunTechPool.push(j) //look for the gun name in the requirements, but the gun name needs to show up before the word ' not '
}
b.activeGun = originalActiveGunIndex
if (!b.guns[b.activeGun].have) {
if (b.inventory.length === 0) {
b.activeGun = null
} else {
b.activeGun = b.inventory[0]
}
b.inventoryGun = 0;
}
}
if (gunTechPool.length) {
const index = Math.floor(Math.random() * gunTechPool.length)
@@ -4356,7 +4364,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine)) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
},
requires: "nails, nail gun, rivets, shotgun, super balls, mine",
effect() {
@@ -5280,26 +5288,26 @@ const tech = {
if (this.count > 0) powerUps.research.changeRerolls(3)
}
},
{
name: "electric armor",
// description: "<strong class='color-e'>explosions</strong> do no <strong class='color-defense'>defense</strong><br> while your <strong class='color-f'>energy</strong> is above <strong>98%</strong>",
description: "instead of causing <strong class='color-h'>health</strong> loss, <strong class='color-e'>explosions</strong><br>drain <strong>12</strong> <strong class='color-f'>energy</strong> and have more knockback",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
},
requires: "an explosive damage source, not iridium-192",
effect() {
tech.isImmuneExplosion = true;
},
remove() {
tech.isImmuneExplosion = false;
}
},
// {
// name: "electric armor",
// // description: "<strong class='color-e'>explosions</strong> do no <strong class='color-defense'>defense</strong><br> while your <strong class='color-f'>energy</strong> is above <strong>98%</strong>",
// description: "instead of causing <strong class='color-h'>health</strong> loss, <strong class='color-e'>explosions</strong><br>drain <strong>12</strong> <strong class='color-f'>energy</strong> and have more knockback",
// isGunTech: true,
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
// },
// requires: "an explosive damage source, not iridium-192",
// effect() {
// tech.isImmuneExplosion = true;
// },
// remove() {
// tech.isImmuneExplosion = false;
// }
// },
{
name: "MIRV",
description: "fire <strong>+1</strong> <strong>missile</strong> or <strong>grenade</strong> per shot<br><strong>12%</strong> <strong class='color-e'>explosion</strong> <strong class='color-d'>damage</strong> and <strong>radius</strong>",
@@ -5321,21 +5329,23 @@ const tech = {
},
{
name: "rocket-propelled grenade",
description: "<strong>grenades</strong> rapidly <strong>accelerate</strong> forward<br>map <strong>collisions</strong> trigger an <strong class='color-e'>explosion</strong>",
description: "<strong>grenades</strong> <strong class='color-e'>explode</strong> on map <strong>collisions</strong><br><strong class='color-e'>explosions</strong> drain <strong class='color-f'>energy</strong>, not <strong class='color-h'>health</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades")
return tech.haveGunCheck("grenades") && !tech.isVacuumBomb
},
requires: "grenades",
requires: "grenades, not vacuum bomb",
effect() {
tech.isImmuneExplosion = true;
tech.isRPG = true;
b.setGrenadeMode()
},
remove() {
tech.isImmuneExplosion = true;
tech.isRPG = false;
b.setGrenadeMode()
}
@@ -5349,9 +5359,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode
return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode && !tech.isRPG
},
requires: "grenades, not neutron bomb, chain reaction",
requires: "grenades, not neutron bomb, chain reaction, RPG",
effect() {
tech.isVacuumBomb = true;
b.setGrenadeMode()
@@ -5646,7 +5656,7 @@ const tech = {
}
},
{
name: "sentry gun",
name: "sentry",
descriptionFunction() {
return `<strong>mines</strong> fire one ${b.guns[10].nameString()} at a time<br><strong>mines</strong> fire <strong>50%</strong> more ${b.guns[10].nameString('s')}`
},

View File

@@ -1,5 +1,7 @@
:root {
--build-bg-color: #aeb6c2;
--card-color: #fafcfd;
--hover-card-color: #e5e5ed;
}
body {
@@ -185,15 +187,15 @@ summary {
.choose-grid-module {
line-height: 160%;
background-color: #fafcfd;
background-color: var(--card-color);
font-size: 0.75em;
}
.choose-grid-module:hover {
background-color: #efeff5;
background-color: var(--hover-card-color);
}
.choose-grid-module:hover .card-text {
background-color: #efeff5;
background-color: var(--hover-card-color);
}
.research-select {
@@ -244,7 +246,7 @@ summary {
.pause-grid-module {
line-height: 160%;
background-color: #fafcfd;
background-color: var(--card-color);
font-size: 0.75em;
}
@@ -276,7 +278,7 @@ summary {
.experiment-grid-module {
line-height: 160%;
background-color: #fafcfd;
background-color: var(--card-color);
font-size: 0.75em;
}
@@ -292,11 +294,11 @@ summary {
}
.experiment-grid-module:hover:not(.build-tech-selected, .build-field-selected, .build-gun-selected) {
background-color: #efeff5;
background-color: var(--card-color);
}
.experiment-start-box{
background-color: #fafcfd;
background-color: var(--card-color);
/* font-size: 1em; */
position: sticky;
top:0;
@@ -347,10 +349,10 @@ summary {
margin-right: -1px;
padding: 1px;
line-height: 160%;
background-color: #fafcfd;
background-color: var(--card-color);
}
.cancel-card:hover {
background-color: #efeff5;
background-color: var(--hover-card-color);
}
.research-card {
font-size: 1.1em;
@@ -360,15 +362,15 @@ summary {
margin-right: -1px;
padding: 1px 0px 1px 10px;
line-height: 160%;
background-color: #fafcfd;
background-color: var(--card-color);
}
.research-card:hover {
background-color: #efeff5;
background-color: var(--hover-card-color);
}
/* keeps 5 columns at 1440px */
@media (1710px <= width < 1950px) {
@media (min-width: 1710px) and (max-width: 1950px) {
.experiment-grid-module, .choose-grid-module, .pause-grid-module {
line-height: 143%;
font-size: 0.68em;
@@ -383,7 +385,8 @@ summary {
min-height: 75px;
}
}
@media (width < 1710px) {
/* (min-width: 30em) and (max-width: 80em) */
@media (max-width: 1709px) {
.experiment-grid-module, .choose-grid-module, .pause-grid-module {
line-height: 139%;
font-size: 0.58em;
@@ -431,7 +434,7 @@ summary {
} */
.experiment-grid-module:hover .card-text {
background-color: #efeff5;
background-color: var(--hover-card-color);
}
.build-tech-selected .card-text{
background-color: hsl(253, 100%, 84%);
@@ -453,9 +456,9 @@ summary {
}
.experiment-grid-disabled {
background-color: var(--build-bg-color);
color: #000;
opacity: 0.25;
/* background-color: var(--build-bg-color); */
/* color: #000; */
opacity: 0.35;
}
.experiment-grid-disabled[data-descr] {
@@ -756,7 +759,7 @@ summary {
font-weight: 100;
}
.color-cancel {
background-color: #fafcfd;
background-color: var(--card-color);
border: 0.15em #444 solid;
padding: 0.2em;
border-radius: 0.2em;
@@ -980,7 +983,7 @@ summary {
text-align: center;
letter-spacing: 10px;
border: none;
background-color: #efeff5;
background-color: var(--card-color);
}
.flipX {
animation: 14s anim-flipX linear infinite;

View File

@@ -1,25 +1,64 @@
******************************************************** NEXT PATCH **************************************************
tech: RPG - gains the rocket jumping effects from electric armor
tech: repeater - shotgun gets another shot, and a longer fire delay
shotgun cross hairs show when fire is on cooldown
eternalism no longer makes tech options have 50% opacity when choosing
keys 1,2,3,4,5,6,7,8,9,0,-,= switch to a gun in your inventory
Nerfed blinkBoss health and speed
sneaker mobs are immune to harm for one cycles after vanishing
experiment button new style
new images for energy, bots
some new images for cloaking tech
and some images were made brighter
bug fixes
safari media rules css fixed
*********************************************************** TODO *****************************************************
tech: maybe missiles explode when they hit walls, but explosions only drain energy
tech: sticky grenades
needs another effect to be good enough
stick to mobs?
testChamber2
mechanics
cover exit with slime, press button to lower slime and exit
companion cube
bring cube to the end and use it to unlock research
level draws on the block to show it's different
only this block can trigger a button?
if cube no longer exists or is off the map spawn a new one
or maybe add a button for the player to destroy current cube and spawn new cube
double portal fling chain
for player?
for cube
button that activates a laser beam that hits a target and opens a door
in order to enter the door you need to place the cube on the button to activate the laser
cube has to fly through a portal in order to get to the button
you can't use your body
story:
you pick up the cube early on and have to get it to a button
you run through the level to get the cube, clearing the level of mobs
picking up the cube spawns the boss
maybe an extra hard boss that is designed for that level
blockBoss?
you must get the cube to a button near the start of the level
the button opens a door
normal blocks don't work
normal blocks spawn into mobs like blockBoss
or mobs don't spawn blocks
or just the code looks for the cube
or the cube is resting on a button, and when you take the cube off the button the laser fires
make a mob similar to slasher
because it's just a very well made mob.
tech - only allow 1,2 turrets at time?
turrets drain energy?
turrets never run out of ammo
turrets automatically use one of your mine ammos when they run out?
or turrets automatically use one of your mine ammos when they run out?
good with multi gun builds
conflict with booby trap
conflict with booby trap?
tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy?
@@ -62,14 +101,6 @@ tech: sporangium that grow little trees
the trees have an area of effect damage for about 6-10 seconds
maybe something similar to radioactive drones, but maybe a few smaller shapes
spores, worms, fleas - can target player
when to target player
probably have to not go after player for at least a few seconds
only go after player if there are no mobs
go after what ever is closest target
go after a random target
if distance to player < 60 damage player
new bot type that makes phonon waves
name: phono-bot?
each bot has to generate it themselves, can't run code in gun.do
@@ -337,34 +368,6 @@ make plasma ball power up and block pick up still work when you have no no energ
tech: entropic gravity - gain defense for each research
requires wormhole or pilot wave or negative mass field?
testChamber2
mechanics
companion cube
bring cube to the end and use it to unlock research
level draws on the block to show it's different
only this block can trigger a button
if cube no longer exists or is off the map spawn a new one
double portal fling chain
for player?
for cube
button that activates a laser beam that hits a target and opens a door
in order to enter the door you need to place the cube on the button to activate the laser
cube has to fly through a portal in order to get to the button
you can't use your body
story:
you pick up the cube early on and have to get it to a button
you run through the level to get the cube, clearing the level of mobs
picking up the cube spawns the boss
maybe an extra hard boss that is designed for that level
blockBoss?
you must get the cube to a button near the start of the level
the button opens a door
normal blocks don't work
normal blocks spawn into mobs like blockBoss
or mobs don't spawn blocks
or just the code looks for the cube
or the cube is resting on a button, and when you take the cube off the button the laser fires
mitosis: after needle,bullets or rivets hit a surface split off into two smaller less damaging versions that have their velocity reset -firerate
after killing a mob go invulnerable for 1 second
@@ -1164,9 +1167,9 @@ if pause is pressed while selecting power ups, display pause menu on top of sele
quantum stuff -- Hypertorus, Glowing Opal Pearlescent, Physics, Hydro-Dipping Hydrodipped, Vija Celmins, Matt Molloy (photo of golden waves in the sky)
***major themes missing***
***maybe redo***
dynamical systems
heuristics
negative feedback - too dark
supercritical fission
***past style themes***
field emitter - isometric, clean white robot spherical gun turret on bird legs, blender 3d, style of artstation and behance, Disney Pixar, cute
standing wave - concentric transparent blue geometric circles science
@@ -1174,7 +1177,7 @@ if pause is pressed while selecting power ups, display pause menu on top of sele
time dilation - graphic of a hyperbolic equation Luminogram
negative mass - Blacklight painting by Moebius
plasma torch - by Dan Mumford
metamaterial cloaking - Scientific photography by Miki Asai
metamaterial cloaking - Scientific photography by Miki Asai, by Bruce Munro
molecular assembler - by Laurie Greasley 16-bit Isometric
wormhole - by Tim White