new reactor boss: timeBoss - after taking some damage it speeds up the passage of time
reactor level has big doors

nonrefundable tech show up in the pause menu
time dilation field - move, jump, and fire 25% faster
JUNK tech: closed timelike curve - spawn 5 field power ups, but every 12 seconds teleport a second into your future
This commit is contained in:
landgreen
2022-05-25 19:15:34 -07:00
parent 25037cac0d
commit 779500ce21
10 changed files with 450 additions and 386 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -271,7 +271,7 @@ const b = {
},
fireCDscale: 1,
setFireCD() {
b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage
b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage * m.fieldFireRate
if (tech.isFastTime) b.fireCDscale *= 0.5
if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.8, b.inventory.length)
if (tech.isFireMoveLock) b.fireCDscale *= 0.5

View File

@@ -275,9 +275,11 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
const style = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'style="animation: techColorCycle 1s linear infinite alternate;"' : ''
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) {
if (tech.tech[i].count > 0) {
const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
if (tech.tech[i].isFieldTech) {
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>`
} 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">
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>

View File

@@ -16,12 +16,13 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// // simulation.isHorizontalFlipped = true
// m.setField("wormhole")
// b.giveGuns("matter wave")
// tech.giveTech("chain reaction")
// tech.giveTech("fireworks")
// tech.giveTech("flame test")
// tech.giveTech("pyrotechnics")
// m.addHealth(Infinity)
// m.setField("standing wave")
// b.giveGuns("nail gun")
// tech.giveTech("closed timelike curve")
// tech.giveTech("irradiated nails")
// tech.giveTech("pneumatic actuator")
// tech.giveTech("6s half-life")
// for (let i = 0; i < 10; i++) tech.giveTech("replication")
// tech.giveTech("eternalism")
// for (let i = 0; i < 10; i++) tech.giveTech("ammonium nitrate")
@@ -30,18 +31,13 @@ const level = {
// for (let i = 0; i < 15; i++) tech.giveTech()
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
// powerUps.research.changeRerolls(100000)
// for (let i = 0; i < 5; i++) tech.giveTech("corona discharge")
// tech.tech[297].frequency = 100
// m.setField("plasma torch")
// tech.giveTech("plasma ball")
// tech.giveTech("extruder")
// m.immuneCycle = Infinity //you can't take damage
// level.difficultyIncrease(15) //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
// level.temple();
// level.testing(); //not in rotation, used for testing
// spawn.slashBoss(1900, -500)
// level.testing();
// level.reactor(); //not in rotation, used for testing
// spawn.timeBoss(1900, -500)
if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************
// powerUps.research.changeRerolls(3000)
@@ -1054,6 +1050,9 @@ const level = {
}
}
},
isClosed() {
return this.position.y > y - 1
},
draw() {
ctx.fillStyle = "#555"
ctx.beginPath();
@@ -2596,7 +2595,11 @@ const level = {
testing() {
const button = level.button(1000, 0)
spawn.bodyRect(1000, -50, 50, 50);
level.custom = () => {
ctx.fillStyle = "#d4d4d4"
ctx.fillRect(2500, -475, 200, 300)
ctx.fillStyle = "rgba(0,255,255,0.1)";
ctx.fillRect(6400, -550, 300, 350);
level.exit.drawAndCheck();
@@ -2605,6 +2608,8 @@ const level = {
level.customTopLayer = () => {
button.query();
button.draw();
ctx.fillStyle = "rgba(0,0,0,0.1)"
ctx.fillRect(-150, -650, 900, 250)
};
level.setPosToSpawn(0, -450); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
@@ -2686,10 +2691,10 @@ const level = {
// spawn.randomMob(1600, -500)
},
reactor() {
level.setPosToSpawn(-50, -800); //normal spawn
level.setPosToSpawn(-550, -800); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 3000;
level.exit.y = -35;
level.exit.x = 3500;
level.exit.y = -42;
spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
level.defaultZoom = 2000
simulation.zoomTransition(level.defaultZoom)
@@ -2699,25 +2704,26 @@ const level = {
// spawn.debris(750, -2200, 3700, 16); //16 debris per level
const button = level.button(1400, 0)
button.isUp = true
spawn.mapRect(-1525, -2825, 1250, 4925);
spawn.mapRect(-400, -2025, 625, 925);
spawn.mapRect(-400, -750, 625, 1200);
spawn.bodyRect(250, -70, 100, 70, 1);
spawn.mapRect(-425, 0, 4200, 2100);
spawn.mapRect(175, -1250, 50, 300);
spawn.mapRect(-475, -2825, 4250, 1025);
spawn.mapRect(-425, 0, 4500, 2100);
spawn.mapRect(-475, -2825, 4500, 1025);
// spawn.mapRect(1200, -1300, 600, 800);
const a = 400 //side length
const c = 100 //corner offset
spawn.mapVertex(1487, -900, `${-a} ${-a+c} ${-a+c} ${-a} ${a-c} ${-a} ${a} ${-a+c} ${a} ${a-c} ${a-c} ${a} ${-a+c} ${a} ${-a} ${a-c}`); //square with edges cut off
//entrance
spawn.mapRect(-2025, -2825, 1250, 4925);
spawn.mapRect(-900, -2825, 1125, 1725);
spawn.mapRect(-900, -750, 1125, 2850);
spawn.mapRect(-325, -1250, 550, 300);
//exit
spawn.mapRect(3300, -2825, 1125, 4925);
spawn.mapRect(2750, -2150, 1025, 1775);
spawn.mapRect(2750, -475, 50, 300);
spawn.mapRect(3800, -2825, 1225, 4925);
spawn.mapRect(2750, -2150, 1325, 1775);
spawn.mapRect(2750, -475, 550, 300);
spawn.mapRect(2750, -7, 1050, 150); //exit room floor
const doorIn = level.door(187, -950, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1
const doorOut = level.door(2762, -175, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1
const doorIn = level.door(-313, -950, 525, 200, 190, 2) //x, y, width, height, distance, speed = 1
const doorOut = level.door(2762, -175, 525, 200, 190, 2) //x, y, width, height, distance, speed = 1
// doorOut.isClosing = true
let isDoorsLocked = false
let isFightOver = false
@@ -2725,7 +2731,7 @@ const level = {
level.custom = () => {
if (isDoorsLocked) {
if (player.position.x < 0) { //if player gets trapped inside starting room open up again
if (player.position.x < -300) { //if player gets trapped inside starting room open up again
isDoorsLocked = false
doorIn.isClosing = false
}
@@ -2738,26 +2744,32 @@ const level = {
doorIn.openClose();
doorOut.openClose();
ctx.fillStyle = "#d5ebef"
ctx.fillRect(2750, -375, 550, 375)
ctx.fillRect(2750, -375, 1050, 375)
level.enter.draw();
level.exit.drawAndCheck();
button.draw();
if (button.isUp) {
button.query();
} else if (!isSpawnedBoss) {
isSpawnedBoss = true
isDoorsLocked = true
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 > 22) {
for (let i = 0, len = scale * 0.1 / 3; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
for (let i = 0, len = scale * 0.17 / 3; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
for (let i = 0, len = scale * 0.23 / 3; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
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.33) {
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
@@ -2766,7 +2778,11 @@ const level = {
}
}
spawn.secondaryBossChance(2200, -800)
} else if (!isFightOver && !(simulation.cycle % 120)) { //once a second look for any bosses
}
} 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) {
@@ -2778,8 +2794,9 @@ const level = {
isFightOver = true
doorIn.isClosing = false
doorOut.isClosing = false
powerUps.spawnBossPowerUp(2900, -100)
powerUps.spawn(3050, -200, "tech")
powerUps.spawnBossPowerUp(3600, -100)
powerUps.spawn(3650, -200, "tech")
// if (player.position.x < 2760 && player.position.x > 210) {}
}
}
};
@@ -2790,8 +2807,8 @@ const level = {
// }
doorIn.draw();
doorOut.draw();
ctx.fillStyle = "rgba(0,0,0,0.05)"
ctx.fillRect(-275, -1100, 500, 350);
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)
};
@@ -4082,7 +4099,7 @@ const level = {
spawn.randomMob(3600, 1725, 0.9);
spawn.randomMob(4100, 1225, 0.9);
spawn.randomMob(2825, 400, 0.9);
if (simulation.difficulty > 1) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss", "orbitalBoss", "grenadierBoss"]);
if (simulation.difficulty > 1) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "blinkBoss", "streamBoss", "historyBoss", "orbitalBoss", "grenadierBoss", "blockBoss", "revolutionBoss", "slashBoss"]);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
spawn.secondaryBossChance(7725, 2275)

View File

@@ -77,8 +77,8 @@ const m = {
setMovement() {
// m.Fx = 0.08 / mass * tech.squirrelFx
// m.FxAir = 0.4 / mass / mass
m.Fx = tech.baseFx * tech.squirrelFx * (tech.isFastTime ? 1.5 : 1) / player.mass //base player mass is 5
m.jumpForce = tech.baseJumpForce * tech.squirrelJump * (tech.isFastTime ? 1.13 : 1) / player.mass / player.mass //base player mass is 5
m.Fx = tech.baseFx * m.fieldFx * tech.squirrelFx * (tech.isFastTime ? 1.5 : 1) / player.mass //base player mass is 5
m.jumpForce = tech.baseJumpForce * m.fieldJump * tech.squirrelJump * (tech.isFastTime ? 1.13 : 1) / player.mass / player.mass //base player mass is 5
},
FxAir: 0.016, // 0.4/5/5 run Force in Air
yOff: 70,
@@ -893,6 +893,9 @@ const m = {
holdingTarget: null,
timeSkipLastCycle: 0,
// these values are set on reset by setHoldDefaults()
fieldFx: 1,
fieldJump: 1,
fieldFireRate: 1,
blockingRecoil: 4,
grabPowerUpRange2: 0,
isFieldActive: false,
@@ -951,6 +954,11 @@ const m = {
m.isCloak = false;
player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield
m.airSpeedLimit = 125
m.fieldFireRate = 1
b.setFireCD();
m.fieldFx = 1
m.fieldJump = 1
m.setMovement();
m.drop();
m.holdingMassScale = 0.5;
m.fieldArc = 0.2; //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
@@ -1045,10 +1053,6 @@ const m = {
m.holdingTarget = null;
}
},
// setMovement() {
// m.Fx = tech.baseFx * tech.squirrelFx * (tech.isFastTime ? 1.5 : 1);
// m.jumpForce = tech.baseJumpForce * tech.squirrelJump * (tech.isFastTime ? 1.13 : 1)
// },
definePlayerMass(mass = m.defaultMass) {
Matter.Body.setMass(player, mass);
//reduce air and ground move forces
@@ -2514,8 +2518,13 @@ const m = {
{
name: "time dilation",
// description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 1px;'>stop time</strong><br>while time is stopped you can <strong>move</strong> and <strong>fire</strong><br>and <strong>collisions</strong> do <strong>50%</strong> less <strong class='color-harm'>harm</strong>",
description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 2px;'>stop time</strong><br>for everything except you<br>generate <strong>18</strong> <strong class='color-f'>energy</strong>/second",
description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 2px;'>stop time</strong><br>move, jump, and fire <strong>25%</strong> faster<br>generate <strong>18</strong> <strong class='color-f'>energy</strong>/second",
set() {
m.fieldFireRate = 0.75
b.setFireCD();
m.fieldFx = 1.2
m.fieldJump = 1.09
m.setMovement();
if (tech.isRewindField) {
this.rewindCount = 0
m.grabPowerUpRange2 = 300000
@@ -2643,26 +2652,6 @@ const m = {
sleep(bullet);
simulation.cycle--; //pause all functions that depend on game cycle increasing
// if (tech.isTimeSkip) {
// m.immuneCycle = 0;
// m.drain += 0.0000025
// m.regenEnergy(); //immunity disables normal regen, so turn off immunity for just this function
// m.immuneCycle = m.cycle + 10;
// simulation.isTimeSkipping = true;
// m.cycle++;
// simulation.gravity();
// if (tech.isFireMoveLock && input.fire) {
// player.force.x = 0
// player.force.y = 0
// }
// Engine.update(engine, simulation.delta);
// m.move();
// simulation.checks();
// m.walk_cycle += m.flipLegs * m.Vx;
// b.fire();
// b.bulletDo();
// simulation.isTimeSkipping = false;
// }
} else { //holding, but field button is released
m.wakeCheck();
}
@@ -2678,80 +2667,6 @@ const m = {
m.drawFieldMeter()
}
}
// } else {
// m.fieldFire = true;
// m.isBodiesAsleep = false;
// m.isTimeStopped = false;
// m.drain = 0.005
// let isFieldInputDown = false;
// m.hold = function() {
// if (m.isHolding) {
// m.drawHold(m.holdingTarget);
// m.holding();
// m.throwBlock();
// isFieldInputDown = false
// } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
// if (!m.holdingTarget) isFieldInputDown = true;
// m.grabPowerUp();
// m.lookForPickUp();
// // if (m.energy > 0.05) { //deflecting
// // m.drawField();
// // m.pushMobsFacing();
// // }
// } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
// m.pickUp();
// } else {
// m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
// }
// if (isFieldInputDown && !input.field && !m.holdingTarget && !m.isHolding) {
// isFieldInputDown = false;
// m.isTimeStopped = true;
// }
// m.drawFieldMeter()
// if (m.energy < m.maxEnergy) { //extra energy regen
// m.regenEnergy();
// m.regenEnergy();
// }
// if (m.isTimeStopped) {
// if (m.energy > m.drain) {
// // if (player.speed > 0.01 || input.fire)
// m.energy -= m.drain;
// m.immuneCycle = m.cycle + 10; //immune to harm while time is stopped, this also disables regen
// simulation.cycle--; //pause all functions that depend on game cycle increasing
// m.isBodiesAsleep = true;
// ctx.globalCompositeOperation = "saturation" //draw field everywhere
// ctx.fillStyle = "#ccc";
// ctx.fillRect(-100000, -100000, 200000, 200000)
// ctx.globalCompositeOperation = "source-over"
// function sleep(who) {
// for (let i = 0, len = who.length; i < len; ++i) {
// if (!who[i].isSleeping) {
// who[i].storeVelocity = who[i].velocity
// who[i].storeAngularVelocity = who[i].angularVelocity
// }
// Matter.Sleeping.set(who[i], true)
// }
// }
// sleep(mob);
// sleep(body);
// sleep(bullet);
// } else { //restart time
// m.fieldCDcycle = m.cycle + 60;
// m.energy = 0;
// m.isTimeStopped = false
// m.wakeCheck();
// }
// if (simulation.isChoosing) {
// // m.fieldCDcycle = m.cycle + 60;
// m.isTimeStopped = false
// m.wakeCheck();
// }
// }
// }
// }
},
effect() {
this.set();

View File

@@ -280,13 +280,11 @@ const powerUps = {
if (!simulation.paused) {
if (tech.isNoDraftPause) {
const cycle = () => {
m.fireCDcycle = m.cycle + 5; //fire cooldown
if (simulation.isChoosing && m.alive) requestAnimationFrame(cycle)
}
requestAnimationFrame(cycle);
// const cycle = () => {
// m.fireCDcycle = m.cycle + 1; //fire cooldown
// if (simulation.isChoosing && m.alive) requestAnimationFrame(cycle)
// }
// requestAnimationFrame(cycle);
document.getElementById("choose-grid").style.opacity = "0.8"
} else {
@@ -1081,7 +1079,7 @@ const powerUps = {
}
},
pauseEjectTech(index) {
if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing) {
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)) {
tech.removeTech(index)
powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);

View File

@@ -89,18 +89,35 @@ const simulation = {
m.airControl()
}
m.move();
level.custom();
simulation.checks();
mobs.loop();
// m.draw();
m.walk_cycle += m.flipLegs * m.Vx;
m.hold();
level.customTopLayer();
b.fire();
b.bulletRemove();
b.bulletDo();
}
simulation.isTimeSkipping = false;
},
timePlayerSkip(cycles = 60) {
simulation.isTimeSkipping = true;
for (let i = 0; i < cycles; i++) {
simulation.cycle++;
simulation.gravity();
Engine.update(engine, simulation.delta);
// level.custom();
// level.customTopLayer();
if (!m.isBodiesAsleep) {
simulation.checks();
mobs.loop();
}
b.bulletRemove();
if (!m.isBodiesAsleep) b.bulletDo();
}
simulation.isTimeSkipping = false;
},
mouse: {
x: canvas.width / 2,
y: canvas.height / 2

View File

@@ -1,6 +1,6 @@
//main object for spawning things in a level
const spawn = {
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture", "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
randomBossList: ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
"powerUpBoss", "powerUpBossBaby", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
@@ -1031,7 +1031,7 @@ const spawn = {
me.isSpawnBoss = true;
me.spawnID = spawnID
me.accelMag = 0.00018 * simulation.accelScale;
me.accelMag = 0.00022 * simulation.accelScale;
me.memory = Infinity;
me.showHealthBar = false;
me.isVerticesChange = true
@@ -1039,7 +1039,7 @@ const spawn = {
me.seePlayerFreq = Math.floor(14 + 7 * Math.random())
me.seeAtDistance2 = 200000 //1400000;
me.stroke = "transparent"
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body //| cat.map //"rgba(255,60,0,0.3)"
me.collisionFilter.mask = cat.player | cat.bullet | cat.body | cat.map //"rgba(255,60,0,0.3)"
// Matter.Body.setDensity(me, 0.0014) // normal density is 0.001
Matter.Body.setAngularVelocity(me, 0.12 * (Math.random() - 0.5))
// spawn.shield(me, x, y, 1);
@@ -1047,7 +1047,7 @@ const spawn = {
me.onHit = function() { //run this function on hitting player
this.explode();
};
me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
me.damageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
me.doAwake = function() {
this.alwaysSeePlayer();
this.checkStatus();
@@ -1741,6 +1741,68 @@ const spawn = {
}
}
},
// timeBoss(x, y, radius = 25) {
// mobs.spawn(x, y, 12, radius, "#000");
// let me = mob[mob.length - 1];
// me.isBoss = true;
// me.stroke = "transparent"; //used for drawSneaker
// me.eventHorizon = 1100; //required for black hole
// me.eventHorizonGoal = 1100; //required for black hole
// me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon
// me.accelMag = 0.00006 * simulation.accelScale;
// // me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
// // me.frictionAir = 0.005;
// me.memory = Infinity;
// Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
// me.onDeath = function() {
// powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// };
// me.damageReduction = 0.23 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
// me.do = function() {
// //keep it slow, to stop issues from explosion knock backs
// if (!(simulation.cycle % this.seePlayerFreq)) {
// if (this.distanceToPlayer2() < this.seeAtDistance2) { //&& !m.isCloak ignore cloak for black holes
// this.locatePlayer();
// if (!this.seePlayer.yes) this.seePlayer.yes = true;
// } else if (this.seePlayer.recall) {
// this.lostPlayer();
// }
// }
// this.checkStatus();
// if (this.seePlayer.recall) {
// //accelerate towards the player
// const forceMag = this.accelMag * this.mass;
// const dx = this.seePlayer.position.x - this.position.x
// const dy = this.seePlayer.position.y - this.position.y
// const mag = Math.sqrt(dx * dx + dy * dy)
// this.force.x += forceMag * dx / mag;
// this.force.y += forceMag * dy / mag;
// //eventHorizon waves in and out
// const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008))
// // zoom camera in and out with the event horizon
// //draw darkness
// if (!simulation.isTimeSkipping) {
// ctx.beginPath();
// ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
// ctx.fillStyle = "rgba(0,0,0,0.05)";
// ctx.fill();
// //when player is inside event horizon
// if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
// // if (!(simulation.cycle % 10)) simulation.timePlayerSkip(5)
// // if (!(simulation.cycle % 2)) simulation.timePlayerSkip(1)
// simulation.timePlayerSkip(2)
// // if (m.immuneCycle < m.cycle) {
// // if (m.energy > 0) m.energy -= 0.004
// // if (m.energy < 0.1) m.damage(0.00017 * simulation.dmgScale);
// // }
// }
// }
// }
// }
// },
suckerBoss(x, y, radius = 25) {
mobs.spawn(x, y, 12, radius, "#000");
let me = mob[mob.length - 1];
@@ -1808,7 +1870,6 @@ const spawn = {
y: this.velocity.y + velocity.y
});
}
//accelerate towards the player
const forceMag = this.accelMag * this.mass;
const dx = this.seePlayer.position.x - this.position.x
@@ -1816,11 +1877,8 @@ const spawn = {
const mag = Math.sqrt(dx * dx + dy * dy)
this.force.x += forceMag * dx / mag;
this.force.y += forceMag * dy / mag;
//eventHorizon waves in and out
const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008))
// zoom camera in and out with the event horizon
const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)) // zoom camera in and out with the event horizon
//draw darkness
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI);
@@ -2229,88 +2287,88 @@ const spawn = {
}
spawn.allowShields = true;
},
// timeSkipBoss(x, y, radius = 55) {
// mobs.spawn(x, y, 6, radius, '#000');
// let me = mob[mob.length - 1];
// me.isBoss = true;
// // me.stroke = "transparent"; //used for drawSneaker
// me.timeSkipLastCycle = 0
// me.eventHorizon = 1800; //required for black hole
// me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
// me.accelMag = 0.0004 * simulation.accelScale;
// // me.frictionAir = 0.005;
// // 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.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
// spawn.shield(me, x, y, 1);
timeSkipBoss(x, y, radius = 55) {
mobs.spawn(x, y, 6, radius, '#000');
let me = mob[mob.length - 1];
me.isBoss = true;
// me.stroke = "transparent"; //used for drawSneaker
me.timeSkipLastCycle = 0
me.eventHorizon = 1800; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
me.accelMag = 0.0004 * simulation.accelScale;
// me.frictionAir = 0.005;
// 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.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
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)
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
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
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.clip();
// 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.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI);
// ctx.fillStyle = "#000";
// ctx.fill();
// ctx.globalCompositeOperation = "source-over";
// ctx.beginPath();
// ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// ctx.clip();
// ctx.strokeStyle = "#000";
// ctx.stroke();
// // ctx.beginPath();
// // ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI);
// // ctx.fillStyle = "#000";
// // ctx.fill();
// // ctx.strokeStyle = "#000";
// // ctx.stroke();
// // 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();
// }
// }
// }
// },
// 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)) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,190)");
let me = mob[mob.length - 1];
@@ -3456,33 +3514,6 @@ const spawn = {
}
}
}
//invulnerable every other revolution
// me.isInvulnerable = false
// me.invulnerable = function() {
// //draw trigger angle
// if (this.laserAngle % (4 * Math.PI) > 2 * Math.PI) {
// if (!this.isInvulnerable) {
// this.isInvulnerable = true
// if (this.damageReduction) this.startingDamageReduction = this.damageReduction
// this.damageReduction = 0
// }
// } else if (this.isInvulnerable) {
// this.isInvulnerable = false
// this.damageReduction = this.startingDamageReduction
// }
// 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();
// }
// }
me.do = function() {
this.invulnerable();
this.checkStatus();
@@ -3893,6 +3924,93 @@ const spawn = {
// }
};
},
timeBoss(x, y, radius = 50, isSpawnBossPowerUp = true) {
mobs.spawn(x, y, 0, radius, `hsl(0, 100%, 50%)`) // "rgb(201,202,225)");
let me = mob[mob.length - 1];
Matter.Body.rotate(me, 2 * Math.PI * Math.random());
me.isBoss = true;
Matter.Body.setDensity(me, 0.001); //normal is 0.001
me.inertia = Infinity;
me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false
me.frictionAir = 0.01
me.restitution = 1
me.friction = 0
me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob
Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
me.seePlayer.recall = 1;
spawn.spawnOrbitals(me, radius + 15, 1)
// me.skipRate = 1 + Math.floor(simulation.difficulty*0.02)
// spawn.shield(me, x, y, 1);
me.onDamage = function() {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
this.invulnerableCount = 360 + simulation.difficulty * 4 //how long does invulnerable time last
this.isInvulnerable = true
this.damageReduction = 0
// requestAnimationFrame(() => { simulation.timePlayerSkip(300) }); //wrapping in animation frame prevents errors, probably
}
};
me.onDeath = function() {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
requestAnimationFrame(() => { simulation.timePlayerSkip(30) }); //wrapping in animation frame prevents errors, probably
};
me.cycle = Math.floor(360 * Math.random())
me.nextHealthThreshold = 0.75
me.invulnerableCount = 0
// console.log(me.mass) //100
me.do = function() {
this.cycle++
this.fill = `hsl(${this.cycle*0.5}, 100%, 80%)`;
// this.fill = `hsl(${270 + 50*Math.sin(this.cycle*0.02)}, 100%, 60%)`;
this.seePlayer.recall = 1
//maintain speed //faster in the vertical to help avoid repeating patterns
if (this.speed < 0.01) {
const unit = Vector.sub(player.position, this.position)
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1));
} 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.x) < 6.5) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.02, y: this.velocity.y });
}
if (this.isInvulnerable) {
this.invulnerableCount--
if (this.invulnerableCount < 0) {
this.isInvulnerable = false
this.damageReduction = this.startingDamageReduction
}
//time dilation
if (!simulation.isTimeSkipping) {
requestAnimationFrame(() => { simulation.timePlayerSkip(1) }); //wrapping in animation frame prevents errors, probably
// if (!(simulation.cycle % 10))
//draw invulnerable
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 = 15 + 6 * Math.random();
ctx.strokeStyle = `rgba(255,255,255,${0.5+0.2*Math.random()})`;
ctx.stroke();
}
}
this.checkStatus();
//horizontal attraction
// const xMag = 0.0005
// if (player.position.x > this.position.x + 200) {
// this.force.x += xMag * this.mass;
// } else if (player.position.x < this.position.x - 200) {
// this.force.x -= xMag * this.mass;
// }
};
},
bounceBullet(x, y, velocity = { x: 0, y: 0 }, radius = 11, sides = 6) {
//bullets
mobs.spawn(x, y, sides, radius, "rgb(255,0,155)");
@@ -5668,7 +5786,7 @@ const spawn = {
x: Math.cos(time),
y: Math.sin(time)
}
Matter.Body.setPosition(this, Vector.add(who.position, Vector.mult(orbit, radius))) //bullets move with player
Matter.Body.setPosition(this, Vector.add(Vector.add(who.position, who.velocity), Vector.mult(orbit, radius))) //bullets move with player
//damage player
if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles
@@ -5685,26 +5803,24 @@ const spawn = {
}
};
},
orbitalBoss(x, y, radius = 88) {
orbitalBoss(x, y, radius = 70) {
const nodeBalance = Math.random()
const nodes = Math.min(15, Math.floor(2 + 4 * nodeBalance + 0.75 * Math.sqrt(simulation.difficulty)))
mobs.spawn(x, y, nodes, radius, "rgb(255,0,150)");
let me = mob[mob.length - 1];
me.isBoss = true;
Matter.Body.setDensity(me, 0.0017 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.stroke = "transparent"; //used for drawGhost
me.seeAtDistance2 = 2000000;
me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
me.memory = Infinity;
me.frictionAir = 0.04;
me.accelMag = 0.0003 * simulation.accelScale
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
me.accelMag = 0.0007 * simulation.accelScale
spawn.shield(me, x, y, 1);
const rangeInnerVsOuter = Math.random()
let speed = (0.009 + 0.0011 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
let range = radius + 400 + 200 * rangeInnerVsOuter + nodes * 7
let range = radius + 300 + 200 * rangeInnerVsOuter + nodes * 7
for (let i = 0; i < nodes; i++) spawn.orbital(me, range, i / nodes * 2 * Math.PI, speed)
const orbitalIndexes = [] //find indexes for all the current nodes
for (let i = 0; i < nodes; i++) orbitalIndexes.push(mob.length - 1 - i)
@@ -5718,10 +5834,9 @@ const spawn = {
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0.18 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.do = function() {
// this.armor();
this.seePlayerCheckByDistance();
this.seePlayerByHistory();
this.checkStatus();
this.attraction();
};

View File

@@ -602,9 +602,9 @@ const tech = {
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isAmmoFromHealth && !tech.isEnergyNoAmmo
return !tech.isAmmoFromHealth
},
requires: "not catabolism, ideal gas law",
requires: "not catabolism",
effect() {
tech.isEnergyNoAmmo = true;
},
@@ -4661,9 +4661,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.implosion === -1 && tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.isBoomBotUpgrade || tech.isTokamak)
return tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.isBoomBotUpgrade || tech.isTokamak)
},
requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation, implosion",
requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation",
effect: () => {
tech.isExplodeRadio = true; //iridium-192
},
@@ -4976,9 +4976,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && tech.implosion === -1
return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode
},
requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, implosion",
requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics",
effect() {
tech.isNeutronBomb = true;
b.setGrenadeMode()
@@ -7106,7 +7106,7 @@ const tech = {
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "time dilation" && !m.isShipMode && !tech.isRewindAvoidDeath && !tech.isEnergyHealth && !tech.isTimeSkip
},
requires: "time dilation, not CPT symmetry, mass-energy, timelike",
requires: "time dilation, not CPT symmetry, mass-energy",
effect() {
tech.isRewindField = true;
m.fieldUpgrades[m.fieldMode].set()
@@ -7117,25 +7117,6 @@ const tech = {
if (this.count) m.fieldUpgrades[m.fieldMode].set()
}
},
// {
// name: "timelike",
// description: "<strong>time dilation</strong> doubles your relative time <strong>rate</strong><br>and makes you immune to <strong class='color-harm'>harm</strong>",
// isFieldTech: true,
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return m.fieldUpgrades[m.fieldMode].name === "time dilation" && !m.isShipMode && !tech.isRewindField
// },
// requires: "time dilation, not retrocausality",
// effect() {
// tech.isTimeSkip = true;
// },
// remove() {
// tech.isTimeSkip = false;
// }
// },
{
name: "Lorentz transformation",
description: `use ${powerUps.orb.research(3)}to increase your time rate<br><strong>move</strong>, <strong>jump</strong>, and <strong>shoot</strong> <strong>50%</strong> faster`,
@@ -7887,6 +7868,33 @@ const tech = {
},
remove() {}
},
{
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>",
maxCount: 1,
count: 0,
frequency: 0,
isJunk: true,
isNonRefundable: true,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
function loop() {
if (!simulation.paused && m.alive) {
if (!(simulation.cycle % 720)) {
requestAnimationFrame(() => { simulation.timePlayerSkip(60) }); //wrapping in animation frame prevents errors, probably
}
}
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
},
remove() {}
},
{
name: "discount",
description: "get 3 random <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> for the price of 1!",

128
todo.txt
View File

@@ -1,16 +1,69 @@
******************************************************** NEXT PATCH **************************************************
ideal gas law - lose all your current foam ammo; foam gun gets 1200% more ammo from ammo power ups
pressure vessel - has 25% more charges produced as you hold
new reactor boss: timeBoss - after taking some damage it speeds up the passage of time
reactor level has big doors
slashBoss is a bit slower and has a bit longer between slashes
reactor SprayBoss: slower to fire, slower to move, smaller bullets, fewer in number
just a tiny nerf though
bug fixes
nonrefundable tech show up in the pause menu
time dilation field - move, jump, and fire 25% faster
JUNK tech: closed timelike curve - spawn 5 field power ups, but every 12 seconds teleport a second into your future
******************************************************** TODO ********************************************************
if a mob dies in skiptime it doesn't register?
is this only for the ondeath event?
so far, but needs more tests
is this only for timeskip > 1
yes I think
make MEE work with harm reduction
how to nerf MEE
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)
skip every other cycle inside black holes?
maybe run simulation.timeSkip(60) in a map
in labs?
reactor boss
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
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
The new mob should be as such, a "real" exploding mob:
Deals regular damage on impact, but breaks apart on touch into several red dots (like the ones thrown out by the going through walls boss) and a chance for also throwing a bomb or two (increases with difficulty)
If the mob is close to the player or heading into the player fast it will shatter as well (and the projectiles will inherit its speed)
By a formula such as
ShouldShatter(distToPlayer, speed) = distToPlayer * speed > threshold
Optionally (and a part I can do as I'm good at it and it doesn't revolve around a lot of functional code which you don't like other people doing):
Color changing based on the mob explosion status
Regular state: red
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
make laser gain damage and energy drain from fire delay tech
wording? put it in the gun description
reactor: add horizontal flip mode
pause time like invariant for other things...
throwing blocks
charging railgun
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
how to make the description work
change description based on your current field?
@@ -24,9 +77,6 @@ tech expansion: should also make other fields do things
reduces the cloaking vision effect?
needs more benefit?
nonrefundable tech don't display, this is confusing
maybe they can show up but greyed out or something
guntech fire a bullet that fires nail fragments after 1s in the same direction as the original bullet
like overwatch roadhog
@@ -146,72 +196,14 @@ setting to remove UI, except health bar
except active gun? to see ammo
checkbox in pause and in settings
pause time like invariant for other things...
throwing blocks
charging railgun
charging anything?
bug - url sharing still broken sometimes
maybe? timing QTE for charging effects, if you fire right before the charge gets full it's better
+damage for each different bot type you have
disables bot upgrades?
tech: doing damage to mobs refunds up to 50% of damage taken in last 10 seconds
use history[] to manage this?
make a seed/hash system that controls only the tech/guns/fields shown
URL sharing could include a seed
seed controls:
seeded random at start - random level boss, mob types list, level order, horizontal flip
seeded random during run - tech, gun, field choices
not seeded random - mob spawns, mob size, minor level differences, custom level boss choices, ammo rewards, tech effect randomness
better to only seed things at the start of the run so it doesn't mess with power up choices
make option for a daily seed: seed = day+year
give 1 extra tech for doing the daily seeded run
make the option for the daily run, a secret exit in the intro level?
tech upgrade to anthropic principle to make it trigger at 50% life and 0% once per map
tech: spontaneous collapse - very low chance of something to occur
JUNK tech
https://bindingofisaacrebirth.fandom.com/wiki/Damocles
bug? cloaking field doesn't show energy over max
run more profiles of n-gon to fix performance issues
reactor
life-like cellular automata boss
https://scratch.mit.edu/projects/77724260/
night/day?
boss on far right produces more "on" cells
tailBoss
story the last 5 seconds of position, draw damage circles over those positions, like a tail
limit mantis boss to only reactor?
laserBoss?
swoopBoss: hides in top center
take a lap around the map that you have to dodge
spawn mobs
fire sniper bullets?
remove center map element?
add some blocks to the reactor level
add ammo?
boss speeds up as time goes on?
slow bullet speed?
foam hits all the bullets and makes this fight easy
give map some background graphics
it's a little short
add alternate boss
add a boss that spawns after the first one dies
balance
boss damage reduction
bullet size
bullet spawn number
bounce speed
add horizontal flip mode
bug: possibly clearing away all bullets causes a problem
bullet.js 255 (.do() is missing)
I died and quantum immortality triggered (I had needles and ice-IX)