laser delay
laser energy drain and damage now scale with fire delay effects no change for pulse since it already has a fire delay explosion harm to player no longer scales with explosion radius explosion damage will treat all explosions the same as a basic grenade explosion large radius explosions are much safer acetone peroxide 80->70% increased radius, 100->50% increase in harm from explosions CPT only triggers from damage above 1% per game cycle so no trigger from slime hazards or black holes or mob auras level: reactor has a horizontal flipped mode regression gives finalBoss(1.0005), Boss(1.0025), mob(1.05) increased damage taken JUNK tech: return - go back to the intro level, but keep your tech bug fixes
This commit is contained in:
66
js/bullet.js
66
js/bullet.js
@@ -347,14 +347,14 @@ const b = {
|
||||
}
|
||||
},
|
||||
explosionRange() {
|
||||
return tech.explosiveRadius * (tech.isExplosionHarm ? 1.8 : 1) * (tech.isSmallExplosion ? 0.66 : 1) * (tech.isExplodeRadio ? 1.25 : 1)
|
||||
return tech.explosiveRadius * (tech.isExplosionHarm ? 1.7 : 1) * (tech.isSmallExplosion ? 0.66 : 1) * (tech.isExplodeRadio ? 1.25 : 1)
|
||||
},
|
||||
explosion(where, radius, color = "rgba(255,25,0,0.6)") { // typically explode is used for some bullets with .onEnd
|
||||
radius *= tech.explosiveRadius
|
||||
|
||||
let dist, sub, knock;
|
||||
let dmg = radius * 0.019 * (tech.isExplosionStun ? 0.7 : 1); //* 0.013 * (tech.isExplosionStun ? 0.7 : 1);
|
||||
if (tech.isExplosionHarm) radius *= 1.8 // 1/sqrt(2) radius -> area
|
||||
if (tech.isExplosionHarm) radius *= 1.7 // 1/sqrt(2) radius -> area
|
||||
if (tech.isSmallExplosion) {
|
||||
// color = "rgba(255,0,30,0.7)"
|
||||
radius *= 0.66
|
||||
@@ -375,7 +375,7 @@ const b = {
|
||||
|
||||
//player damage
|
||||
if (Vector.magnitude(Vector.sub(where, player.position)) < radius) {
|
||||
const DRAIN = (tech.isExplosionHarm ? 0.9 : 0.45) * (tech.isRadioactiveResistance ? 0.25 : 1)
|
||||
const DRAIN = (tech.isExplosionHarm ? 0.67 : 0.45) * (tech.isRadioactiveResistance ? 0.25 : 1)
|
||||
if (m.immuneCycle < m.cycle) m.energy -= DRAIN
|
||||
if (m.energy < 0) {
|
||||
m.energy = 0
|
||||
@@ -424,7 +424,7 @@ const b = {
|
||||
|
||||
if (dist < radius) {
|
||||
if (simulation.dmgScale) {
|
||||
const harm = radius * (tech.isExplosionHarm ? 0.00036 : 0.00018)
|
||||
const harm = tech.isExplosionHarm ? 0.075 : 0.05
|
||||
if (tech.isImmuneExplosion && m.energy > 0.15) {
|
||||
// const mitigate = Math.min(1, Math.max(1 - m.energy * 0.5, 0))
|
||||
m.energy -= 0.15
|
||||
@@ -458,14 +458,14 @@ const b = {
|
||||
body[i].force.y += knock.y;
|
||||
if (tech.isBlockExplode) {
|
||||
if (body[i] === m.holdingTarget) m.drop()
|
||||
const size = 20 + 350 * Math.pow(body[i].mass, 0.25)
|
||||
const size = 20 + 300 * Math.pow(body[i].mass, 0.25)
|
||||
const where = body[i].position
|
||||
const onLevel = level.onLevel //prevent explosions in the next level
|
||||
Matter.Composite.remove(engine.world, body[i]);
|
||||
body.splice(i, 1);
|
||||
setTimeout(() => {
|
||||
if (onLevel === level.onLevel) b.explosion(where, size); //makes bullet do explosive damage at end
|
||||
}, 150 + 300 * Math.random());
|
||||
}, 250 + 300 * Math.random());
|
||||
}
|
||||
} else if (dist < alertRange) {
|
||||
knock = Vector.mult(Vector.normalise(sub), -Math.sqrt(dmg) * body[i].mass * 0.011);
|
||||
@@ -2389,14 +2389,14 @@ const b = {
|
||||
}
|
||||
if (tech.isLaserPush) { //push mobs away
|
||||
const index = path.length - 1
|
||||
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.95, y: best.who.velocity.y * 0.95 });
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.005 * push * Math.min(6, best.who.mass))
|
||||
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
|
||||
Matter.Body.applyForce(best.who, path[index], force)
|
||||
}
|
||||
} else if (tech.isLaserPush && best.who.classType === "body") {
|
||||
const index = path.length - 1
|
||||
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.95, y: best.who.velocity.y * 0.95 });
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.005 * push * Math.min(6, best.who.mass))
|
||||
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
|
||||
Matter.Body.applyForce(best.who, path[index], force)
|
||||
}
|
||||
};
|
||||
@@ -4203,7 +4203,7 @@ const b = {
|
||||
}
|
||||
}
|
||||
|
||||
if (!m.isCloak) { //if time dilation isn't active
|
||||
if (!m.isCloak) { //if cloaking field isn't active
|
||||
const size = 33
|
||||
q = Matter.Query.region(mob, {
|
||||
min: {
|
||||
@@ -6957,8 +6957,15 @@ const b = {
|
||||
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
|
||||
} else {
|
||||
m.fireCDcycle = m.cycle
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
|
||||
b.laser();
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
|
||||
const where = {
|
||||
x: m.pos.x + 20 * Math.cos(m.angle),
|
||||
y: m.pos.y + 20 * Math.sin(m.angle)
|
||||
}
|
||||
b.laser(where, {
|
||||
x: where.x + 3000 * Math.cos(m.angle),
|
||||
y: where.y + 3000 * Math.sin(m.angle)
|
||||
}, tech.laserDamage / b.fireCDscale);
|
||||
}
|
||||
},
|
||||
firePulse() {
|
||||
@@ -6969,11 +6976,11 @@ const b = {
|
||||
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
|
||||
} else {
|
||||
m.fireCDcycle = m.cycle
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
|
||||
// const divergence = input.down ? 0.15 : 0.2
|
||||
// const scale = Math.pow(0.9, tech.beamSplitter)
|
||||
// const pushScale = scale * scale
|
||||
let dmg = tech.laserDamage // * scale //Math.pow(0.9, tech.laserDamage)
|
||||
let dmg = tech.laserDamage / b.fireCDscale // * scale //Math.pow(0.9, tech.laserDamage)
|
||||
const where = {
|
||||
x: m.pos.x + 20 * Math.cos(m.angle),
|
||||
y: m.pos.y + 20 * Math.sin(m.angle)
|
||||
@@ -6993,7 +7000,7 @@ const b = {
|
||||
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
|
||||
} else {
|
||||
m.fireCDcycle = m.cycle
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
|
||||
const range = {
|
||||
x: 5000 * Math.cos(m.angle),
|
||||
y: 5000 * Math.sin(m.angle)
|
||||
@@ -7006,7 +7013,7 @@ const b = {
|
||||
x: 7.5 * Math.cos(m.angle - Math.PI / 2),
|
||||
y: 7.5 * Math.sin(m.angle - Math.PI / 2)
|
||||
}
|
||||
const dmg = 0.70 * tech.laserDamage // 3.5 * 0.55 = 200% more damage
|
||||
const dmg = 0.70 * tech.laserDamage / b.fireCDscale // 3.5 * 0.55 = 200% more damage
|
||||
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
|
||||
const eye = {
|
||||
x: m.pos.x + 15 * Math.cos(m.angle),
|
||||
@@ -7057,8 +7064,8 @@ const b = {
|
||||
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
|
||||
} else {
|
||||
m.fireCDcycle = m.cycle
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode
|
||||
const dmg = 0.4 * tech.laserDamage // 3.5 * 0.55 = 200% more damage
|
||||
m.energy -= m.fieldRegen + tech.laserFieldDrain * tech.isLaserDiode / b.fireCDscale
|
||||
const dmg = 0.4 * tech.laserDamage / b.fireCDscale // 3.5 * 0.55 = 200% more damage
|
||||
const spacing = Math.ceil(4 - 0.3 * tech.historyLaser)
|
||||
ctx.beginPath();
|
||||
b.laser({
|
||||
@@ -7084,27 +7091,6 @@ const b = {
|
||||
ctx.stroke();
|
||||
}
|
||||
},
|
||||
// firePulse() {
|
||||
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down
|
||||
// let energy = 0.3 * Math.min(m.energy, 1.5)
|
||||
// m.energy -= energy * tech.isLaserDiode
|
||||
// if (tech.beamSplitter) {
|
||||
// // energy *= Math.pow(0.9, tech.beamSplitter)
|
||||
// // b.pulse(energy, m.angle)
|
||||
// // for (let i = 1; i < 1 + tech.beamSplitter; i++) {
|
||||
// // b.pulse(energy, m.angle - i * 0.27)
|
||||
// // b.pulse(energy, m.angle + i * 0.27)
|
||||
// // }
|
||||
// const divergence = input.down ? 0.2 : 0.5
|
||||
// const angle = m.angle - tech.beamSplitter * divergence / 2
|
||||
// for (let i = 0; i < 1 + tech.beamSplitter; i++) {
|
||||
// b.pulse(energy, angle + i * divergence)
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// b.pulse(energy, m.angle)
|
||||
// }
|
||||
// },
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -109,7 +109,7 @@ function collisionChecks(event) {
|
||||
let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * simulation.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0
|
||||
if (m.isCloak) dmg *= 0.5
|
||||
mob[k].foundPlayer();
|
||||
if (tech.isRewindAvoidDeath && m.energy > 0.66) { //CPT reversal runs in m.damage, but it stops the rest of the collision code here too
|
||||
if (tech.isRewindAvoidDeath && m.energy > 0.66 && dmg > 0.01) { //CPT reversal runs in m.damage, but it stops the rest of the collision code here too
|
||||
m.damage(dmg);
|
||||
return
|
||||
}
|
||||
@@ -190,7 +190,7 @@ function collisionChecks(event) {
|
||||
time: simulation.drawTime
|
||||
});
|
||||
}
|
||||
if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? 1.0025 : 1.05
|
||||
if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? (mob[k].isFinalBoss ? 1.0005 : 1.0025) : 1.05
|
||||
return;
|
||||
}
|
||||
//mob + body collisions
|
||||
@@ -229,7 +229,7 @@ function collisionChecks(event) {
|
||||
}
|
||||
|
||||
const stunTime = dmg / Math.sqrt(obj.mass)
|
||||
if (stunTime > 0.5) mobs.statusStun(mob[k], 60 + 60 * Math.sqrt(stunTime))
|
||||
if (stunTime > 0.5 && mob[k].memory !== Infinity) mobs.statusStun(mob[k], 60 + 60 * Math.sqrt(stunTime))
|
||||
if (mob[k].alive && mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer();
|
||||
if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) {
|
||||
obj.hasFragmented = true;
|
||||
|
||||
254
js/level.js
254
js/level.js
@@ -15,10 +15,10 @@ const level = {
|
||||
levels: [],
|
||||
start() {
|
||||
if (level.levelsCleared === 0) { //this code only runs on the first level
|
||||
// // simulation.isHorizontalFlipped = true
|
||||
// simulation.isHorizontalFlipped = true
|
||||
// m.addHealth(Infinity)
|
||||
// m.setField("time dilation")
|
||||
// b.giveGuns("spores")
|
||||
// b.giveGuns("laser")
|
||||
// tech.giveTech("closed timelike curve")
|
||||
// tech.giveTech("retrocausality")
|
||||
// tech.giveTech("clock gating")
|
||||
@@ -38,11 +38,7 @@ const level = {
|
||||
// level.difficultyIncrease(20) //30 is near max on hard //60 is near max on why
|
||||
// simulation.enableConstructMode() //used to build maps in testing mode
|
||||
// level.testing();
|
||||
// simulation.fpsCap = 30 //new fps
|
||||
// simulation.fpsInterval = 1000 / simulation.fpsCap;
|
||||
//how long to wait to return to normal fps
|
||||
// m.defaultFPSCycle = m.cycle + 20 + Math.min(90, Math.floor(200 * dmg))
|
||||
// spawn.timeSkipBoss(1900, -500)
|
||||
// spawn.starter(1900, -500, 200)
|
||||
// level.reactor(); //not in rotation, used for testing
|
||||
|
||||
if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************
|
||||
@@ -2697,8 +2693,6 @@ const level = {
|
||||
// spawn.randomMob(1600, -500)
|
||||
},
|
||||
reactor() {
|
||||
level.setPosToSpawn(-550, -800); //normal spawn
|
||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
||||
level.exit.x = 3500;
|
||||
level.exit.y = -42;
|
||||
spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
|
||||
@@ -2708,8 +2702,7 @@ const level = {
|
||||
color.map = "#303639";
|
||||
// powerUps.spawnStartingPowerUps(1475, -1175);
|
||||
// spawn.debris(750, -2200, 3700, 16); //16 debris per level
|
||||
const button = level.button(1400, 0)
|
||||
button.isUp = true
|
||||
|
||||
spawn.bodyRect(250, -70, 100, 70, 1);
|
||||
spawn.mapRect(-425, 0, 4500, 2100);
|
||||
spawn.mapRect(-475, -2825, 4500, 1025);
|
||||
@@ -2735,90 +2728,169 @@ const level = {
|
||||
let isFightOver = false
|
||||
let isSpawnedBoss = false
|
||||
|
||||
level.custom = () => {
|
||||
if (isDoorsLocked) {
|
||||
if (player.position.x < -300) { //if player gets trapped inside starting room open up again
|
||||
isDoorsLocked = false
|
||||
doorIn.isClosing = false
|
||||
if (simulation.isHorizontalFlipped) { //flip the map horizontally
|
||||
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
|
||||
level.setPosToSpawn(550, -800); //normal spawn
|
||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
||||
|
||||
const button = level.button(-1500, 0)
|
||||
button.isUp = true
|
||||
|
||||
level.custom = () => {
|
||||
if (isDoorsLocked) {
|
||||
if (player.position.x > 300) { //if player gets trapped inside starting room open up again
|
||||
isDoorsLocked = false
|
||||
doorIn.isClosing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if (!isFightOver && player.position.x > 225) {
|
||||
// isDoorsLocked = true
|
||||
// doorIn.isClosing = true
|
||||
// doorOut.isClosing = true
|
||||
// }
|
||||
doorIn.openClose();
|
||||
doorOut.openClose();
|
||||
ctx.fillStyle = "#d5ebef"
|
||||
ctx.fillRect(2750, -375, 1050, 375)
|
||||
level.enter.draw();
|
||||
level.exit.drawAndCheck();
|
||||
button.draw();
|
||||
if (button.isUp) {
|
||||
button.query();
|
||||
} else if (!isSpawnedBoss) {
|
||||
if (player.position.x > 0) {
|
||||
if (!doorOut.isClosed() || !doorIn.isClosed()) {
|
||||
doorIn.isClosing = true
|
||||
doorOut.isClosing = true
|
||||
doorIn.openClose();
|
||||
doorOut.openClose();
|
||||
ctx.fillStyle = "#d5ebef"
|
||||
ctx.fillRect(-3800, -375, 1050, 375)
|
||||
level.enter.draw();
|
||||
level.exit.drawAndCheck();
|
||||
button.draw();
|
||||
if (button.isUp) {
|
||||
button.query();
|
||||
} else if (!isSpawnedBoss) {
|
||||
if (player.position.x < 0) {
|
||||
if (!doorOut.isClosed() || !doorIn.isClosed()) {
|
||||
doorIn.isClosing = true
|
||||
doorOut.isClosing = true
|
||||
} else {
|
||||
isSpawnedBoss = true
|
||||
isDoorsLocked = true
|
||||
for (let i = 0; i < 9; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "ammo")
|
||||
for (let i = 0; i < 3; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "heal");
|
||||
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
|
||||
if (Math.random() < 0.07 && simulation.difficulty > 24) {
|
||||
for (let i = 0, len = scale * 0.25 / 4; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
|
||||
for (let i = 0, len = scale * 0.1 / 4; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false);
|
||||
for (let i = 0, len = scale * 0.16 / 4; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false)
|
||||
for (let i = 0, len = scale * 0.23 / 4; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false);
|
||||
} else {
|
||||
if (Math.random() < 0.25) {
|
||||
for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
|
||||
} else if (Math.random() < 0.33) {
|
||||
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
|
||||
} else if (Math.random() < 0.5) {
|
||||
for (let i = 0, len = scale * 0.16; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
|
||||
} else {
|
||||
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
|
||||
}
|
||||
}
|
||||
spawn.secondaryBossChance(-2300, -800)
|
||||
}
|
||||
} else {
|
||||
isSpawnedBoss = true
|
||||
isDoorsLocked = true
|
||||
for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
|
||||
for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
|
||||
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
|
||||
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
|
||||
// if (Math.random() < 0.07 && simulation.difficulty > 24) {
|
||||
// for (let i = 0, len = scale * 0.25 / 4; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
|
||||
// for (let i = 0, len = scale * 0.1 / 4; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
|
||||
// for (let i = 0, len = scale * 0.16 / 4; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
|
||||
// for (let i = 0, len = scale * 0.23 / 4; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
|
||||
// } else {
|
||||
// if (Math.random() < 0.25) {
|
||||
// for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
|
||||
// } else if (Math.random() < 0.33) {
|
||||
// for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
|
||||
// } else if (Math.random() < 0.5) {
|
||||
// for (let i = 0, len = scale * 0.16; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
|
||||
// } else {
|
||||
// for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
|
||||
// }
|
||||
// }
|
||||
spawn.secondaryBossChance(2200, -800)
|
||||
doorIn.isClosing = false
|
||||
}
|
||||
} else {
|
||||
doorIn.isClosing = false
|
||||
}
|
||||
} else if (!isFightOver && !(simulation.cycle % 180)) {
|
||||
let isFoundBoss = false
|
||||
for (let i = 0; i < mob.length; i++) {
|
||||
if (mob[i].isBoss) {
|
||||
isFoundBoss = true
|
||||
break
|
||||
} else if (!isFightOver && !(simulation.cycle % 180)) {
|
||||
let isFoundBoss = false
|
||||
for (let i = 0; i < mob.length; i++) {
|
||||
if (mob[i].isBoss) {
|
||||
isFoundBoss = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!isFoundBoss) {
|
||||
isFightOver = true
|
||||
doorIn.isClosing = false
|
||||
doorOut.isClosing = false
|
||||
powerUps.spawnBossPowerUp(-3600, -100)
|
||||
powerUps.spawn(-3650, -200, "tech")
|
||||
// if (player.position.x < 2760 && player.position.x > 210) {}
|
||||
}
|
||||
}
|
||||
if (!isFoundBoss) {
|
||||
isFightOver = true
|
||||
doorIn.isClosing = false
|
||||
doorOut.isClosing = false
|
||||
powerUps.spawnBossPowerUp(3600, -100)
|
||||
powerUps.spawn(3650, -200, "tech")
|
||||
// if (player.position.x < 2760 && player.position.x > 210) {}
|
||||
};
|
||||
|
||||
level.customTopLayer = () => {
|
||||
doorIn.draw();
|
||||
doorOut.draw();
|
||||
ctx.fillStyle = "rgba(0,0,0,0.1)"
|
||||
ctx.fillRect(-225, -1100, 1000, 350);
|
||||
};
|
||||
} else {
|
||||
level.setPosToSpawn(-550, -800); //normal spawn
|
||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
||||
|
||||
const button = level.button(1400, 0)
|
||||
button.isUp = true
|
||||
|
||||
level.custom = () => {
|
||||
if (isDoorsLocked) {
|
||||
if (player.position.x < -300) { //if player gets trapped inside starting room open up again
|
||||
isDoorsLocked = false
|
||||
doorIn.isClosing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
level.customTopLayer = () => {
|
||||
// if (isDoorsLocked) {
|
||||
// ctx.fillStyle = "#333"
|
||||
// ctx.fillRect(2800, -375, 500, 375);
|
||||
// }
|
||||
doorIn.draw();
|
||||
doorOut.draw();
|
||||
ctx.fillStyle = "rgba(0,0,0,0.1)"
|
||||
ctx.fillRect(-775, -1100, 1000, 350);
|
||||
// ctx.fillStyle = "rgba(0,255,255,0.1)"
|
||||
// ctx.fillRect(2750, -375, 550, 375)
|
||||
};
|
||||
doorIn.openClose();
|
||||
doorOut.openClose();
|
||||
ctx.fillStyle = "#d5ebef"
|
||||
ctx.fillRect(2750, -375, 1050, 375)
|
||||
level.enter.draw();
|
||||
level.exit.drawAndCheck();
|
||||
button.draw();
|
||||
if (button.isUp) {
|
||||
button.query();
|
||||
} else if (!isSpawnedBoss) {
|
||||
if (player.position.x > 0) {
|
||||
if (!doorOut.isClosed() || !doorIn.isClosed()) {
|
||||
doorIn.isClosing = true
|
||||
doorOut.isClosing = true
|
||||
} else {
|
||||
isSpawnedBoss = true
|
||||
isDoorsLocked = true
|
||||
for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
|
||||
for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
|
||||
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
|
||||
if (Math.random() < 0.07 && simulation.difficulty > 24) {
|
||||
for (let i = 0, len = scale * 0.25 / 4; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
|
||||
for (let i = 0, len = scale * 0.1 / 4; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
|
||||
for (let i = 0, len = scale * 0.16 / 4; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
|
||||
for (let i = 0, len = scale * 0.23 / 4; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
|
||||
} else {
|
||||
if (Math.random() < 0.25) {
|
||||
for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
|
||||
} else if (Math.random() < 0.33) {
|
||||
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
|
||||
} else if (Math.random() < 0.5) {
|
||||
for (let i = 0, len = scale * 0.16; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
|
||||
} else {
|
||||
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
|
||||
}
|
||||
}
|
||||
spawn.secondaryBossChance(2200, -800)
|
||||
}
|
||||
} else {
|
||||
doorIn.isClosing = false
|
||||
}
|
||||
} else if (!isFightOver && !(simulation.cycle % 180)) {
|
||||
let isFoundBoss = false
|
||||
for (let i = 0; i < mob.length; i++) {
|
||||
if (mob[i].isBoss) {
|
||||
isFoundBoss = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!isFoundBoss) {
|
||||
isFightOver = true
|
||||
doorIn.isClosing = false
|
||||
doorOut.isClosing = false
|
||||
powerUps.spawnBossPowerUp(3600, -100)
|
||||
powerUps.spawn(3650, -200, "tech")
|
||||
// if (player.position.x < 2760 && player.position.x > 210) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
level.customTopLayer = () => {
|
||||
doorIn.draw();
|
||||
doorOut.draw();
|
||||
ctx.fillStyle = "rgba(0,0,0,0.1)"
|
||||
ctx.fillRect(-775, -1100, 1000, 350);
|
||||
};
|
||||
}
|
||||
|
||||
// if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
|
||||
powerUps.addResearchToLevel() //needs to run after mobs are spawned
|
||||
},
|
||||
@@ -3024,7 +3096,9 @@ const level = {
|
||||
spawn.mapRect(2025, 0, 150, 50); //lid to floor hole
|
||||
} else {
|
||||
for (let i = 0; i < 60; i++) {
|
||||
setTimeout(() => { spawn.sneaker(2100, -1500 - 50 * i); }, 2000 + 500 * i);
|
||||
setTimeout(() => {
|
||||
if (level.levels[level.onLevel] === "intro") spawn.sneaker(2100, -1500 - 50 * i);
|
||||
}, 2000 + 500 * i);
|
||||
}
|
||||
}
|
||||
const wires = new Path2D() //pre-draw the complex lighting path to save processing
|
||||
|
||||
18
js/mob.js
18
js/mob.js
@@ -115,13 +115,19 @@ const mobs = {
|
||||
who.isStunned = true;
|
||||
who.status.push({
|
||||
effect() {
|
||||
who.seePlayer.yes = false;
|
||||
who.seePlayer.recall = 0;
|
||||
who.seePlayer.position = {
|
||||
x: who.position.x + 100 * (Math.random() - 0.5),
|
||||
y: who.position.y + 100 * (Math.random() - 0.5)
|
||||
if (who.memory !== Infinity) {
|
||||
who.seePlayer.yes = false;
|
||||
who.seePlayer.recall = 0;
|
||||
who.seePlayer.position = {
|
||||
x: who.position.x + 100 * (Math.random() - 0.5),
|
||||
y: who.position.y + 100 * (Math.random() - 0.5)
|
||||
}
|
||||
} else {
|
||||
Matter.Body.setVelocity(who, {
|
||||
x: who.velocity.x * 0.6,
|
||||
y: who.velocity.y * 0.6
|
||||
});
|
||||
}
|
||||
// && !who.isBoss
|
||||
if (who.velocity.y < 2) who.force.y += who.mass * 0.0004 //extra gravity
|
||||
|
||||
//draw health bar
|
||||
|
||||
@@ -646,7 +646,7 @@ const m = {
|
||||
}
|
||||
},
|
||||
damage(dmg) {
|
||||
if (tech.isRewindAvoidDeath && m.energy > 0.6) {
|
||||
if (tech.isRewindAvoidDeath && m.energy > 0.6 && dmg > 0.01) {
|
||||
const steps = Math.floor(Math.min(299, 150 * m.energy))
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.rewind(${steps})`)
|
||||
m.rewind(steps)
|
||||
@@ -981,6 +981,7 @@ const m = {
|
||||
},
|
||||
setMaxEnergy() {
|
||||
m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 0.6 * (m.fieldUpgrades[m.fieldMode].name === "standing wave")
|
||||
// if (tech.isEnergyHealth) m.maxEnergy *= Math.sqrt(m.harmReduction())
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-f'>maxEnergy</span> <span class='color-symbol'>=</span> ${(m.maxEnergy.toFixed(2))}`)
|
||||
},
|
||||
fieldMeterColor: "#0cf",
|
||||
|
||||
@@ -848,7 +848,6 @@ const simulation = {
|
||||
m.fireCDcycle = 0
|
||||
m.drop();
|
||||
m.hole.isOn = false;
|
||||
level.zones = [];
|
||||
simulation.drawList = [];
|
||||
|
||||
if (tech.isDronesTravel && m.alive) {
|
||||
|
||||
@@ -289,6 +289,7 @@ const spawn = {
|
||||
Composite.add(engine.world, me.constraint);
|
||||
}, 2000); //add in a delay in case the level gets flipped left right
|
||||
me.isBoss = true;
|
||||
me.isFinalBoss = true;
|
||||
me.frictionAir = 0.01;
|
||||
me.memory = Infinity;
|
||||
me.hasRunDeathScript = false
|
||||
@@ -956,7 +957,7 @@ const spawn = {
|
||||
me.isCell = true;
|
||||
me.cellID = cellID
|
||||
me.accelMag = 0.000165 * simulation.accelScale;
|
||||
me.memory = 40;
|
||||
me.memory = Infinity;
|
||||
me.isVerticesChange = true
|
||||
me.frictionAir = 0.012
|
||||
me.seePlayerFreq = Math.floor(11 + 7 * Math.random())
|
||||
|
||||
106
js/tech.js
106
js/tech.js
@@ -93,6 +93,8 @@ const tech = {
|
||||
// console.log(count)
|
||||
// }
|
||||
// count total non junk tech
|
||||
id = "github"
|
||||
|
||||
let count = 0
|
||||
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
||||
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk) count += tech.tech[i].frequency
|
||||
@@ -2223,6 +2225,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "mass-energy equivalence",
|
||||
// description: "<strong class='color-f'>energy</strong> protects you instead of <strong class='color-h'>health</strong><br>√ of <strong class='color-harm'>harm</strong> <strong>reduction</strong> reduces max <strong class='color-f'>energy</strong>",
|
||||
description: "<strong class='color-f'>energy</strong> protects you instead of <strong class='color-h'>health</strong><br><strong class='color-harm'>harm</strong> <strong>reduction</strong> effects provide <strong>no</strong> benefit",
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -3675,11 +3678,13 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "strange attractor",
|
||||
description: `use ${powerUps.orb.research(2)} to spawn <strong>1</strong> <strong class='color-m'>tech</strong><br>with <strong>double</strong> your <strong class='color-dup'>duplication</strong> chance`,
|
||||
descriptionFunction() { return `use ${powerUps.orb.research(2)} to spawn <strong>1</strong> <strong class='color-m'>tech</strong> with <strong>double</strong><br>your <strong class='color-dup'>duplication</strong> chance <em>(${(2*tech.duplicationChance()*100).toFixed(0)}%)</em>` },
|
||||
|
||||
// description: `use ${powerUps.orb.research(2)} to spawn <strong>1</strong> <strong class='color-m'>tech</strong> with <strong>double</strong><br>your <strong class='color-dup'>duplication</strong> chance <em>(${(2*tech.duplicationChance()*100).toFixed(0)}%)</em>`,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
frequencyDefault: 1,
|
||||
frequency: 1000,
|
||||
frequencyDefault: 1000,
|
||||
isNonRefundable: true,
|
||||
isBadRandomOption: true,
|
||||
allowed() {
|
||||
@@ -4613,7 +4618,7 @@ const tech = {
|
||||
allowed() {
|
||||
return tech.haveGunCheck("missiles") && tech.isMissileBig //&& !tech.isSmartRadius && !tech.isImmuneExplosion
|
||||
},
|
||||
requires: "missiles, cruse missile", //, not electric reactive armor, controlled explosions",
|
||||
requires: "missiles, cruse missile",
|
||||
effect() {
|
||||
tech.isMissileBiggest = true
|
||||
},
|
||||
@@ -4767,7 +4772,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "acetone peroxide",
|
||||
description: "increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>80%</strong>, but<br>you take <strong>200%</strong> more <strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong>",
|
||||
description: "increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>70%</strong>, but<br>you take <strong>50%</strong> more <strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong>",
|
||||
isGunTech: true,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -4857,9 +4862,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
|
||||
return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isEnergyHealth
|
||||
},
|
||||
requires: "an explosive damage source, not iridium-192",
|
||||
requires: "an explosive damage source, not iridium-192, mass-energy",
|
||||
effect: () => {
|
||||
tech.isImmuneExplosion = true;
|
||||
},
|
||||
@@ -4916,9 +4921,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("grenades") && !tech.isNeutronBomb
|
||||
return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode
|
||||
},
|
||||
requires: "grenades, not neutron bomb",
|
||||
requires: "grenades, not neutron bomb, chain reaction",
|
||||
effect() {
|
||||
tech.isVacuumBomb = true;
|
||||
b.setGrenadeMode()
|
||||
@@ -4937,9 +4942,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb //tech.isVacuumBomb
|
||||
return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb && !tech.isVacuumBomb
|
||||
},
|
||||
requires: "grenades, not iridium-192, neutron bomb",
|
||||
requires: "grenades, not iridium-192, neutron bomb, vacuum bomb",
|
||||
effect() {
|
||||
tech.isBlockExplode = true; //chain reaction
|
||||
},
|
||||
@@ -5013,9 +5018,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode
|
||||
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && !tech.isPetalsExplode && !tech.isCircleExplode
|
||||
},
|
||||
requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics",
|
||||
requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test",
|
||||
effect() {
|
||||
tech.isNeutronBomb = true;
|
||||
b.setGrenadeMode()
|
||||
@@ -6147,7 +6152,7 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.18
|
||||
return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.16
|
||||
},
|
||||
requires: "laser, not free-electron",
|
||||
effect() {
|
||||
@@ -6174,14 +6179,14 @@ const tech = {
|
||||
},
|
||||
requires: "laser, not pulse, diodes",
|
||||
effect() {
|
||||
tech.laserFieldDrain = 0.007 //base is 0.002
|
||||
tech.laserDamage = 0.54; //base is 0.18
|
||||
tech.laserFieldDrain = 0.0063 //base is 0.002
|
||||
tech.laserDamage = 0.48; //base is 0.16
|
||||
tech.laserColor = "#83f"
|
||||
tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
|
||||
},
|
||||
remove() {
|
||||
tech.laserFieldDrain = 0.002;
|
||||
tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.16
|
||||
tech.laserFieldDrain = 0.0018;
|
||||
tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
|
||||
tech.laserColor = "#f00"
|
||||
tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
|
||||
}
|
||||
@@ -6348,7 +6353,7 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.18 && !tech.isStuckOn
|
||||
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.16 && !tech.isStuckOn
|
||||
},
|
||||
requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
|
||||
effect() {
|
||||
@@ -7837,6 +7842,26 @@ const tech = {
|
||||
// },
|
||||
// remove() {}
|
||||
// },
|
||||
{
|
||||
name: "return",
|
||||
description: "return to the introduction level<br>reduce combat <strong>difficulty</strong> by <strong>2 levels</strong>",
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
isJunk: true,
|
||||
isNonRefundable: true,
|
||||
allowed() {
|
||||
return true
|
||||
},
|
||||
requires: "",
|
||||
effect() {
|
||||
// level.levelsCleared = 0 //increases chance of power ups spawns, so shouldn't reset
|
||||
level.difficultyDecrease(simulation.difficultyMode * 2)
|
||||
level.onLevel = 0
|
||||
simulation.clearNow = true //end current level
|
||||
},
|
||||
remove() {}
|
||||
},
|
||||
{
|
||||
name: "panpsychism",
|
||||
description: "awaken all <strong class='color-block'>blocks</strong><br><strong class='color-block'>blocks</strong> have a chance to spawn power ups",
|
||||
@@ -7907,7 +7932,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "closed timelike curve",
|
||||
description: "spawn 5 <strong class='color-f'>field</strong> power ups, but every 12 seconds<br>teleport a second into your future<br>",
|
||||
description: "spawn 5 <strong class='color-f'>field</strong> power ups, but every 12 seconds<br>teleport a second into your future or past",
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
@@ -7923,7 +7948,14 @@ const tech = {
|
||||
function loop() {
|
||||
if (!simulation.paused && m.alive) {
|
||||
if (!(simulation.cycle % 720)) {
|
||||
requestAnimationFrame(() => { simulation.timePlayerSkip(60) }); //wrapping in animation frame prevents errors, probably
|
||||
requestAnimationFrame(() => {
|
||||
if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option
|
||||
m.rewind(60)
|
||||
m.energy += 0.4 //to make up for lost energy
|
||||
} else {
|
||||
simulation.timePlayerSkip(60)
|
||||
}
|
||||
}); //wrapping in animation frame prevents errors, probably
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(loop);
|
||||
@@ -9065,7 +9097,10 @@ const tech = {
|
||||
allowed() { return true },
|
||||
requires: "",
|
||||
effect() {
|
||||
setInterval(() => { m.rewind(120) }, 10000);
|
||||
setInterval(() => {
|
||||
m.rewind(120)
|
||||
m.energy += 0.4
|
||||
}, 10000);
|
||||
// for (let i = 0; i < 24; i++) {
|
||||
// setTimeout(() => { m.rewind(120) }, i * 5000);
|
||||
// }
|
||||
@@ -9083,7 +9118,10 @@ const tech = {
|
||||
allowed() { return true },
|
||||
requires: "",
|
||||
effect() {
|
||||
setInterval(() => { m.rewind(30) }, 4000);
|
||||
setInterval(() => {
|
||||
m.rewind(30)
|
||||
m.energy += 0.2
|
||||
}, 4000);
|
||||
},
|
||||
remove() {}
|
||||
},
|
||||
@@ -9674,6 +9712,28 @@ const tech = {
|
||||
},
|
||||
remove() {}
|
||||
},
|
||||
// {
|
||||
// name: "JUNKie", //just crashes the game
|
||||
// description: "all junk",
|
||||
// maxCount: 1,
|
||||
// count: 0,
|
||||
// frequency: 1,
|
||||
// frequencyDefault: 1,
|
||||
// isNonRefundable: true,
|
||||
// isJunk: true,
|
||||
// allowed() { return true },
|
||||
// requires: "",
|
||||
// effect() {
|
||||
|
||||
// for (let i = 0, len = tech.tech.length; i < len; i++) {
|
||||
// if (tech.tech[i].isJunk && tech.tech[i].count < tech.tech[i].maxCount) tech.tech[i].effect()
|
||||
// }
|
||||
|
||||
// },
|
||||
// remove() {
|
||||
// tech.tooManyTechChoices = 0
|
||||
// }
|
||||
// },
|
||||
{
|
||||
name: "path integral",
|
||||
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Path_integral_formulation' class="link">path integral</a>`,
|
||||
|
||||
Reference in New Issue
Block a user