finalBoss boulders

finalBoss has a new phase: "boulders"
  each phase has been rebalanced
  boss health is a bit higher
  mob mines are white now

pilot wave gets +1 choice for gun,field,tech

bug fixes:
This commit is contained in:
landgreen
2022-10-09 20:00:28 -07:00
parent c162f1074e
commit 3c860797b3
8 changed files with 179 additions and 90 deletions

View File

@@ -97,10 +97,10 @@ const b = {
simulation.makeTextLog(`${b.guns[b.activeGun].name}.<span class='color-g'>ammo</span><span class='color-symbol'>:</span> 0`); simulation.makeTextLog(`${b.guns[b.activeGun].name}.<span class='color-g'>ammo</span><span class='color-symbol'>:</span> 0`);
m.fireCDcycle = m.cycle + 30; //fire cooldown m.fireCDcycle = m.cycle + 30; //fire cooldown
if (tech.isAmmoFromHealth) { if (tech.isAmmoFromHealth) {
const amount = 0.01 const amount = 0.02
if (tech.isEnergyHealth) { if (tech.isEnergyHealth) {
if (m.maxEnergy > amount) { if (m.maxEnergy > amount * 2) {
tech.healMaxEnergyBonus -= amount tech.healMaxEnergyBonus -= amount * 2
m.setMaxEnergy(); m.setMaxEnergy();
for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + 50 * (Math.random() - 0.5), m.pos.y + 50 * (Math.random() - 0.5), "ammo"); for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + 50 * (Math.random() - 0.5), m.pos.y + 50 * (Math.random() - 0.5), "ammo");
} }

View File

@@ -18,18 +18,18 @@ const level = {
// simulation.enableConstructMode() //used to build maps in testing mode // simulation.enableConstructMode() //used to build maps in testing mode
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// tech.giveTech("performance") // tech.giveTech("performance")
// level.difficultyIncrease(6 * 4) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(13 * 4) //30 is near max on hard //60 is near max on why
// m.maxHealth = m.health = 100 // m.maxHealth = m.health = 100
// tech.isRerollDamage = true // tech.isRerollDamage = true
// powerUps.research.changeRerolls(50) // powerUps.research.changeRerolls(500)
// m.immuneCycle = Infinity //you can't take damage // m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100 // tech.tech[297].frequency = 100
// m.couplingChange(5) // m.couplingChange(5)
// m.setField("pilot wave") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave // m.setField("standing wave") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave
// simulation.molecularMode = 2 // simulation.molecularMode = 2
// m.damage(0.1); // m.damage(0.1);
// b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.guns[0].ammo = 1000000 // b.guns[0].ammo = 10000
// for (let i = 0; i < 1; ++i) tech.giveTech("needle gun") // for (let i = 0; i < 1; ++i) tech.giveTech("needle gun")
// tech.giveTech("pressure vessel") // tech.giveTech("pressure vessel")
@@ -47,7 +47,7 @@ const level = {
// tech.addJunkTechToPool(0.5) // tech.addJunkTechToPool(0.5)
// tech.tech[322].frequency = 100 // tech.tech[322].frequency = 100
// spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 })
// for (let i = 0; i < 36; ++i) tech.giveTech() // for (let i = 0; i < 40; ++i) tech.giveTech()
// for (let i = 0; i < 13; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); // for (let i = 0; i < 13; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research");
if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************
// for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); // for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
@@ -58,13 +58,13 @@ const level = {
// lore.techCount = 2 // lore.techCount = 2
// simulation.isCheating = false //true; // simulation.isCheating = false //true;
// level.levelsCleared = 10 // level.levelsCleared = 10
// mobs.mobDeaths = 200
// localSettings.loreCount = 7 //this sets what conversation is heard // localSettings.loreCount = 7 //this sets what conversation is heard
// if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
// level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation // level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation
// level.null() // level.null()
// localSettings.isHuman = true // localSettings.isHuman = true
// tech.isNoDraftPause = false //disable pause // tech.isNoDraftPause = false //disable pause
// mobs.mobDeaths = 200
// for (let i = 0; i < 13; i++) level.nextLevel(); //jump to final boss // for (let i = 0; i < 13; i++) level.nextLevel(); //jump to final boss
// lore.unlockTesting(); // lore.unlockTesting();
@@ -3139,7 +3139,7 @@ const level = {
slime.levelRise(0.1) slime.levelRise(0.1)
ctx.fillStyle = "rgba(0,255,255,0.1)" ctx.fillStyle = "rgba(0,255,255,0.1)"
ctx.fillRect(5400, -550, 300, 350) ctx.fillRect(5385, -550, 300, 250)
}; };
level.setPosToSpawn(0, -250); //normal spawn level.setPosToSpawn(0, -250); //normal spawn
@@ -3152,18 +3152,7 @@ const level = {
simulation.zoomTransition(level.defaultZoom) simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#ddd"; document.body.style.backgroundColor = "#ddd";
powerUps.spawn(1675, -50, "ammo"); for (let i = 0; i < 16; i++) powerUps.spawn(4600 + 40 * i, -30, "ammo");
powerUps.spawn(3350, -75, "ammo");
powerUps.spawn(3925, -50, "ammo");
powerUps.spawn(4250, -75, "ammo");
powerUps.spawn(4550, -75, "ammo");
powerUps.spawn(5025, -50, "ammo");
powerUps.spawn(4725, -50, "ammo");
powerUps.spawn(4975, -350, "ammo");
powerUps.spawn(5125, -350, "ammo");
powerUps.spawn(5075, -425, "ammo");
powerUps.spawn(5050, -400, "ammo");
powerUps.spawn(5075, -425, "ammo");
spawn.mapRect(-1950, 0, 8200, 1800); //ground spawn.mapRect(-1950, 0, 8200, 1800); //ground
spawn.mapRect(-1950, -1500, 1800, 1900); //left wall spawn.mapRect(-1950, -1500, 1800, 1900); //left wall
@@ -3181,7 +3170,7 @@ const level = {
spawn.mapRect(5400, -300, 400, 400); //right wall spawn.mapRect(5400, -300, 400, 400); //right wall
spawn.mapRect(5700, -3300, 1800, 5100); //right wall spawn.mapRect(5700, -3300, 1800, 5100); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.mapRect(5425, -650, 375, 450); //blocking exit spawn.mapRect(5403, -650, 400, 450); //blocking exit
// spawn.secondaryBossChance(4800, -500) //no bonus bosses on final level // spawn.secondaryBossChance(4800, -500) //no bonus bosses on final level
if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run
@@ -3203,7 +3192,7 @@ const level = {
slime.query(); slime.query();
slime.levelRise(0.1) slime.levelRise(0.1)
ctx.fillStyle = "rgba(0,255,255,0.1)" ctx.fillStyle = "rgba(0,255,255,0.1)"
ctx.fillRect(-5400 - 300, -550, 300, 350) ctx.fillRect(-5385 - 300, -550, 300, 250)
}; };
} }
if (mobs.mobDeaths < level.levelsCleared && localSettings.loreCount > 5 && !simulation.isCheating) { if (mobs.mobDeaths < level.levelsCleared && localSettings.loreCount > 5 && !simulation.isCheating) {

View File

@@ -1228,7 +1228,7 @@ const mobs = {
// }); //wrapping in animation frame prevents errors, probably // }); //wrapping in animation frame prevents errors, probably
// } // }
} }
if (tech.isEnergyLoss) m.energy *= 0.75; if (tech.isEnergyLoss) m.energy *= 0.8;
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()
mobs.mobDeaths++ mobs.mobDeaths++

View File

@@ -2715,7 +2715,7 @@ const m = {
//draw field everywhere //draw field everywhere
ctx.globalCompositeOperation = "saturation" ctx.globalCompositeOperation = "saturation"
ctx.fillStyle = "#ccc"; ctx.fillStyle = "#ccc";
ctx.fillRect(-100000, -100000, 200000, 200000) ctx.fillRect(-50000, -50000, 100000, 100000)
ctx.globalCompositeOperation = "source-over" ctx.globalCompositeOperation = "source-over"
//stop time //stop time
m.isBodiesAsleep = true; m.isBodiesAsleep = true;
@@ -3173,7 +3173,8 @@ const m = {
name: "pilot wave", name: "pilot wave",
//<br><strong class='color-block'>blocks</strong> can't <strong>collide</strong> with <strong>intangible</strong> mobs //<br><strong class='color-block'>blocks</strong> can't <strong>collide</strong> with <strong>intangible</strong> mobs
//field <strong>radius</strong> decreases out of <strong>line of sight</strong> //field <strong>radius</strong> decreases out of <strong>line of sight</strong>
description: "use <strong class='color-f'>energy</strong> to guide <strong class='color-block'>blocks</strong><br><strong>unlock</strong> <strong class='color-m'>tech</strong> from other <strong class='color-f'>fields</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<strong>unlock</strong> <strong class='color-m'>tech</strong> from other <strong class='color-f'>fields</strong>
description: "use <strong class='color-f'>energy</strong> to guide <strong class='color-block'>blocks</strong><br><strong class='color-m'>tech</strong>, <strong class='color-f'>fields</strong>, and <strong class='color-g'>guns</strong> have <strong>+1</strong> <strong>choice</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second",
effect: () => { effect: () => {
m.fieldMeterColor = "#333" m.fieldMeterColor = "#333"
m.eyeFillColor = m.fieldMeterColor m.eyeFillColor = m.fieldMeterColor

View File

@@ -650,7 +650,7 @@ const powerUps = {
for (let i = 0; i < b.guns.length; i++) { for (let i = 0; i < b.guns.length; i++) {
if (!b.guns[i].have) options.push(i); if (!b.guns[i].have) options.push(i);
} }
let totalChoices = Math.min(options.length, tech.isDeterminism ? 1 : 2 + tech.extraChoices) let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2) + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave"))
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
function removeOption(index) { function removeOption(index) {
for (let i = 0; i < options.length; i++) { for (let i = 0; i < options.length; i++) {
@@ -787,7 +787,7 @@ const powerUps = {
for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter
if (i !== m.fieldMode) options.push(i); if (i !== m.fieldMode) options.push(i);
} }
let totalChoices = Math.min(options.length, tech.isDeterminism ? 1 : 2 + tech.extraChoices) let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2) + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave"))
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
function removeOption(index) { function removeOption(index) {
@@ -946,7 +946,7 @@ const powerUps = {
} }
//set total choices //set total choices
let totalChoices = tech.isDeterminism ? 1 : 3 + tech.extraChoices let totalChoices = (tech.isDeterminism ? 1 : 3) + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave")
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
if (optionLengthNoDuplicates < totalChoices + 1) { //if not enough options for all the choices if (optionLengthNoDuplicates < totalChoices + 1) { //if not enough options for all the choices
// console.log('if not enough options for all the choices') // console.log('if not enough options for all the choices')

View File

@@ -367,7 +367,7 @@ const spawn = {
me.cycle = 1; me.cycle = 1;
Matter.Body.setDensity(me, 0.2); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.2); //extra dense //normal is 0.001 //makes effective life much larger
me.damageReduction = 0.16 me.damageReduction = 0.12
me.startingDamageReduction = me.damageReduction me.startingDamageReduction = me.damageReduction
me.nextHealthThreshold = 0.999 me.nextHealthThreshold = 0.999
me.invulnerableCount = 0 me.invulnerableCount = 0
@@ -380,7 +380,7 @@ const spawn = {
if (this.health === 1) me.cycle = 1; //reset fight if (this.health === 1) me.cycle = 1; //reset fight
this.health = this.nextHealthThreshold - 0.01 this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25 this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
this.invulnerableCount = 200 + 10 * simulation.difficultyMode //how long does invulnerable time last this.invulnerableCount = 220 + 10 * simulation.difficultyMode //how long does invulnerable time last
this.isInvulnerable = true this.isInvulnerable = true
this.damageReduction = 0 this.damageReduction = 0
} }
@@ -408,15 +408,23 @@ const spawn = {
} }
} }
me.damageReductionDecay = function() { //slowly make the boss take more damage over time //damageReduction resets with each invulnerability phase me.damageReductionDecay = function() { //slowly make the boss take more damage over time //damageReduction resets with each invulnerability phase
//only decay once a second //only decay if the player has done damage in the last 4 seconds if (!(me.cycle % 60) && this.lastDamageCycle + 240 > this.cycle) this.damageReduction *= 1.015 //only decay once a second //only decay if the player has done damage in the last 4 seconds
if (!(me.cycle % 60) && this.lastDamageCycle + 240 > this.cycle) this.damageReduction *= 1.02
// console.log(this.damageReduction)
} }
me.maxMobs = 400 me.maxMobs = 400
me.mode = [{ me.mode = [{
name: "boulders",
spawnRate: 120 - 6 * simulation.difficultyMode,
do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.boulder(me.position.x, me.position.y + 250)
}
},
enter() {},
exit() {},
}, {
name: "mobs", name: "mobs",
whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)], whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
spawnRate: 300 - 12 * simulation.difficultyMode, spawnRate: 240 - 20 * simulation.difficultyMode,
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.torque += 0.000015 * me.inertia; //spin me.torque += 0.000015 * me.inertia; //spin
@@ -435,13 +443,14 @@ const spawn = {
}, },
{ {
name: "hoppers", name: "hoppers",
spawnRate: 400 - 14 * simulation.difficultyMode, spawnRate: 420 - 16 * simulation.difficultyMode,
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
me.torque += 0.00002 * me.inertia; //spin me.torque += 0.00002 * me.inertia; //spin
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
const vertex = me.vertices[i] const vertex = me.vertices[i]
spawn.hopBullet(vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5)); spawn.hopBullet(vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5), 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
Matter.Body.setDensity(mob[mob.length - 1], 0.002); //normal is 0.001
const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(me.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(me.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex
Matter.Body.setVelocity(mob[mob.length - 1], { Matter.Body.setVelocity(mob[mob.length - 1], {
x: me.velocity.x + velocity.x, x: me.velocity.x + velocity.x,
@@ -455,14 +464,14 @@ const spawn = {
}, },
{ {
name: "seekers", name: "seekers",
spawnRate: 60 - 2 * simulation.difficultyMode, spawnRate: 60 - 3 * simulation.difficultyMode,
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
const index = Math.floor((me.cycle % 360) / 60) const index = Math.floor((me.cycle % 360) / 60)
spawn.seeker(me.vertices[index].x, me.vertices[index].y, 20 * (0.5 + Math.random()), 9); //give the bullet a rotational velocity as if they were attached to a vertex spawn.seeker(me.vertices[index].x, me.vertices[index].y, 18 * (0.5 + Math.random())); //seeker(x, y, radius = 8, sides = 6)
const who = mob[mob.length - 1] const who = mob[mob.length - 1]
Matter.Body.setDensity(who, 0.00003); //normal is 0.001 Matter.Body.setDensity(who, 0.00003); //normal is 0.001
who.timeLeft = 720 + 15 * simulation.difficulty //* (0.8 + 0.4 * Math.random()); who.timeLeft = 720 + 30 * simulation.difficulty //* (0.8 + 0.4 * Math.random());
who.accelMag = 0.0004 * simulation.accelScale; //* (0.8 + 0.4 * Math.random()) who.accelMag = 0.0004 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random()); who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
} }
@@ -473,7 +482,7 @@ const spawn = {
{ {
name: "mines", name: "mines",
bombCycle: 0, bombCycle: 0,
bombInterval: 36 - 2 * simulation.difficultyMode, bombInterval: 34 - 2 * simulation.difficultyMode,
do() { do() {
const yOff = 120 const yOff = 120
this.bombCycle++ this.bombCycle++
@@ -535,7 +544,7 @@ const spawn = {
}, },
{ {
name: "orbiters", name: "orbiters",
spawnRate: 26 - 2 * simulation.difficultyMode, spawnRate: 30 - 2 * simulation.difficultyMode,
do() { do() {
if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
const speed = (0.01 + 0.0005 * simulation.difficultyMode) * ((Math.random() < 0.5) ? 0.85 : -1.15) const speed = (0.01 + 0.0005 * simulation.difficultyMode) * ((Math.random() < 0.5) ? 0.85 : -1.15)
@@ -548,20 +557,20 @@ const spawn = {
}, },
{ {
name: "laser", name: "laser",
spinForce: 0.00000015, spinForce: 0.00000012, // * (Math.random() < 0.5 ? -1 : 1),
fadeCycle: 0, //fades in over 4 seconds fadeCycle: 0, //fades in over 4 seconds
do() { do() {
this.fadeCycle++ this.fadeCycle++
if (this.fadeCycle > 0) { if (this.fadeCycle > 0) {
me.torque += this.spinForce * me.inertia; //spin //0.00000015 me.torque += this.spinForce * me.inertia; //spin //0.00000015
if (this.fadeCycle > 360) this.fadeCycle = -120 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
ctx.strokeStyle = "#50f"; ctx.strokeStyle = "#50f";
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
ctx.lineWidth = 1.5; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.beginPath();
if (this.fadeCycle < 120) { //damage scales up over 2 seconds to give player time to move as it fades in if (this.fadeCycle < 120) { //damage scales up over 2 seconds to give player time to move as it fades in
const scale = this.fadeCycle / 120 const scale = this.fadeCycle / 120
const dmg = (this.fadeCycle < 60) ? 0 : 0.15 * simulation.dmgScale * scale const dmg = this.fadeCycle < 60 ? 0 : 0.13 * simulation.dmgScale * scale
me.lasers(me.vertices[0], me.angle + Math.PI / 6, dmg); me.lasers(me.vertices[0], me.angle + Math.PI / 6, dmg);
me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6, dmg); me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6, dmg);
me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6, dmg); me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6, dmg);
@@ -622,8 +631,8 @@ const spawn = {
//when player is inside event horizon //when player is inside event horizon
if (Vector.magnitude(Vector.sub(me.position, player.position)) < this.eventHorizon) { if (Vector.magnitude(Vector.sub(me.position, player.position)) < this.eventHorizon) {
if (m.immuneCycle < m.cycle) { if (m.immuneCycle < m.cycle) {
if (m.energy > 0) m.energy -= 0.02 if (m.energy > 0) m.energy -= 0.018
if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0004 * simulation.dmgScale); if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0003 * simulation.dmgScale);
} }
const angle = Math.atan2(player.position.y - me.position.y, player.position.x - me.position.x); const angle = Math.atan2(player.position.y - me.position.y, player.position.x - me.position.x);
player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1); player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
@@ -669,9 +678,9 @@ const spawn = {
// exit() {}, // exit() {},
// }, // },
] ]
shuffle(me.mode); shuffle(me.mode); //THIS SHOULDN'T BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
me.do = function() { me.do = function() {
this.fill = '#' + Math.random().toString(16).substr(-6); //flash colors this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
if (this.health < 1) { if (this.health < 1) {
this.cycle++; this.cycle++;
this.checkStatus(); this.checkStatus();
@@ -679,12 +688,12 @@ const spawn = {
this.spawnBoss(); this.spawnBoss();
this.damageReductionDecay(); this.damageReductionDecay();
for (let i = 0; i < this.totalModes; i++) this.mode[i].do() for (let i = 0; i < this.totalModes; i++) this.mode[i].do()
// this.mode[3].do()
// this.mode[4].do()
// this.mode[7].do()
} }
// this.cycle++;
// this.mode[0].do()
// this.mode[7].do()
}; };
me.spawnRate = 4300 - 30 * simulation.difficultyMode * simulation.difficultyMode me.spawnRate = 4800 - 30 * simulation.difficultyMode * simulation.difficultyMode
me.spawnBoss = function() { //if the fight lasts too long start spawning bosses me.spawnBoss = function() { //if the fight lasts too long start spawning bosses
if (!(me.cycle % this.spawnRate) && this.health < 1) { if (!(me.cycle % this.spawnRate) && this.health < 1) {
this.spawnRate = Math.max(300, this.spawnRate - 10 * simulation.difficultyMode * simulation.difficultyMode) //reduce the timer each time a boss spawns this.spawnRate = Math.max(300, this.spawnRate - 10 * simulation.difficultyMode * simulation.difficultyMode) //reduce the timer each time a boss spawns
@@ -707,7 +716,74 @@ const spawn = {
player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1) player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1)
player.force.y -= magY * player.mass player.force.y -= magY * player.mass
} }
me.boulder = function(x, y) {
mobs.spawn(x, y, 6, Math.floor(50 + 50 * Math.random()), this.fill);
let boss = this
let me = mob[mob.length - 1];
me.stroke = "transparent";
me.onHit = function() {
this.timeLeft = 0
};
me.explodeRange = 500
me.onDeath = function() { //explode
simulation.drawList.push({ //draw explosion
x: this.position.x,
y: this.position.y,
radius: this.explodeRange,
color: this.fill,
time: 8
});
let sub, knock
sub = Vector.sub(player.position, this.position);
if (Vector.magnitude(sub) < this.explodeRange) { //player knock back
m.damage(0.05);
knock = Vector.mult(Vector.normalise(sub), player.mass * 0.1);
player.force.x += knock.x;
player.force.y += knock.y;
}
for (let i = 0, len = powerUp.length; i < len; ++i) { //power up knock backs
sub = Vector.sub(powerUp[i].position, this.position);
if (Vector.magnitude(sub) < this.explodeRange) {
knock = Vector.mult(Vector.normalise(sub), powerUp[i].mass * 0.1);
powerUp[i].force.x += knock.x;
powerUp[i].force.y += knock.y;
}
}
for (let i = 0, len = body.length; i < len; ++i) { //block knock backs
sub = Vector.sub(body[i].position, this.position);
if (Vector.magnitude(sub) < this.explodeRange) {
knock = Vector.mult(Vector.normalise(sub), body[i].mass * 0.1);
body[i].force.x += knock.x;
body[i].force.y += knock.y;
}
}
}
Matter.Body.setDensity(me, 0.003); //normal is 0.001
me.timeLeft = 360;
me.g = 0.0005; //required if using this.gravity
me.frictionAir = 0.005;
me.friction = 1;
me.frictionStatic = 1
me.restitution = 0;
me.leaveBody = false;
me.isDropPowerUp = false;
me.isBadTarget = true;
me.isMobBullet = true;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.spin = me.inertia * 0.000005 * (1 + Math.random()) * (m.pos.x > me.position.x ? 1 : -1)
Matter.Body.setAngularVelocity(me, 0.1 * (1 + 0.3 * Math.random()) * (m.pos.x > me.position.x ? 1 : -1));
Matter.Body.setVelocity(me, { x: 0, y: 10 });
me.do = function() {
this.fill = boss.fill
this.torque += this.spin;
this.gravity();
this.timeLimit();
};
}
me.orbitalNoVelocity = function(who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss me.orbitalNoVelocity = function(who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
let boss = this
mobs.spawn(who.position.x, who.position.y, 6, 20, "rgb(255,0,150)"); mobs.spawn(who.position.x, who.position.y, 6, 20, "rgb(255,0,150)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.stroke = "transparent"; me.stroke = "transparent";
@@ -721,17 +797,18 @@ const spawn = {
me.collisionFilter.category = cat.mobBullet; me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
me.do = function() { me.do = function() {
this.fill = boss.fill
const time = simulation.cycle * speed + phase const time = simulation.cycle * speed + phase
const orbit = { x: Math.cos(time), y: Math.sin(time) } const orbit = { x: Math.cos(time), y: Math.sin(time) }
Matter.Body.setPosition(this, Vector.add(who.position, Vector.mult(orbit, radius))) Matter.Body.setPosition(this, Vector.add(who.position, Vector.mult(orbit, radius)))
if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) { if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
const dmg = 0.06 * simulation.dmgScale const dmg = 0.13 * simulation.dmgScale
m.damage(dmg); m.damage(dmg);
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: this.position.x, x: this.position.x,
y: this.position.y, y: this.position.y,
radius: dmg * 500, radius: Math.sqrt(dmg) * 200,
color: simulation.mobDmgColor, color: simulation.mobDmgColor,
time: simulation.drawTime time: simulation.drawTime
}); });
@@ -739,7 +816,7 @@ const spawn = {
} }
}; };
} }
me.lasers = function(where, angle, dmg = 0.14 * simulation.dmgScale) { me.lasers = function(where, angle, dmg = 0.13 * simulation.dmgScale) {
const vertexCollision = function(v1, v1End, domain) { const vertexCollision = function(v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) { for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices; let vertices = domain[i].vertices;
@@ -1983,6 +2060,7 @@ const spawn = {
// this.fill = `hsla(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%,0.3)` // this.fill = `hsla(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%,0.3)`
//steal all power ups //steal all power ups
if (this.alive) {
for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) { for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
powerUp[i].collisionFilter.mask = 0 powerUp[i].collisionFilter.mask = 0
Matter.Body.setPosition(powerUp[i], this.vertices[i]) Matter.Body.setPosition(powerUp[i], this.vertices[i])
@@ -1991,6 +2069,7 @@ const spawn = {
y: 0 y: 0
}) })
} }
}
this.seePlayerByHistory(50); this.seePlayerByHistory(50);
this.attraction(); this.attraction();
this.checkStatus(); this.checkStatus();
@@ -2108,12 +2187,13 @@ const spawn = {
// Matter.Body.setPosition(powerUp[i], this.vertices[i]) // Matter.Body.setPosition(powerUp[i], this.vertices[i])
// Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 }) // Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
// } // }
if (this.alive) {
for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) { for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
powerUp[i].collisionFilter.mask = 0 powerUp[i].collisionFilter.mask = 0
Matter.Body.setPosition(powerUp[i], this.vertices[i]) Matter.Body.setPosition(powerUp[i], this.vertices[i])
Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 }) Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
} }
}
this.seePlayerCheckByDistance(); this.seePlayerCheckByDistance();
this.attraction(); this.attraction();
@@ -4937,7 +5017,7 @@ const spawn = {
}; };
}, },
mine(x, y) { mine(x, y) {
mobs.spawn(x, y, 8, 10, "rgb(61, 125, 121)"); //"rgb(100,170,150)" mobs.spawn(x, y, 8, 10, "rgb(255, 255, 255)"); //"rgb(100,170,150)" //"rgb(61, 125, 121)"
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.stroke = "transparent"; me.stroke = "transparent";
Matter.Body.setDensity(me, 0.0001); //normal is 0.001 Matter.Body.setDensity(me, 0.0001); //normal is 0.001
@@ -7305,7 +7385,7 @@ const spawn = {
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: this.position.x, x: this.position.x,
y: this.position.y, y: this.position.y,
radius: dmg * 500, radius: Math.sqrt(dmg) * 200,
color: simulation.mobDmgColor, color: simulation.mobDmgColor,
time: simulation.drawTime time: simulation.drawTime
}); });

View File

@@ -554,7 +554,7 @@ const tech = {
}, },
{ {
name: "catabolism", name: "catabolism",
descriptionFunction() { return `if you fire while <strong>out</strong> of <strong class='color-ammo'>ammo</strong><br>spawn ${powerUps.orb.ammo(4)} and <strong>1</strong> maximum ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"}` }, descriptionFunction() { return `if you fire while <strong>out</strong> of <strong class='color-ammo'>ammo</strong><br>spawn ${powerUps.orb.ammo(4)} and ${tech.isEnergyHealth ? "<strong>4</strong> maximum <strong class='color-f'>energy</strong>" : "<strong>2</strong> maximum <strong class='color-h'>health</strong>"}` },
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -2412,7 +2412,7 @@ const tech = {
}, },
{ {
name: "exothermic process", name: "exothermic process",
description: "<strong>+50%</strong> <strong class='color-d'>damage</strong><br>after mobs <strong>die</strong> <strong>25%</strong> <strong class='color-f'>energy</strong>", description: "<strong>+50%</strong> <strong class='color-d'>damage</strong><br>after mobs <strong>die</strong> <strong>20%</strong> <strong class='color-f'>energy</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3437,7 +3437,7 @@ const tech = {
}, },
{ {
name: "unified field theory", name: "unified field theory",
description: `<span style = 'font-size:90%;'><strong>clicking</strong> the <strong class='color-f'>field</strong> box when <strong>paused</strong> cycles your <strong class='color-f'>field</strong><br><strong>triple</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-f'>field</strong><strong class='color-m'>tech</strong></span>`, description: `<span style = 'font-size:90%;'><strong>clicking</strong> the <strong class='color-f'>field</strong> box when <strong>paused</strong> cycles your <strong class='color-f'>field</strong><br><strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-f'>field</strong><strong class='color-m'>tech</strong></span>`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3449,14 +3449,14 @@ const tech = {
effect() { effect() {
tech.isPauseSwitchField = true; tech.isPauseSwitchField = true;
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isFieldTech) tech.tech[i].frequency *= 3 if (tech.tech[i].isFieldTech) tech.tech[i].frequency *= 2
} }
}, },
remove() { remove() {
tech.isPauseSwitchField = false; tech.isPauseSwitchField = false;
if (this.count > 1) { if (this.count > 1) {
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isFieldTech) tech.tech[i].frequency /= 3 if (tech.tech[i].isFieldTech) tech.tech[i].frequency /= 2
} }
} }
} }
@@ -8548,7 +8548,8 @@ const tech = {
allowed() { return true }, allowed() { return true },
requires: "", requires: "",
effect() { effect() {
level.levels.splice(level.onLevel, 0, level.levels[level.onLevel]); const index = Math.min(level.levels.length - 1, level.onLevel)
level.levels.splice(index, 0, level.levels[index]);
}, },
remove() {} remove() {}
}, },

View File

@@ -1,24 +1,42 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
finalBoss rework finalBoss has a new phase: "boulders"
(this is pretty raw, so expect a bug and balance patch soon) each phase has been rebalanced
finalBoss goes invulnerable a few times as it loses health boss health is a bit higher
finalBoss damage reduction is higher mob mines are white now
finalBoss damage reduction slowly decays as you do any damage to the boss
damage reduction resets to normal with each new invulnerability phase
after each invulnerability phase it randomly adds 1 more attack mode
lasers, black hole, mines, hoppers, seekers, mobs, orbiters, oscillation
mobs die below 0.05 -> 0.01 health pilot wave gets +1 choice for gun,field,tech
might cause bugs, but testing this out
guns and field power ups show 3 -> 2 options
bug fixes: bug fixes:
*********************************************************** TODO ***************************************************** *********************************************************** TODO *****************************************************
harpoon + another gun + bessemer + catabolysis + mass-energy exploit? finalBoss
add synergies between modes:
black hole can pull in bullets
laser can hurt bullets? maybe bad idea
old mode changes
mine color needs to be move vibrant
hoppers can hop out of the slime and the door on the sides
new modes:
rotating quadrant immunity shield, can't take damage from that quadrant
maybe also attack player near that quadrant
falling object warps to ceiling after hitting floor
doesn't end, player needs to kill it
slowly grows?
slow effect zones
random placement or place over player or both!
draw white dot and an outline of area of effect
expanding circle stroke, freeze effect triggers when stroke circle hits fill circle
after 1-2 seconds freeze player if in the zone
also freeze mobs
effect that makes player have to be close to boss
hook that tries to yank the player into hitting finalBoss
does damage
pulls player into center
counter with wormhole, negative mass
player targeted unless cloaking
tech - leave one of your tech at random, find it next run tech - leave one of your tech at random, find it next run
store level name and position in local storage store level name and position in local storage