propagator

tech: propagator - 67% damage, lose 1/2 second of time when a mob dies

timeSkipBoss is back, maybe it will not cause bugs this time
  immune to harm unless player is inside horizon
  player loses time when inside horizon

snake bosses are immune to harm until your remove their tail

mob shields are 30% stronger
time dilation: retrocausality automatically grabs power ups
eternalism 50->40% damage
paradigm shift 10->16% chance to get a research when ejecting tech
reaction inhibitor 11->13% mob health reduction
recycling 1->0.5% health for 5 seconds
  up to 2.5% per mob kill at normal max health

bug fixes
This commit is contained in:
landgreen
2022-05-30 12:28:05 -07:00
parent 779500ce21
commit 06c1285828
12 changed files with 407 additions and 220 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -2109,10 +2109,10 @@ const b = {
onEnd() {}, onEnd() {},
do() { do() {
if (this.endCycle < simulation.cycle + 1) this.isWave = false if (this.endCycle < simulation.cycle + 1) this.isWave = false
if (Matter.Query.point(map, this.position).length) { //check if inside map if (Matter.Query.point(map, this.position).length) { //check if inside map //|| Matter.Query.point(body, this.position).length
this.isBranch = true; this.isBranch = true;
this.do = () => { if (this.endCycle < simulation.cycle + 1) this.isWave = false } this.do = () => { if (this.endCycle < simulation.cycle + 1) this.isWave = false }
} else { //check if inside a body } else { //check if inside a mob
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position))
const radius = mob[i].radius + tech.extruderRange / 2 const radius = mob[i].radius + tech.extruderRange / 2
@@ -2387,14 +2387,14 @@ const b = {
} }
if (tech.isLaserPush) { //push mobs away if (tech.isLaserPush) { //push mobs away
const index = path.length - 1 const index = path.length - 1
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.94, y: best.who.velocity.y * 0.94 }); 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.006 * push * Math.min(6, best.who.mass)) 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.applyForce(best.who, path[index], force) Matter.Body.applyForce(best.who, path[index], force)
} }
} else if (tech.isLaserPush && best.who.classType === "body") { } else if (tech.isLaserPush && best.who.classType === "body") {
const index = path.length - 1 const index = path.length - 1
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.94, y: best.who.velocity.y * 0.94 }); 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.006 * push * Math.min(6, best.who.mass)) 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.applyForce(best.who, path[index], force) Matter.Body.applyForce(best.who, path[index], force)
} }
}; };
@@ -6996,7 +6996,7 @@ const b = {
x: 7.5 * Math.cos(m.angle - Math.PI / 2), x: 7.5 * Math.cos(m.angle - Math.PI / 2),
y: 7.5 * Math.sin(m.angle - Math.PI / 2) y: 7.5 * Math.sin(m.angle - Math.PI / 2)
} }
const dmg = 0.66 * tech.laserDamage // 3.5 * 0.55 = 200% more damage const dmg = 0.70 * tech.laserDamage // 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 where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
const eye = { const eye = {
x: m.pos.x + 15 * Math.cos(m.angle), x: m.pos.x + 15 * Math.cos(m.angle),

View File

@@ -198,7 +198,7 @@ function collisionChecks(event) {
const v = Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)); const v = Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity));
if (v > 9) { if (v > 9) {
if (tech.blockDmg) { //electricity if (tech.blockDmg) { //electricity
console.log("hi") // console.log("hi")
Matter.Body.setVelocity(mob[k], { x: 0.5 * mob[k].velocity.x, y: 0.5 * mob[k].velocity.y }); Matter.Body.setVelocity(mob[k], { x: 0.5 * mob[k].velocity.x, y: 0.5 * mob[k].velocity.y });
if (tech.isBlockRadiation && !mob[k].isShielded && !mob[k].isMobBullet) { if (tech.isBlockRadiation && !mob[k].isShielded && !mob[k].isMobBullet) {
mobs.statusDoT(mob[k], tech.blockDmg * m.dmgScale * 4 / 12, 360) //200% increase -> x (1+2) //over 7s -> 360/30 = 12 half seconds -> 3/12 mobs.statusDoT(mob[k], tech.blockDmg * m.dmgScale * 4 / 12, 360) //200% increase -> x (1+2) //over 7s -> 360/30 = 12 half seconds -> 3/12

View File

@@ -187,7 +187,7 @@ window.addEventListener('load', () => {
const canvas = document.getElementById("canvas"); const canvas = document.getElementById("canvas");
//using "const" causes problems in safari when an ID shares the same name. //using "const" causes problems in safari when an ID shares the same name.
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
// const ctx = canvas.getContext('2d', { alpha: false }); //optimization, but doesn't work // const ctx = canvas.getContext('2d', { alpha: false }); //optimization, this works if you wipe with the background color of each level
document.body.style.backgroundColor = "#fff"; document.body.style.backgroundColor = "#fff";
@@ -278,7 +278,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
if (tech.tech[i].count > 0) { if (tech.tech[i].count > 0) {
const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
if (tech.tech[i].isNonRefundable) { if (tech.tech[i].isNonRefundable) {
text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" style = "border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>` text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" style = "border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
} else if (tech.tech[i].isFieldTech) { } else if (tech.tech[i].isFieldTech) {
text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" ${style}><div class="grid-title"> text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" ${style}><div class="grid-title">
<span style="position:relative;"> <span style="position:relative;">

View File

@@ -17,10 +17,10 @@ const level = {
if (level.levelsCleared === 0) { //this code only runs on the first level if (level.levelsCleared === 0) { //this code only runs on the first level
// // simulation.isHorizontalFlipped = true // // simulation.isHorizontalFlipped = true
// m.addHealth(Infinity) // m.addHealth(Infinity)
// m.setField("standing wave") // m.setField("time dilation")
// b.giveGuns("nail gun") // b.giveGuns("nail gun")
// tech.giveTech("closed timelike curve") // tech.giveTech("closed timelike curve")
// tech.giveTech("irradiated nails") // tech.giveTech("retrocausality")
// tech.giveTech("pneumatic actuator") // tech.giveTech("pneumatic actuator")
// tech.giveTech("6s half-life") // tech.giveTech("6s half-life")
// for (let i = 0; i < 10; i++) tech.giveTech("replication") // for (let i = 0; i < 10; i++) tech.giveTech("replication")
@@ -36,8 +36,8 @@ const level = {
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// simulation.enableConstructMode() //used to build maps in testing mode // simulation.enableConstructMode() //used to build maps in testing mode
// level.testing(); // level.testing();
// level.reactor(); //not in rotation, used for testing // spawn.snakeSpitBoss(1900, -500)
// spawn.timeBoss(1900, -500) // level.reservoir(); //not in rotation, used for testing
if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************
// powerUps.research.changeRerolls(3000) // powerUps.research.changeRerolls(3000)
@@ -2681,7 +2681,7 @@ const level = {
// spawn.shieldingBoss(1700, -500) // spawn.shieldingBoss(1700, -500)
// for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40); // for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40);
// for (let i = 0; i < 4; i++) spawn.starter(1900, -500) for (let i = 0; i < 4; i++) spawn.starter(1900, -500)
// spawn.pulsar(1900, -500) // spawn.pulsar(1900, -500)
// spawn.shield(mob[mob.length - 1], 1900, -500, 1); // spawn.shield(mob[mob.length - 1], 1900, -500, 1);
// mob[mob.length - 1].isShielded = true // mob[mob.length - 1].isShielded = true
@@ -3294,8 +3294,8 @@ const level = {
} }
//2nd floor //2nd floor
spawn.mapVertex(855, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); spawn.mapVertex(-687, -1936, "-625 50 0 100 625 50 625 -50 -625 -50");
spawn.mapVertex(-687, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); spawn.mapVertex(855, -1936, "-625 50 0 100 625 50 625 -50 -625 -50");
//2nd floor right building //2nd floor right building
// spawn.mapRect(550, -3050, 600, 175); // spawn.mapRect(550, -3050, 600, 175);
@@ -3328,11 +3328,11 @@ const level = {
spawn.randomMob(950, -1725, 0.1); spawn.randomMob(950, -1725, 0.1);
spawn.randomMob(-725, -1775, 0.1); spawn.randomMob(-725, -1775, 0.1);
spawn.randomMob(-200, -2075, 0); spawn.randomMob(-200, -2075, 0);
spawn.randomMob(-550, -3500, -0.2);
spawn.randomMob(375, -2125, 0); spawn.randomMob(375, -2125, 0);
spawn.randomMob(1025, -3200, 0);
spawn.randomMob(-550, -3500, 0);
spawn.randomMob(-700, -2450, -0.1); spawn.randomMob(-700, -2450, -0.1);
spawn.randomMob(-1175, -2775, -0.1); spawn.randomMob(-1175, -2775, -0.1);
spawn.randomMob(1025, -3200, -0.2);
spawn.randomMob(-525, -3750, -0.2); spawn.randomMob(-525, -3750, -0.2);
spawn.randomMob(1350, -2075, -0.3); spawn.randomMob(1350, -2075, -0.3);
spawn.randomMob(1775, 1000, -0.4); spawn.randomMob(1775, 1000, -0.4);

View File

@@ -1119,7 +1119,7 @@ const mobs = {
if (tech.iceIXOnDeath && this.isSlowed) { if (tech.iceIXOnDeath && this.isSlowed) {
for (let i = 0, len = 2 * Math.sqrt(Math.min(this.mass, 25)) * tech.iceIXOnDeath; i < len; i++) b.iceIX(3, Math.random() * 2 * Math.PI, this.position) for (let i = 0, len = 2 * Math.sqrt(Math.min(this.mass, 25)) * tech.iceIXOnDeath; i < len; i++) b.iceIX(3, Math.random() * 2 * Math.PI, this.position)
} }
if (tech.deathSpawnsFromBoss || (tech.deathSpawns && this.isDropPowerUp)) { if (tech.deathSpawnsFromBoss || tech.deathSpawns) {
const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss
const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns)) const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns))
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
@@ -1130,6 +1130,22 @@ const mobs = {
}); });
} }
} }
if (tech.isDeathSkipTime && !m.isBodiesAsleep) {
requestAnimationFrame(() => {
simulation.timePlayerSkip(this.isBoss ? 45 : 25)
simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
}); //wrapping in animation frame prevents errors, probably
// if (tech.isFlipFlopOn) {
// m.rewind(this.isBoss ? 45 : 25)
// } else {
// requestAnimationFrame(() => {
// simulation.timePlayerSkip(this.isBoss ? 45 : 25)
// simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
// }); //wrapping in animation frame prevents errors, probably
// }
}
if (tech.isEnergyLoss) m.energy *= 0.75; if (tech.isEnergyLoss) m.energy *= 0.75;
powerUps.spawnRandomPowerUp(this.position.x, this.position.y); powerUps.spawnRandomPowerUp(this.position.x, this.position.y);
m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks() m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks()

View File

@@ -2529,6 +2529,25 @@ const m = {
this.rewindCount = 0 this.rewindCount = 0
m.grabPowerUpRange2 = 300000 m.grabPowerUpRange2 = 300000
m.hold = function() { m.hold = function() {
m.grabPowerUp();
// //grab power ups
// for (let i = 0, len = powerUp.length; i < len; ++i) {
// if (
// Vector.magnitudeSquared(Vector.sub(m.pos, powerUp[i].position)) < 100000 &&
// !simulation.isChoosing &&
// (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)
// ) {
// powerUps.onPickUp(powerUp[i]);
// powerUp[i].effect();
// Matter.Composite.remove(engine.world, powerUp[i]);
// powerUp.splice(i, 1);
// break; //because the array order is messed up after splice
// }
// }
if (m.isHolding) { if (m.isHolding) {
m.drawHold(m.holdingTarget); m.drawHold(m.holdingTarget);
m.holding(); m.holding();
@@ -2568,20 +2587,6 @@ const m = {
} else { } else {
m.undoCrouch() m.undoCrouch()
} }
//grab power ups
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (
Vector.magnitudeSquared(Vector.sub(m.pos, powerUp[i].position)) < 100000 &&
!simulation.isChoosing &&
(powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)
) {
powerUps.onPickUp(powerUp[i]);
powerUp[i].effect();
Matter.Composite.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break; //because the array order is messed up after splice
}
}
if (!(this.rewindCount % 30)) { if (!(this.rewindCount % 30)) {
if (tech.isRewindBot) { if (tech.isRewindBot) {
for (let i = 0; i < tech.isRewindBot; i++) { for (let i = 0; i < tech.isRewindBot; i++) {
@@ -2594,8 +2599,6 @@ const m = {
const who = bullet[bullet.length - 1] const who = bullet[bullet.length - 1]
who.endCycle = simulation.cycle + 60 who.endCycle = simulation.cycle + 60
} }
} }
} }
} }
@@ -2612,7 +2615,7 @@ const m = {
} else { } else {
m.fieldFire = true; m.fieldFire = true;
m.isBodiesAsleep = false; m.isBodiesAsleep = false;
m.drain = 0.003 m.drain = 0.0025
m.hold = function() { m.hold = function() {
if (m.isHolding) { if (m.isHolding) {
m.wakeCheck(); m.wakeCheck();

View File

@@ -137,7 +137,7 @@ const powerUps = {
}, },
doDefault() { doDefault() {
//draw power ups //draw power ups
ctx.globalAlpha = 0.4 * Math.sin(m.cycle * 0.15) + 0.6; ctx.globalAlpha = 0.4 * Math.sin(simulation.cycle * 0.15) + 0.6;
for (let i = 0, len = powerUp.length; i < len; ++i) { for (let i = 0, len = powerUp.length; i < len; ++i) {
ctx.beginPath(); ctx.beginPath();
ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI); ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
@@ -237,7 +237,6 @@ const powerUps = {
} }
}, },
choose(type, index) { choose(type, index) {
console.log('choose')
if (type === "gun") { if (type === "gun") {
b.giveGuns(index) b.giveGuns(index)
let text = `b.giveGuns("<span class='color-text'>${b.guns[index].name}</span>")` let text = `b.giveGuns("<span class='color-text'>${b.guns[index].name}</span>")`
@@ -356,7 +355,7 @@ const powerUps = {
// document.body.style.overflow = "hidden" // document.body.style.overflow = "hidden"
// if (m.alive){} // if (m.alive){}
if (simulation.paused) requestAnimationFrame(cycle); if (simulation.paused) requestAnimationFrame(cycle);
simulation.paused = false; if (m.alive) simulation.paused = false;
simulation.isChoosing = false; //stops p from un pausing on key down simulation.isChoosing = false; //stops p from un pausing on key down
build.unPauseGrid() build.unPauseGrid()
if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles
@@ -1080,7 +1079,7 @@ const powerUps = {
}, },
pauseEjectTech(index) { pauseEjectTech(index) {
if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) { if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) {
if (Math.random() < 0.1 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) { if (Math.random() < 0.16 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) {
tech.removeTech(index) tech.removeTech(index)
powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
} else { } else {

View File

@@ -521,9 +521,7 @@ const simulation = {
} }
}, len * swapPeriod); }, len * swapPeriod);
}, },
wipe() { wipe() {}, //set in simulation.startGame
ctx.clearRect(0, 0, canvas.width, canvas.height);
},
gravity() { gravity() {
function addGravity(bodies, magnitude) { function addGravity(bodies, magnitude) {
for (var i = 0; i < bodies.length; i++) { for (var i = 0; i < bodies.length; i++) {
@@ -1049,7 +1047,7 @@ const simulation = {
if (m.lastKillCycle + 300 > m.cycle) { //effects active for 5 seconds after killing a mob if (m.lastKillCycle + 300 > m.cycle) { //effects active for 5 seconds after killing a mob
if (tech.isEnergyRecovery && m.immuneCycle < m.cycle) m.energy += m.maxEnergy * 0.05 if (tech.isEnergyRecovery && m.immuneCycle < m.cycle) m.energy += m.maxEnergy * 0.05
if (tech.isHealthRecovery) m.addHealth(0.01 * m.maxHealth) if (tech.isHealthRecovery) m.addHealth(0.005 * m.maxHealth)
} }
if (!(m.cycle % 420)) { //once every 7 seconds if (!(m.cycle % 420)) { //once every 7 seconds

View File

@@ -1,10 +1,11 @@
//main object for spawning things in a level //main object for spawning things in a level
const spawn = { const spawn = {
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"], nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"],
// other bosses: suckerBoss, laserBoss, tetherBoss, mantisBoss, bounceBoss, sprayBoss //these need a particular level to work so they are not included in the random pool // other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss //these need a particular level to work so they are not included in the random pool
randomBossList: ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", randomBossList: [
"powerUpBoss", "powerUpBossBaby", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
"snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss" "powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
"snakeBoss", "snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "shieldingBoss", "timeSkipBoss"
], ],
bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed
bossTypeSpawnIndex: 0, //increases as the boss type cycles bossTypeSpawnIndex: 0, //increases as the boss type cycles
@@ -19,7 +20,7 @@ const spawn = {
pickList: ["starter", "starter"], pickList: ["starter", "starter"],
fullPickList: [ fullPickList: [
"hopper", "hopper", "hopper", "hopper", "hopper", "hopper",
"slasher", "slasher", "hopper", "slasher", "slasher", "slasher",
"stabber", "stabber", "stabber", "stabber", "stabber", "stabber",
"springer", "springer", "springer", "springer", "springer", "springer",
"shooter", "shooter", "shooter", "shooter",
@@ -2028,7 +2029,6 @@ const spawn = {
me.seePlayerFreq = 300; me.seePlayerFreq = 300;
const springStiffness = 0.00008; //simulation.difficulty const springStiffness = 0.00008; //simulation.difficulty
const springDampening = 0.01; const springDampening = 0.01;
me.springTarget = { me.springTarget = {
x: me.position.x, x: me.position.x,
y: me.position.y y: me.position.y
@@ -2055,11 +2055,9 @@ const spawn = {
Composite.add(engine.world, cons[cons.length - 1]); Composite.add(engine.world, cons[cons.length - 1]);
cons[len2].length = 100 + 1.5 * radius; cons[len2].length = 100 + 1.5 * radius;
me.cons2 = cons[len2]; me.cons2 = cons[len2];
me.startingDamageReduction = me.damageReduction me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false me.isInvulnerable = false
me.invulnerabilityCountDown = 0 me.invulnerabilityCountDown = 0
me.do = function() { me.do = function() {
this.checkStatus(); this.checkStatus();
this.gravity(); this.gravity();
@@ -2069,7 +2067,6 @@ const spawn = {
ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI); ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI);
ctx.fillStyle = "#222"; ctx.fillStyle = "#222";
ctx.fill(); ctx.fill();
this.seePlayerCheck() this.seePlayerCheck()
// this.seePlayerByHistory() // this.seePlayerByHistory()
if (this.isInvulnerable) { if (this.isInvulnerable) {
@@ -2202,7 +2199,6 @@ const spawn = {
} }
} }
}; };
me.onDeath = function() { me.onDeath = function() {
this.removeCons(); this.removeCons();
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y) if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
@@ -2215,7 +2211,6 @@ const spawn = {
} }
} }
}; };
const sideLength = 80 // distance between each node mob const sideLength = 80 // distance between each node mob
const nodes = 3 const nodes = 3
const angle = 2 * Math.PI / nodes const angle = 2 * Math.PI / nodes
@@ -2255,7 +2250,6 @@ const spawn = {
} }
}; };
} }
const stiffness = 0.01 const stiffness = 0.01
const damping = 0.1 const damping = 0.1
for (let i = 1; i < nodes; ++i) { //attach to center mob for (let i = 1; i < nodes; ++i) { //attach to center mob
@@ -2287,88 +2281,86 @@ const spawn = {
} }
spawn.allowShields = true; spawn.allowShields = true;
}, },
timeSkipBoss(x, y, radius = 55) { // timeSkipBoss(x, y, radius = 55) {
mobs.spawn(x, y, 6, radius, '#000'); // mobs.spawn(x, y, 6, radius, '#000');
let me = mob[mob.length - 1]; // let me = mob[mob.length - 1];
me.isBoss = true; // me.isBoss = true;
// me.stroke = "transparent"; //used for drawSneaker // // me.stroke = "transparent"; //used for drawSneaker
me.timeSkipLastCycle = 0 // me.timeSkipLastCycle = 0
me.eventHorizon = 1800; //required for black hole // me.eventHorizon = 1800; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000 // me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
me.accelMag = 0.0004 * simulation.accelScale; // me.accelMag = 0.0004 * simulation.accelScale;
// me.frictionAir = 0.005; // // me.frictionAir = 0.005;
// me.memory = 1600; // // me.memory = 1600;
// Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger // // Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger
Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger // Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
spawn.shield(me, x, y, 1); // spawn.shield(me, x, y, 1);
// me.onDeath = function() {
// //applying forces to player doesn't seem to work inside this method, not sure why
// powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// };
// me.do = function() {
// //keep it slow, to stop issues from explosion knock backs
// if (this.speed > 8) {
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * 0.99,
// y: this.velocity.y * 0.99
// });
// }
// this.seePlayerCheck();
// this.checkStatus();
// this.attraction()
// if (!simulation.isTimeSkipping) {
// const compress = 1
// if (this.timeSkipLastCycle < simulation.cycle - compress &&
// Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) {
// this.timeSkipLastCycle = simulation.cycle
// simulation.timeSkip(compress)
// this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})`
// this.stroke = "#014"
// this.isShielded = false;
// this.isDropPowerUp = true;
// this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets
me.onDeath = function() { // ctx.beginPath();
//applying forces to player doesn't seem to work inside this method, not sure why // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
powerUps.spawnBossPowerUp(this.position.x, this.position.y) // ctx.fillStyle = "#fff";
}; // ctx.globalCompositeOperation = "destination-in"; //in or atop
me.do = function() { // ctx.fill();
//keep it slow, to stop issues from explosion knock backs // ctx.globalCompositeOperation = "source-over";
if (this.speed > 8) { // ctx.beginPath();
Matter.Body.setVelocity(this, { // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
x: this.velocity.x * 0.99, // ctx.clip();
y: this.velocity.y * 0.99
});
}
this.seePlayerCheck();
this.checkStatus();
this.attraction()
if (!simulation.isTimeSkipping) {
const compress = 1
if (this.timeSkipLastCycle < simulation.cycle - compress &&
Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) {
this.timeSkipLastCycle = simulation.cycle
simulation.timeSkip(compress)
this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})` // // ctx.beginPath();
this.stroke = "#014" // // ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI);
this.isShielded = false; // // ctx.fillStyle = "#000";
this.isDropPowerUp = true; // // ctx.fill();
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets // // ctx.strokeStyle = "#000";
// // ctx.stroke();
ctx.beginPath(); // // ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); // // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
ctx.fillStyle = "#fff"; // // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
ctx.globalCompositeOperation = "destination-in"; //in or atop // // ctx.fill();
ctx.fill(); // // ctx.strokeStyle = "#000";
ctx.globalCompositeOperation = "source-over"; // // ctx.stroke();
ctx.beginPath(); // } else {
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); // this.isShielded = true;
ctx.clip(); // this.isDropPowerUp = false;
// this.seePlayer.recall = false
// ctx.beginPath(); // this.fill = "transparent"
// ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI); // this.stroke = "transparent"
// ctx.fillStyle = "#000"; // this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets
// ctx.fill(); // ctx.beginPath();
// ctx.strokeStyle = "#000"; // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// ctx.stroke(); // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
// ctx.fill();
// ctx.beginPath(); // }
// ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); // }
// ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`; // }
// ctx.fill(); // },
// ctx.strokeStyle = "#000";
// ctx.stroke();
} else {
this.isShielded = true;
this.isDropPowerUp = false;
this.seePlayer.recall = false
this.fill = "transparent"
this.stroke = "transparent"
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
ctx.fill();
}
}
}
},
beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) { beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,190)"); mobs.spawn(x, y, 4, radius, "rgb(255,0,190)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
@@ -3931,7 +3923,7 @@ const spawn = {
me.isBoss = true; me.isBoss = true;
Matter.Body.setDensity(me, 0.001); //normal is 0.001 Matter.Body.setDensity(me, 0.001); //normal is 0.001
me.inertia = Infinity; me.inertia = Infinity;
me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0.06 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = me.damageReduction me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false me.isInvulnerable = false
me.frictionAir = 0.01 me.frictionAir = 0.01
@@ -3974,8 +3966,8 @@ const spawn = {
const unit = Vector.sub(player.position, this.position) const unit = Vector.sub(player.position, this.position)
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1)); Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1));
} else { } else {
if (Math.abs(this.velocity.y) < 9) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.02 }); if (Math.abs(this.velocity.y) < 10) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.02 });
if (Math.abs(this.velocity.x) < 6.5) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.02, y: this.velocity.y }); if (Math.abs(this.velocity.x) < 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.02, y: this.velocity.y });
} }
if (this.isInvulnerable) { if (this.isInvulnerable) {
@@ -5138,7 +5130,7 @@ const spawn = {
me.maxCycles = 110; me.maxCycles = 110;
me.frictionStatic = 0; me.frictionStatic = 0;
me.friction = 0; me.friction = 0;
me.frictionAir = 0.5; me.frictionAir = 1;
// me.homePosition = { x: x, y: y }; // me.homePosition = { x: x, y: y };
spawn.shield(me, x, y, 1); spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
@@ -5153,7 +5145,7 @@ const spawn = {
}; };
me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.do = function() { me.do = function() {
// this.armor(); Matter.Body.rotate(this, 0.003) //gently spin around
this.checkStatus(); this.checkStatus();
ctx.beginPath(); //draw cycle timer ctx.beginPath(); //draw cycle timer
ctx.moveTo(this.vertices[this.vertices.length - 1].x, this.vertices[this.vertices.length - 1].y) ctx.moveTo(this.vertices[this.vertices.length - 1].x, this.vertices[this.vertices.length - 1].y)
@@ -5186,6 +5178,73 @@ const spawn = {
} }
}; };
}, },
timeSkipBoss(x, y, radius = 50) {
mobs.spawn(x, y, 15, radius, "rgb(150, 150, 255)");
let me = mob[mob.length - 1];
me.isBoss = true;
me.eventHorizon = 0; //set in mob loop
me.frictionStatic = 0;
me.friction = 0;
me.frictionAir = 0.004;
me.accelMag = 0.0001 + 0.00003 * simulation.accelScale
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 50 + 100 * Math.random(), true)
Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 //makes effective life much larger
me.damageReduction = 0.07 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// requestAnimationFrame(() => { simulation.timePlayerSkip(120) }); //wrapping in animation frame prevents errors, probably
};
me.onDamage = function() {
//find side of mob closest to player
//causes lag for foam,laser too many seekers //maybe scale chance with dmg
// const where = Vector.add(this.position, Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.radius + 10))
// spawn.seeker(where.x, where.y); //give the bullet a rotational velocity as if they were attached to a vertex
};
me.do = function() {
this.seePlayerByHistory();
this.attraction();
this.checkStatus();
this.eventHorizon = 950 + 170 * Math.sin(simulation.cycle * 0.005)
if (!simulation.isTimeSkipping) {
if (Vector.magnitude(Vector.sub(this.position, m.pos)) < this.eventHorizon) {
this.attraction();
this.damageReduction = this.startingDamageReduction
this.isInvulnerable = false
if (!(simulation.cycle % 15)) requestAnimationFrame(() => {
simulation.timePlayerSkip(8)
simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
}); //wrapping in animation frame prevents errors, probably
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
ctx.fillStyle = "#fff";
ctx.globalCompositeOperation = "destination-in"; //in or atop
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// ctx.stroke();
ctx.clip();
} else {
this.damageReduction = 0
this.isInvulnerable = true
//prevents other things from being drawn later on in the draw cycle
requestAnimationFrame(() => {
simulation.camera();
ctx.beginPath(); //gets rid of already draw shapes
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI, false); //part you can't see
ctx.fillStyle = color.background;
ctx.fill();
ctx.restore();
})
}
}
};
},
streamBoss(x, y, radius = 110) { streamBoss(x, y, radius = 110) {
mobs.spawn(x, y, 5, radius, "rgb(245,180,255)"); mobs.spawn(x, y, 5, radius, "rgb(245,180,255)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
@@ -5412,10 +5471,14 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.accelMag = 0.0001 + 0.0002 * Math.sqrt(simulation.accelScale) me.accelMag = 0.0003 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250; me.memory = 250;
me.laserRange = 500; me.laserRange = 500;
Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.startingDamageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0
me.isInvulnerable = true
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < mob.length; i++) { //wake up tail mobs for (let i = 0; i < mob.length; i++) { //wake up tail mobs
@@ -5428,9 +5491,7 @@ const spawn = {
}; };
me.canFire = false; me.canFire = false;
me.closestVertex1 = 0; me.closestVertex1 = 0;
// me.closestVertex2 = 1;
me.cycle = 0 me.cycle = 0
me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.do = function() { me.do = function() {
// this.armor(); // this.armor();
this.seePlayerByHistory() this.seePlayerByHistory()
@@ -5439,7 +5500,7 @@ const spawn = {
this.cycle++ this.cycle++
if (this.seePlayer.recall && ((this.cycle % 10) === 0)) { if (this.seePlayer.recall && ((this.cycle % 10) === 0)) {
if (this.canFire) { if (this.canFire) {
if (this.cycle > 120) { if (this.cycle > 100) {
this.cycle = 0 this.cycle = 0
this.canFire = false this.canFire = false
// Matter.Body.setAngularVelocity(this, 0.1) // Matter.Body.setAngularVelocity(this, 0.1)
@@ -5450,7 +5511,7 @@ const spawn = {
} }
spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 6) spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 6)
Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001 Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -10) const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -13)
Matter.Body.setVelocity(mob[mob.length - 1], { Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + velocity.x, x: this.velocity.x + velocity.x,
y: this.velocity.y + velocity.y y: this.velocity.y + velocity.y
@@ -5482,14 +5543,29 @@ const spawn = {
// } // }
} }
} }
if (this.isInvulnerable) {
ctx.beginPath();
let vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(255,255,255,0.7)";
ctx.stroke();
}
}; };
//extra space to give head room //extra space to give head room
angle -= 0.1 angle -= 0.1
mag -= 10 mag -= 10
let previousTailID = 0
for (let i = 0; i < nodes; ++i) { for (let i = 0; i < nodes; ++i) {
angle -= 0.15 + i * 0.008 angle -= 0.15 + i * 0.008
mag -= 5 mag -= 5
spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20); spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20);
if (i === 0) mob[mob.length - 1].snakeHeadID = me.id
mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id
} }
this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01); this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01);
@@ -5530,36 +5606,46 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.accelMag = 0.00077 * simulation.accelScale; me.accelMag = 0.0004 + 0.0003 * Math.sqrt(simulation.accelScale)
me.memory = 250; me.memory = 250;
me.laserRange = 500; me.laserRange = 500;
Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.startingDamageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0
me.isInvulnerable = true
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < mob.length; i++) { //wake up tail mobs
if (mob[i].isSnakeTail && mob[i].alive) {
mob[i].isSnakeTail = false;
mob[i].do = mob[i].doActive
// mob[i].removeConsBB();
}
}
}; };
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.do = function() { me.do = function() {
// this.armor();
this.seePlayerByHistory() this.seePlayerByHistory()
this.checkStatus(); this.checkStatus();
this.attraction(); this.attraction();
this.harmZone(); this.harmZone();
if (this.isInvulnerable) {
ctx.beginPath();
let vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(255,255,255,0.7)";
ctx.stroke();
}
}; };
//extra space to give head room //extra space to give head room
angle -= 0.1 angle -= 0.1
mag -= 10 mag -= 10
let previousTailID = 0
for (let i = 0; i < nodes; ++i) { for (let i = 0; i < nodes; ++i) {
angle -= 0.15 + i * 0.008 angle -= 0.15 + i * 0.008
mag -= 5 mag -= 5
spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20); spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20);
if (i === 0) mob[mob.length - 1].snakeHeadID = me.id
mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id
} }
this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01); this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01);
for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors
@@ -5595,23 +5681,23 @@ const spawn = {
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body
me.accelMag = 0.0006 * simulation.accelScale; me.accelMag = 0.0006 * simulation.accelScale;
me.leaveBody = false; me.leaveBody = Math.random() < 0.33 ? true : false;
me.showHealthBar = false; me.showHealthBar = false;
me.isDropPowerUp = false; me.isDropPowerUp = false;
// Matter.Body.setDensity(me, 0.00004); //normal is 0.001 Matter.Body.setDensity(me, 0.003); //normal is 0.001
me.frictionAir = 0.015; me.frictionAir = 0.015;
me.isSnakeTail = true; me.isSnakeTail = true;
me.stroke = "transparent" me.stroke = "transparent"
me.onDeath = function() { me.onDeath = function() {
// if (this.isSnakeTail) { //wake up tail mobs setTimeout(() => {
// for (let i = 0; i < mob.length; i++) { for (let i = 0, len = mob.length; i < len; i++) {
// if (mob[i].isSnakeTail && mob[i].alive) { if (this.id === mob[i].previousTailID && mob[i].alive) mob[i].death()
// mob[i].isSnakeTail = false; if (this.snakeHeadID === mob[i].id) {
// mob[i].do = mob[i].doActive mob[i].isInvulnerable = false
// mob[i].removeConsBB(); mob[i].damageReduction = mob[i].startingDamageReduction
// } }
// } }
// } }, 150);
}; };
me.do = function() { me.do = function() {
this.checkStatus(); this.checkStatus();
@@ -5666,7 +5752,7 @@ const spawn = {
me.stroke = "rgb(220,220,255)"; me.stroke = "rgb(220,220,255)";
Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
me.shield = true; me.shield = true;
me.damageReduction = 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.isUnblockable = true me.isUnblockable = true
me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo
me.collisionFilter.category = cat.mobShield me.collisionFilter.category = cat.mobShield

View File

@@ -221,7 +221,8 @@ const tech = {
}, },
damageFromTech() { damageFromTech() {
let dmg = 1 //m.fieldDamage let dmg = 1 //m.fieldDamage
if (tech.isNoDraftPause) dmg *= 1.5 if (tech.isDeathSkipTime) dmg *= 1.67
if (tech.isNoDraftPause) dmg *= 1.4
if (tech.isTechDebt) dmg *= Math.max(41 / (tech.totalCount + 21), 4 - 0.15 * tech.totalCount) if (tech.isTechDebt) dmg *= Math.max(41 / (tech.totalCount + 21), 4 - 0.15 * tech.totalCount)
if (tech.isAxion && tech.isHarmMACHO) dmg *= 1 + 0.75 * (1 - m.harmReduction()) if (tech.isAxion && tech.isHarmMACHO) dmg *= 1 + 0.75 * (1 - m.harmReduction())
if (tech.OccamDamage) dmg *= tech.OccamDamage if (tech.OccamDamage) dmg *= tech.OccamDamage
@@ -556,7 +557,7 @@ const tech = {
{ {
name: "cache", name: "cache",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Cache_(computing)' class="link">cache</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Cache_(computing)' class="link">cache</a>`,
description: `${powerUps.orb.ammo()} give <strong>16x</strong> more <strong class='color-ammo'>ammo</strong>, but<br>you can't <strong>store</strong> any more <strong class='color-ammo'>ammo</strong> than that`, description: `${powerUps.orb.ammo()} give <strong>1600%</strong> more <strong class='color-ammo'>ammo</strong>, but<br>you can't <strong>store</strong> any more <strong class='color-ammo'>ammo</strong> than that`,
// ammo powerups always max out your gun, // ammo powerups always max out your gun,
// but the maximum ammo ti limited // but the maximum ammo ti limited
// description: `${powerUps.orb.ammo()} give <strong>13x</strong> more <strong class='color-ammo'>ammo</strong>, but<br>you can't <strong>store</strong> any more <strong class='color-ammo'>ammo</strong> than that`, // description: `${powerUps.orb.ammo()} give <strong>13x</strong> more <strong class='color-ammo'>ammo</strong>, but<br>you can't <strong>store</strong> any more <strong class='color-ammo'>ammo</strong> than that`,
@@ -936,7 +937,7 @@ const tech = {
}, },
{ {
name: "reaction inhibitor", name: "reaction inhibitor",
description: "mobs spawn with <strong>11%</strong> less <strong>health</strong>", description: "mobs spawn with <strong>13%</strong> less <strong>health</strong>",
maxCount: 3, maxCount: 3,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -946,7 +947,7 @@ const tech = {
}, },
requires: "", //"any mob death tech", requires: "", //"any mob death tech",
effect: () => { effect: () => {
tech.mobSpawnWithHealth *= 0.89 tech.mobSpawnWithHealth *= 0.87
//set all mobs at full health to 0.85 //set all mobs at full health to 0.85
for (let i = 0; i < mob.length; i++) { for (let i = 0; i < mob.length; i++) {
@@ -957,6 +958,24 @@ const tech = {
tech.mobSpawnWithHealth = 1; tech.mobSpawnWithHealth = 1;
} }
}, },
{
name: "propagator",
description: "increase <strong class='color-d'>damage</strong> by <strong>67%</strong>, but after<br>mobs <strong>die</strong> lose <strong>0.5</strong> seconds of <strong>time</strong>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
tech.isDeathSkipTime = true
},
remove() {
tech.isDeathSkipTime = false
}
},
{ {
name: "decorrelation", name: "decorrelation",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>70%</strong> after not <strong>activating</strong><br>your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> for <strong>2</strong> seconds", description: "reduce <strong class='color-harm'>harm</strong> by <strong>70%</strong> after not <strong>activating</strong><br>your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> for <strong>2</strong> seconds",
@@ -1772,6 +1791,24 @@ const tech = {
m.eyeFillColor = 'transparent' m.eyeFillColor = 'transparent'
} }
}, },
// {
// name: "spacetime interval",
// description: "increase <strong class='color-d'>damage</strong> by <strong>93%</strong>, but after mobs <strong>die</strong><br>move into the <strong>past</strong> / <strong>future</strong> while <strong class='color-flop'>ON</strong> / <strong class='color-flop'>OFF</strong>",
// maxCount: 1,
// count: 0,
// frequency: 4,
// frequencyDefault: 4,
// allowed() {
// return tech.isFlipFlop || tech.isRelay
// },
// requires: "ON/OFF tech",
// effect() {
// tech.isDeathSkipTime = true
// },
// remove() {
// tech.isDeathSkipTime = false
// }
// },
{ {
name: "NAND gate", name: "NAND gate",
description: "if in the <strong class='color-flop'>ON</strong> state<br>do <strong>55.5%</strong> more <strong class='color-d'>damage</strong>", description: "if in the <strong class='color-flop'>ON</strong> state<br>do <strong>55.5%</strong> more <strong class='color-d'>damage</strong>",
@@ -2479,7 +2516,7 @@ const tech = {
}, },
{ {
name: "recycling", name: "recycling",
description: "if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br>regain <strong>1%</strong> of max <strong class='color-h'>health</strong> every second", description: "if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br>regain <strong>0.5%</strong> of max <strong class='color-h'>health</strong> every second",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3172,7 +3209,7 @@ const tech = {
{ {
name: "paradigm shift", name: "paradigm shift",
description: `<strong>clicking</strong> <strong class='color-m'>tech</strong> while paused <strong>ejects</strong> them<br><strong>10%</strong> chance to convert that <strong class='color-m'>tech</strong> into ${powerUps.orb.research(1)}`, description: `<strong>clicking</strong> <strong class='color-m'>tech</strong> while paused <strong>ejects</strong> them<br><strong>16%</strong> chance to convert that <strong class='color-m'>tech</strong> into ${powerUps.orb.research(1)}`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3191,7 +3228,7 @@ const tech = {
{ {
name: "eternalism", name: "eternalism",
// description: `increase <strong class='color-d'>damage</strong> by <strong>60%</strong>, but <strong>time</strong> doesn't <strong>pause</strong><br>while choosing a choosing a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong>`, //${powerUps.orb.heal()} or // description: `increase <strong class='color-d'>damage</strong> by <strong>60%</strong>, but <strong>time</strong> doesn't <strong>pause</strong><br>while choosing a choosing a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong>`, //${powerUps.orb.heal()} or
description: "increase <strong class='color-d'>damage</strong> by <strong>50%</strong>, but<br><strong>time</strong> can't be <strong>paused</strong> <em>(time dilation still works)</em>", description: "increase <strong class='color-d'>damage</strong> by <strong>40%</strong>, but<br><strong>time</strong> can't be <strong>paused</strong> <em>(time dilation still works)</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3556,19 +3593,19 @@ const tech = {
// return `randomly remove <strong>${this.removePercent * 100}%</strong> of your <strong class='color-m'>tech</strong><br>for each removed gain <strong>${this.damagePerRemoved * 100}%</strong> <strong class='color-d'>damage</strong>` // return `randomly remove <strong>${this.removePercent * 100}%</strong> of your <strong class='color-m'>tech</strong><br>for each removed gain <strong>${this.damagePerRemoved * 100}%</strong> <strong class='color-d'>damage</strong>`
// }, // },
descriptionFunction() { descriptionFunction() {
return `randomly remove <strong>half</strong> your <strong class='color-m'>tech</strong><br>for each removed gain <strong>${this.damagePerRemoved * 100}%</strong> <strong class='color-d'>damage</strong> <em>(~${this.damagePerRemoved * 50 * tech.totalCount}%)</em>` return `randomly remove <strong>half</strong> your <strong class='color-m'>tech</strong><br>for each removed gain <strong>${this.damagePerRemoved * 100 }%</strong> <strong class='color-d'>damage</strong> <em>(~${(this.count === 0) ? this.damagePerRemoved * 50 * tech.totalCount : tech.OccamDamage*100}%)</em>`
}, },
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 199,
frequencyDefault: 1, frequencyDefault: 1,
isNonRefundable: true, isNonRefundable: true,
isBadRandomOption: true, isBadRandomOption: true,
allowed() { allowed() {
return (tech.totalCount > 6) return (tech.totalCount > 6)
}, },
requires: "NOT EXPERIMENT MODE, more than 6 tech", requires: "more than 6 tech",
removePercent: 0.5, // removePercent: 0.5,
damagePerRemoved: 0.5, damagePerRemoved: 0.5,
effect() { effect() {
let pool = [] let pool = []
@@ -3577,7 +3614,7 @@ const tech = {
} }
pool = shuffle(pool); //shuffles order of maps pool = shuffle(pool); //shuffles order of maps
let removeCount = 0 let removeCount = 0
for (let i = 0, len = pool.length * this.removePercent; i < len; i++) removeCount += tech.removeTech(pool[i]) for (let i = 0, len = pool.length * this.damagePerRemoved; i < len; i++) removeCount += tech.removeTech(pool[i])
tech.OccamDamage = 1 + this.damagePerRemoved * removeCount tech.OccamDamage = 1 + this.damagePerRemoved * removeCount
// tech.OccamDamage = Math.pow(1.25, removeCount) // tech.OccamDamage = Math.pow(1.25, removeCount)
}, },
@@ -5713,8 +5750,8 @@ const tech = {
simulation.updateGunHUD() simulation.updateGunHUD()
}, },
remove() { remove() {
b.guns[8].ammoPack = 24
if (this.count) { if (this.count) {
b.guns[8].ammoPack = 24
b.guns[8].ammo += this.ammoLost b.guns[8].ammo += this.ammoLost
simulation.updateGunHUD() simulation.updateGunHUD()
} }
@@ -6110,7 +6147,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.17 return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine) && tech.laserDamage === 0.18
}, },
requires: "laser, not free-electron", requires: "laser, not free-electron",
effect() { effect() {
@@ -6138,13 +6175,13 @@ const tech = {
requires: "laser, not pulse, diodes", requires: "laser, not pulse, diodes",
effect() { effect() {
tech.laserFieldDrain = 0.007 //base is 0.002 tech.laserFieldDrain = 0.007 //base is 0.002
tech.laserDamage = 0.51; //base is 0.16 tech.laserDamage = 0.54; //base is 0.18
tech.laserColor = "#83f" tech.laserColor = "#83f"
tech.laserColorAlpha = "rgba(136, 51, 255,0.5)" tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
}, },
remove() { remove() {
tech.laserFieldDrain = 0.002; tech.laserFieldDrain = 0.002;
tech.laserDamage = 0.17; //used in check on pulse and diode: tech.laserDamage === 0.16 tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.16
tech.laserColor = "#f00" tech.laserColor = "#f00"
tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)" tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
} }
@@ -6217,7 +6254,7 @@ const tech = {
{ {
name: "diffuse beam", name: "diffuse beam",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Diffuser_(optics)' class="link">diffuse beam</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Diffuser_(optics)' class="link">diffuse beam</a>`,
description: "<strong class='color-laser'>laser</strong> beam is <strong>wider</strong> and doesn't <strong>reflect</strong><br>increase full beam <strong class='color-d'>damage</strong> by <strong>200%</strong>", description: "<strong class='color-laser'>laser</strong> beam is <strong>wider</strong> and doesn't <strong>reflect</strong><br>increase full beam <strong class='color-d'>damage</strong> by <strong>220%</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -6311,7 +6348,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.17 && !tech.isStuckOn return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.18 && !tech.isStuckOn
}, },
requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier", requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
effect() { effect() {
@@ -7049,7 +7086,7 @@ const tech = {
}, },
requires: "extruder", requires: "extruder",
effect() { effect() {
tech.extruderRange += 60 tech.extruderRange += 55
}, },
remove() { remove() {
tech.extruderRange = 15 tech.extruderRange = 15
@@ -7895,6 +7932,51 @@ const tech = {
}, },
remove() {} remove() {}
}, },
{
name: "translate",
description: "translate n-gon into a random language",
maxCount: 1,
count: 0,
frequency: 0,
isJunk: true,
isNonRefundable: true,
allowed() {
return true
},
requires: "",
effect() {
// generate a container
const gtElem = document.createElement('div')
gtElem.id = "gtElem"
gtElem.style.visibility = 'hidden' // make it invisible
document.body.append(gtElem)
// generate a script to run after creation
function initGT() {
// create a new translate element
new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem')
// ok now since it's loaded perform a funny hack to make it work
const langSelect = document.getElementsByClassName("goog-te-combo")[0]
// select a random language. It takes a second for all langauges to load, so wait a second.
setTimeout(() => {
langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random())
// simulate a click
langSelect.dispatchEvent(new Event('change'))
// now make it go away
const bar = document.getElementById(':1.container')
bar.style.display = 'none'
bar.style.visibility = 'hidden'
}, 1000)
}
// add the google translate script
const translateScript = document.createElement('script')
translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT'
document.body.append(translateScript)
},
remove() {}
},
{ {
name: "discount", name: "discount",
description: "get 3 random <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> for the price of 1!", description: "get 3 random <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> for the price of 1!",
@@ -10223,4 +10305,5 @@ const tech = {
isClusterExplode: null, isClusterExplode: null,
isCircleExplode: null, isCircleExplode: null,
isPetalsExplode: null, isPetalsExplode: null,
isDeathSkipTime: null
} }

View File

@@ -1,14 +1,43 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
new reactor boss: timeBoss - after taking some damage it speeds up the passage of time tech: propagator - 67% damage, lose 1/2 second of time when a mob dies
reactor level has big doors
nonrefundable tech show up in the pause menu timeSkipBoss is back, maybe it will not cause bugs this time
time dilation field - move, jump, and fire 25% faster immune to harm unless player is inside horizon
JUNK tech: closed timelike curve - spawn 5 field power ups, but every 12 seconds teleport a second into your future player loses time when inside horizon
snake bosses are immune to harm until your remove their tail
mob shields are 30% stronger
time dilation: retrocausality automatically grabs power ups
eternalism 50->40% damage
paradigm shift 10->16% chance to get a research when ejecting tech
reaction inhibitor 11->13% mob health reduction
recycling 1->0.5% health for 5 seconds
up to 2.5% per mob kill at normal max health
bug fixes
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************
make targeting skip invulnerable mobs
drones, spores, harpoon, missiles?, mines, nail on death
this helps beat snake boss
spores are biggest issue
let blocking instantly destroy the red orbitals? since they can't be deflected
also mines on reactor level?
also any bullet?
BUG time skip probably led to player being able to move, and game not being paused for a few seconds while the death screen faded in
also small chance it happened with rewind instead, but unlikely
make one value to track all the +dmg effects that don't need dynamic calculations
update it with a set damage function
block manufacturing - molecular assembler tech
Holding r-click will create a slowly increasing in size block, which will be thrown on release
if a mob dies in skiptime it doesn't register? if a mob dies in skiptime it doesn't register?
is this only for the ondeath event? is this only for the ondeath event?
so far, but needs more tests so far, but needs more tests
@@ -19,23 +48,9 @@ make MEE work with harm reduction
how to nerf MEE how to nerf MEE
maybe harm reduction could also reduce energy regen maybe harm reduction could also reduce energy regen
timeSkipBoss
sends out waves of 60s time skip every 5 seconds?
or 1 cycle skip every other cycle
only active when player is inside range
immune to harm outside range?
simulation.timeSkip(60) simulation.timeSkip(60)
skip every other cycle inside black holes? maybe run simulation.timeSkip(60) in a room in labs
maybe run simulation.timeSkip(60) in a map
in labs?
reactor boss
mob fires laser/bullets that timeSkip player mob fires laser/bullets that timeSkip player
maybe an effect when in range of the historyBoss
JUNK tech simulation.timeSkip(60)
add CPT graphics to simulation.timeSkip(60)
for player
tech requires eternalism - 2x time while choosing, gain more damage
Currently, the mob just deals higher damage on impact, which is annoying although not hard to compete with nor unique Currently, the mob just deals higher damage on impact, which is annoying although not hard to compete with nor unique
By "redesign" I mean replacing instances of the regular mob, since the same code is used for the tiny red projectiles (I think) just add a new mob and remove the old one from the rotation By "redesign" I mean replacing instances of the regular mob, since the same code is used for the tiny red projectiles (I think) just add a new mob and remove the old one from the rotation
@@ -51,7 +66,6 @@ About to explode: animation to dark red
Exploding: several shockwaves from the explosion points and tiny trails given to the shrapnel for a second or two until they deaccelerate Exploding: several shockwaves from the explosion points and tiny trails given to the shrapnel for a second or two until they deaccelerate
make laser gain damage and energy drain from fire delay tech make laser gain damage and energy drain from fire delay tech
wording? put it in the gun description wording? put it in the gun description
@@ -62,8 +76,6 @@ pause time like invariant for other things...
charging railgun charging railgun
charging anything? charging anything?
give retrocausality a short delay before it rewinds, so you can pick up powerups without going back
tech expansion: should also make other fields do things tech expansion: should also make other fields do things
how to make the description work how to make the description work
change description based on your current field? change description based on your current field?
@@ -733,23 +745,13 @@ possible names for tech
nuclear pasta - hard matter in neutron star nuclear pasta - hard matter in neutron star
nonlocal nonlocal
fine-tuned universe fine-tuned universe
eternalism https://en.wikipedia.org/wiki/Eternalism_(philosophy_of_time)
axial motor
hall effect thrusters hall effect thrusters
spaghettification spaghettification
particle accelerator particle accelerator
superluminal signalling superluminal signalling
NP-complete NP-complete
lenticular lens: is an array of lenses, designed so that when viewed from slightly different angles, different parts of the image underneath are shown. lenticular lens: is an array of lenses, designed so that when viewed from slightly different angles, different parts of the image underneath are shown.
p-zombie
a tutorial / lore intro
needs to be optional so it doesn't slow experienced players
put something on the intro map
maybe a button triggers something
rename ?
health -> integrity, unity
heal -> also integrity, unity
plot script: plot script: