diff --git a/img/accretion disk.webp b/img/accretion disk.webp new file mode 100644 index 0000000..d8a6013 Binary files /dev/null and b/img/accretion disk.webp differ diff --git a/js/bullet.js b/js/bullet.js index b1bc458..72ba461 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -3035,7 +3035,7 @@ const b = { const me = bullet.length; const THRUST = 0.0018 const RADIUS = 18 - const SCALE = 1 - 0.12 / tech.bulletsLastLonger + const SCALE = 1 - 0.11 / tech.bulletsLastLonger bullet[me] = Bodies.polygon(where.x, where.y, 3, RADIUS, { angle: dir - Math.PI, // inertia: Infinity, diff --git a/js/index.js b/js/index.js index 5c22bad..3c216a6 100644 --- a/js/index.js +++ b/js/index.js @@ -351,7 +351,6 @@ const build = { } } - // fade alpha for all pixels // for (let i = 0; i < data.length; i += 4) { // if (data[i + 3] > 0) { @@ -424,11 +423,8 @@ const build = { } }, pauseGrid() { - // build.pixelDraw(); - build.generatePauseLeft() //makes the left side of the pause menu with the tech build.generatePauseRight() //makes the right side of the pause menu with the tech - document.getElementById("tech").style.display = "none" document.getElementById("guns").style.display = "none" document.getElementById("field").style.display = "none" @@ -436,12 +432,8 @@ const build = { document.getElementById("health-bg").style.display = "none" document.getElementById("defense-bar").style.display = "none" document.getElementById("damage-bar").style.display = "none" - - //show in game console - // document.getElementById("text-log").style.display = "inline" simulation.lastLogTime = m.cycle //hide in game console - }, generatePauseLeft() { //used for junk estimation @@ -504,12 +496,29 @@ ${junkCount ? `
JUNK: ${(junkCount / tota ${simulation.isCheating ? "

lore disabled" : ""} `; // deaths: ${mobs.mobDeaths}   - if (tech.isPauseSwitchField && !simulation.isChoosing) { + // if (tech.isPauseSwitchField && !simulation.isChoosing) { + // const style = localSettings.isHideImages ? `style="height:auto;"` : `style="background-image: url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? m.fieldUpgrades[0].imageNumber : ""}.webp');"` + // text += `
+ //
+ //
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
+ // ${m.fieldUpgrades[m.fieldMode].description}
` + if ((tech.isPauseSwitchField || simulation.testing)) { //&& !simulation.isChoosing + // const fieldNameP = m.fieldUpgrades[m.fieldMode > 1 ? m.fieldMode - 1 : m.fieldUpgrades.length - 1].name + // const fieldNameN = m.fieldUpgrades[m.fieldMode === m.fieldUpgrades.length - 2 ? 1 : m.fieldMode + 1].name + //button above for previous + text += `
+
` + //button for current const style = localSettings.isHideImages ? `style="height:auto;"` : `style="background-image: url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? m.fieldUpgrades[0].imageNumber : ""}.webp');"` text += `
-
+
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
${m.fieldUpgrades[m.fieldMode].description}
` + //button below for next + text += `
+
` + + } else { const style = localSettings.isHideImages ? `style="height:auto;"` : `style="background-image: url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? m.fieldUpgrades[0].imageNumber : ""}.webp');"` text += `
@@ -1356,7 +1365,24 @@ window.addEventListener("keydown", function (event) { document.body.style.cursor = "auto"; if (tech.isPauseSwitchField || simulation.testing) { - document.getElementById("pause-field").addEventListener("click", () => { + document.getElementById("pause-field-previous").addEventListener("click", () => { + const energy = m.energy //save current energy + if (m.fieldMode === 4 && simulation.molecularMode > 0) { + simulation.molecularMode-- + m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription() + } else { + m.setField((m.fieldMode < 2) ? m.fieldUpgrades.length - 1 : m.fieldMode - 1) //cycle to previous field, skip field emitter + if (m.fieldMode === 4) { + simulation.molecularMode = 3 + m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription() + } + } + m.energy = energy //return to current energy + document.getElementById("pause-field").style.backgroundImage = `url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? Math.floor(Math.random() * 10) : ""}.webp')` + document.getElementById("pause-field").innerHTML = `
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
${m.fieldUpgrades[m.fieldMode].description}
` + }); + + document.getElementById("pause-field-next").addEventListener("click", () => { const energy = m.energy //save current energy if (m.fieldMode === 4 && simulation.molecularMode < 3) { simulation.molecularMode++ @@ -1371,10 +1397,7 @@ window.addEventListener("keydown", function (event) { m.energy = energy //return to current energy // document.getElementById("pause-field").innerHTML = `
  ${m.fieldUpgrades[m.fieldMode].name}
${m.fieldUpgrades[m.fieldMode].description}` document.getElementById("pause-field").style.backgroundImage = `url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? Math.floor(Math.random() * 10) : ""}.webp')` - document.getElementById("pause-field").innerHTML = ` -
-
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
- ${m.fieldUpgrades[m.fieldMode].description}
` + document.getElementById("pause-field").innerHTML = `
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
${m.fieldUpgrades[m.fieldMode].description}
` }); } } diff --git a/js/level.js b/js/level.js index 4e72d84..cfb4fba 100644 --- a/js/level.js +++ b/js/level.js @@ -19,8 +19,8 @@ const level = { // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode // simulation.isHorizontalFlipped = true // tech.giveTech("performance") - // level.difficultyIncrease(3 * 2) //30 is near max on hard //60 is near max on why - // m.maxHealth = m.health = 100000000 + // level.difficultyIncrease(7 * 2) //30 is near max on hard //60 is near max on why + // m.maxHealth = m.health = 1//00000000 // m.maxEnergy = m.energy = 10000000 // tech.isRerollDamage = true // powerUps.research.changeRerolls(99999) @@ -47,7 +47,7 @@ const level = { // for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide") // m.lastKillCycle = m.cycle // for (let i = 0; i < 1; ++i) tech.giveTech("swarf") - // for (let i = 0; i < 1; ++i) tech.giveTech("CPT symmetry") + // for (let i = 0; i < 1; ++i) tech.giveTech("unified field theory") // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research"); // for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); @@ -57,8 +57,8 @@ const level = { // for (let i = 0; i < 1; ++i) spawn.laserLayer(1400, -500) // Matter.Body.setPosition(player, { x: -200, y: -3330 }); // for (let i = 0; i < 4; ++i) spawn.laserLayer(1300, -500 + 100 * Math.random()) - // for (let i = 0; i < 3; ++i) spawn.laser(1900, -500) - // for (let i = 0; i < 1; ++i) spawn.laserBombingBoss(1900, -2500) + // for (let i = 0; i < 1; ++i) spawn.laserLayerBoss(1900, -500) + // for (let i = 0; i < 1; ++i) spawn.dragonFlyBoss(1900, -500) // spawn.beetleBoss(1900, -500, 25) // spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color) // for (let i = 0; i < 5; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random()) @@ -4996,10 +4996,7 @@ const level = { powerUps.directSpawn(x + 998, y - 333, "tech", false); } const powerUp1 = powerUp[powerUp.length - 1] - powerUp1.holdPosition = { - x: powerUp1.position.x, - y: powerUp1.position.y - } + powerUp1.holdPosition = { x: powerUp1.position.x, y: powerUp1.position.y } let isSpawnedMobs = false doCustom.push( () => { @@ -5014,9 +5011,23 @@ const level = { if (Vector.magnitudeSquared(Vector.sub(m.pos, powerUp1.position)) < 90000) { //zone radius is 300 //damage player and drain energy if (m.immuneCycle < m.cycle) { - m.damage(0.01); - if (m.energy > 0.1) m.energy -= 0.02 + if (m.energy < 0.02) { + //push out + // const force = Vector.mult(Vector.normalise(Vector.sub(player.position, powerUp1.position)), 0.02 * player.mass) + // player.force.x += force.x + // player.force.y += force.y + player.force.x += (player.position.x > powerUp1.position.x) ? 0.02 * player.mass : - 0.02 * player.mass + + } else { + m.energy -= 0.01 + //friction + Matter.Body.setVelocity(player, { + x: player.velocity.x * 0.45, + y: player.velocity.y * 0.98 + }); + } } + //draw electricity going towards player const unit = Vector.normalise(Vector.sub(m.pos, powerUp1.position)) let xElec = powerUp1.position.x + 40 * unit.x; diff --git a/js/player.js b/js/player.js index e0df3d5..afdab53 100644 --- a/js/player.js +++ b/js/player.js @@ -540,10 +540,10 @@ const m = { } }, baseHealth: 1, - setMaxHealth() { + setMaxHealth(isMessage) { m.maxHealth = m.baseHealth + tech.extraMaxHealth + 3 * tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth document.getElementById("health-bg").style.width = `${Math.floor(300 * m.maxHealth)}px` - simulation.makeTextLog(`m.maxHealth = ${m.maxHealth.toFixed(2)}`) + if (isMessage) simulation.makeTextLog(`m.maxHealth = ${m.maxHealth.toFixed(2)}`) if (m.health > m.maxHealth) m.health = m.maxHealth; m.displayHealth(); }, @@ -605,10 +605,7 @@ const m = { let history = m.history[(m.cycle - steps) % 600] Matter.Body.setPosition(player, history.position); - Matter.Body.setVelocity(player, { - x: history.velocity.x, - y: history.velocity.y - }); + Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y }); m.yOff = history.yOff if (m.yOff < 48) { m.doCrouch() @@ -2125,14 +2122,8 @@ const m = { hole: { isOn: false, isReady: false, - pos1: { - x: 0, - y: 0 - }, - pos2: { - x: 0, - y: 0 - }, + pos1: { x: 0, y: 0 }, + pos2: { x: 0, y: 0 }, }, fieldArc: 0, fieldThreshold: 0, @@ -2175,20 +2166,14 @@ const m = { m.calculateFieldThreshold(); //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) m.isBodiesAsleep = true; m.wakeCheck(); - m.setMaxEnergy(); - m.setMaxHealth(); + m.setMaxEnergy(false); + m.setMaxHealth(false); m.couplingChange() m.hole = { isOn: false, isReady: false, - pos1: { - x: 0, - y: 0 - }, - pos2: { - x: 0, - y: 0 - }, + pos1: { x: 0, y: 0 }, + pos2: { x: 0, y: 0 }, } }, setMaxEnergy(isMessage = true) { @@ -3436,15 +3421,9 @@ const m = { } } else if (simulation.molecularMode === 1) { m.energy -= 0.33; - const direction = { - x: Math.cos(m.angle), - y: Math.sin(m.angle) - } + const direction = { x: Math.cos(m.angle), y: Math.sin(m.angle) } const push = Vector.mult(Vector.perp(direction), 0.08) - b.missile({ - x: m.pos.x + 30 * direction.x, - y: m.pos.y + 30 * direction.y - }, m.angle, -15) + b.missile({ x: m.pos.x + 30 * direction.x, y: m.pos.y + 30 * direction.y }, m.angle, -15) bullet[bullet.length - 1].force.x += push.x * (Math.random() - 0.5) bullet[bullet.length - 1].force.y += 0.005 + push.y * (Math.random() - 0.5) // b.missile({ x: m.pos.x, y: m.pos.y - 40 }, -Math.PI / 2 + 0.5 * (Math.random() - 0.5), 0, 1) @@ -3538,10 +3517,7 @@ const m = { radiusLimit: 10, damage: 0.8, setPositionToNose() { - const nose = { - x: m.pos.x + 10 * Math.cos(m.angle), - y: m.pos.y + 10 * Math.sin(m.angle) - } + const nose = { x: m.pos.x + 10 * Math.cos(m.angle), y: m.pos.y + 10 * Math.sin(m.angle) } Matter.Body.setPosition(this, Vector.add(nose, Vector.mult(Vector.normalise(Vector.sub(nose, m.pos)), circleRadiusScale * this.circleRadius))); }, fire() { diff --git a/js/spawn.js b/js/spawn.js index 9f7c1df..691729b 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -6,7 +6,8 @@ const spawn = { "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", "snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "shieldingBoss", - "timeSkipBoss", "dragonFlyBoss", "beetleBoss", "sneakBoss", "mantisBoss" + "timeSkipBoss", "dragonFlyBoss", "beetleBoss", "sneakBoss", "mantisBoss", + "laserLayerBoss" ], bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed bossTypeSpawnIndex: 0, //increases as the boss type cycles @@ -4216,7 +4217,7 @@ const spawn = { ctx.beginPath(); ctx.moveTo(this.lasers[i].a.x, this.lasers[i].a.y); ctx.lineTo(this.lasers[i].b.x, this.lasers[i].b.y); - ctx.lineWidth = 5 + 5 * this.lasers[i].fade; + ctx.lineWidth = 2 + 40 - 40 * this.lasers[i].fade; ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.lasers[i].fade})`; ctx.stroke(); } @@ -4238,21 +4239,207 @@ const spawn = { this.force.x += force.x; this.force.y += force.y; } - }, - me.do = function () { - this.cycle++ - this.torque = this.lookTorque * this.inertia * 0.6; - this.seePlayerCheck(); - this.checkStatus(); - this.drift(); - //add new laser to lasers array - this.addLaser() - this.fireLaser() - // if (this.seePlayer.recall) { - // //set direction to turn to fire - // if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); - // } - }; + } + me.do = function () { + this.cycle++ + this.torque = this.lookTorque * this.inertia * 0.6; + this.seePlayerCheck(); + this.checkStatus(); + this.drift(); + //add new laser to lasers array + this.addLaser() + this.fireLaser() + // if (this.seePlayer.recall) { + // //set direction to turn to fire + // if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); + // } + }; + }, + laserLayerBoss(x, y, radius = 65) { + const color = "#f09" + mobs.spawn(x, y, 4, radius, color); + let me = mob[mob.length - 1]; + me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front + for (let i = 0; i < 4; i += 2) { + let spike = Vector.mult(Vector.normalise(Vector.sub(me.vertices[i], me.position)), radius * 2) + me.vertices[i].x = me.position.x + spike.x + me.vertices[i].y = me.position.y + spike.y + } + Matter.Body.rotate(me, Math.random() * Math.PI * 2); + me.accelMag = 0.0001 * simulation.accelScale; + + + me.isBoss = true; + me.onDeath = function () { + powerUps.spawnBossPowerUp(this.position.x, this.position.y) + }; + Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger + me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = me.damageReduction + me.isInvulnerable = false + me.nextHealthThreshold = 0.75 + me.invulnerableCount = 0 + 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 = 120 + this.isInvulnerable = true + this.damageReduction = 0 + + // if (this.health > 0.74) this.laserLimit += 2 //increase total lasers once player gets into combat + // this.addLaser() + this.laserDelay = 130 + } + }; + me.lasers = [] //keeps track of static laser beams + // me.laserLimit = 1 + 2 * (simulation.difficultyMode < 3 ? 1 : 2) + me.laserLimit = 2 + (simulation.difficultyMode < 3 ? 1 : 2) + me.fireDelay = Math.max(75, 140 - simulation.difficulty * 0.5) + me.cycle = 0 + me.laserDelay = 210 + me.addLaser = function () { + if (this.cycle > this.laserDelay) { + this.cycle = 0 + const seeRange = 6000; + let add = (where, angle) => { + const v1 = { x: where.x + seeRange * Math.cos(angle), y: where.y + seeRange * Math.sin(angle) }; + const v2 = { x: where.x + seeRange * Math.cos(angle + Math.PI), y: where.y + seeRange * Math.sin(angle + Math.PI) }; + //find where v1,v2 hit walls and make them stop there + let best1 = vertexCollision(where, v1, [map]); + let best2 = vertexCollision(where, v2, [map]); + if (best2.who === null) { + best2.x = v2.x + best2.y = v2.y + } + if (best1.who === null) { //if the path never hits the map , just stop at seeRange + best1.x = v1.x + best1.y = v1.y + } + if (best1.y > best2.y) { //make laser beams always fire from top to bottom so they are predicable, and not stopped by blocks on the ground + const save1X = best1.x + const save1Y = best1.y + best1.x = best2.x + best1.y = best2.y + best2.x = save1X + best2.y = save1Y + } + this.lasers.push({ a: { x: best1.x, y: best1.y }, b: { x: best2.x, y: best2.y }, fade: 0 }) + } + // add(m.pos, m.angle) + add(m.pos, this.angle + Math.PI / 4 + Math.PI / 2) + add(this.position, this.angle + Math.PI / 4) + //friction to animate the mob dropping something + Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.05)); + Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.05) + if (!this.seePlayer.recall && (Vector.magnitude(Vector.sub(this.position, this.driftGoal)) < 200 || 0.3 > Math.random())) { + //used in drift when can't find player + const radius = Math.random() * 1000; + const angle = Math.random() * 2 * Math.PI; + this.driftGoal = Vector.add(this.driftCenter, { x: radius * Math.cos(angle), y: radius * Math.sin(angle) }) + } + } + } + me.fireLaser = function () { + for (let i = 0; i < this.lasers.length; i++) { //fire all lasers in the array + let best = vertexCollision(this.lasers[i].a, this.lasers[i].b, m.isCloak ? [body] : [body, [playerBody, playerHead]]); //not checking map to fix not hitting player bug, this might make some lasers look strange when the map changes + if (this.lasers[i].fade > 0.99) { + if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { // hitting player + m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage after getting hit + const dmg = 0.05 * simulation.dmgScale; + m.damage(dmg); + simulation.drawList.push({ //add dmg to draw queue + x: best.x, + y: best.y, + radius: dmg * 1500, + color: "rgba(255,0,100,0.5)", + time: 20 + }); + this.lasers.splice(i, 1) //remove this laser node + if (this.distanceToPlayer < 1000) { //mob jumps away from player + const forceMag = 0.03 * this.mass; + const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x); + this.force.x -= 2 * forceMag * Math.cos(angle); + this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity + } + } else if (best.who && best.who.classType === "body") { //hitting block + ctx.beginPath(); + ctx.moveTo(best.x, best.y); + ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y); + ctx.strokeStyle = `rgb(255,0,100)`; + ctx.lineWidth = 2; + ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); + ctx.stroke(); + ctx.setLineDash([]); + } else { //hitting nothing + ctx.beginPath(); + ctx.moveTo(this.lasers[i].b.x, this.lasers[i].b.y); + ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y); + ctx.strokeStyle = `rgb(255,0,100)`; + ctx.lineWidth = 2; + ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); + ctx.stroke(); + ctx.setLineDash([]); + } + } else {//fade in warning + this.lasers[i].fade += 0.007 + ctx.beginPath(); + ctx.moveTo(this.lasers[i].a.x, this.lasers[i].a.y); + ctx.lineTo(this.lasers[i].b.x, this.lasers[i].b.y); + ctx.lineWidth = 2 + 40 - 40 * this.lasers[i].fade; + ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.lasers[i].fade})`; + ctx.stroke(); + if (this.lasers[i].fade > 0.99) { + this.lasers[i].fade = 1; + if (this.lasers.length > this.laserLimit) this.lasers.shift() //cap total lasers + break + } + } + } + } + me.driftCenter = { ...me.position }; //copy position with out reference so it doesn't change as mob moves + const r = Math.random() * 100; + const a = Math.random() * 2 * Math.PI; + me.driftGoal = Vector.add(me.driftCenter, { x: r * Math.cos(a), y: r * Math.sin(a) }) //updated in addLaser() + me.drift = function () { + //accelerate towards the player + if (this.seePlayer.recall) { + const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass) + this.force.x += force.x; + this.force.y += force.y; + } else { //drift + const force = Vector.mult(Vector.normalise(Vector.sub(this.driftGoal, this.position)), 0.00001 * this.mass) + // const force = Vector.mult(this.driftGoal, 0.0001 * this.mass) + this.force.x += force.x; + this.force.y += force.y; + } + this.torque = this.lookTorque * this.inertia * 0.9; + } + me.do = function () { + this.cycle++ + this.seePlayerCheck(); + this.checkStatus(); + this.drift(); + //add new laser to lasers array + this.addLaser() + this.fireLaser() + if (this.isInvulnerable) { + this.invulnerableCount-- + if (this.invulnerableCount < 0) { + this.isInvulnerable = false + this.damageReduction = this.startingDamageReduction + } + //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 = 13 + 5 * Math.random(); + ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`; + ctx.stroke(); + } + }; }, laser(x, y, radius = 30) { const color = "#f00" @@ -4325,7 +4512,6 @@ const spawn = { laserBoss(x, y, radius = 30) { mobs.spawn(x, y, 3, radius, "#f00"); let me = mob[mob.length - 1]; - setTimeout(() => { //fix mob in place, but allow rotation me.constraint = Constraint.create({ pointA: { x: me.position.x, y: me.position.y }, @@ -5551,7 +5737,7 @@ const spawn = { let me = mob[mob.length - 1]; Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger me.isBoss = true; - me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.accelMag = 0.0017 * Math.sqrt(simulation.accelScale); me.frictionAir = 0.01; @@ -5667,7 +5853,7 @@ const spawn = { this.isVanished = true this.cloak(); //teleport to near the end of player history - Matter.Body.setPosition(this, m.history[Math.floor((m.history.length - 1) * (0.66 + 0.33 * Math.random()))].position) + Matter.Body.setPosition(this, m.history[Math.floor((m.history.length - 1) * (0.3 + 0.4 * Math.random()))].position) Matter.Body.setVelocity(this, { x: 0, y: 0 }); this.damageReduction = 0 //immune to harm for the rest of this game cycle } @@ -7176,7 +7362,7 @@ const spawn = { let me = mob[mob.length - 1]; me.isBoss = true; 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.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0 me.isInvulnerable = true @@ -7283,6 +7469,9 @@ const spawn = { if (this.snakeHeadID === mob[i].id) { mob[i].isInvulnerable = false mob[i].damageReduction = mob[i].startingDamageReduction + } else if (mob[i].isSnakeTail) { + //damage all snake tails + mob[i].health *= 0.95 } } }, 500); diff --git a/js/tech.js b/js/tech.js index a62ab72..aaf08b3 100644 --- a/js/tech.js +++ b/js/tech.js @@ -231,6 +231,7 @@ const tech = { // } // } // } + if (tech.isPowerUpDamage) dmg *= 1 + 0.05 * powerUp.length if (tech.isDamageCooldown) dmg *= m.lastKillCycle + tech.isDamageCooldownTime > m.cycle ? 0.45 : 4.33 if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.93 if (tech.isDivisor && b.activeGun !== undefined && b.activeGun !== null && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77 @@ -3338,6 +3339,27 @@ const tech = { powerUps.setPowerUpMode(); }, }, + { + name: "accretion disk", + descriptionFunction() { + return `+5% damage (${5 * powerUp.length}%)
for each power up that exists on this level` + }, + maxCount: 1, + count: 0, + frequency: 3, + frequencyDefault: 3, + isHealTech: true, + allowed() { + return tech.isHealAttract + }, + requires: "accretion", + effect() { + tech.isPowerUpDamage = true + }, + remove() { + tech.isPowerUpDamage = false + }, + }, { name: "self-assembly", descriptionFunction() { @@ -4067,7 +4089,7 @@ const tech = { }, { name: "unified field theory", - description: `when paused clicking your field cycles it
double the frequency of finding fieldtech`, + description: `in the pause menu click to switch fields
double the frequency of finding fieldtech`, maxCount: 1, count: 0, frequency: 1, @@ -12166,4 +12188,5 @@ const tech = { isMobLowHealth: null, isDamageCooldown: null, isDamageCooldownTime: null, + isPowerUpDamage: null, } \ No newline at end of file diff --git a/style.css b/style.css index b254cf7..216d5f9 100644 --- a/style.css +++ b/style.css @@ -1264,7 +1264,7 @@ summary { } 100% { - background-color: rgb(200, 255, 255) + background-color: rgb(0, 204, 255) } } diff --git a/todo.txt b/todo.txt index 30494eb..e6d3a66 100644 --- a/todo.txt +++ b/todo.txt @@ -1,41 +1,24 @@ ******************************************************** NEXT PATCH ************************************************** -mob: laserLayer - leaves behind lasers that persist for a few seconds -ghoster mobs do 66% less damage, but they eject your ammo - -grappling hook tech rupture renamed swarf - fires several nails at nearby mobs, not explosions -grappling hook 6->9 energy per second -CIWS 18->10 energy -reel +40->75 energy reeling blocks -wormhole 5->7% duplication -cloaking no longer drains energy, this fixes a can't cloak bug - dazzler no longer drains energy - dazzler range reduced by 15% - dazzler stuns for 3->2 seconds -zero point energy 100->166 max energy -expansion 40->77 max energy -annihilation -33% of max energy -> 10 energy -dynamical systems is no longer a field tech 35->30 damage -tessellation is no longer a field tech 50->35 defense -yield stress removed - topological defect 80->111% damage - brittle 80->111% damage -commodities exchange 6-12 -> 10-14 power ups -heat engine 50->40% damage -flame test grenades clusters explode 40% faster -alternator uses 10->0% energy for harpoon - -finally made a shared vertexCollision function - this might cause some bugs with laser-like effects... +laserLayerBoss - sends lasers to player's location +snakes bosses - after you kill a tail piece the rest of the tails lose 5% life + this makes targeting any part of the tail a viable strategy +accretion disk - 5% damage for every power up on this level + requires accretion +unified field theory has buttons to cycle field forwards or backwards when paused +iceIX range and damage increased 15% +electric tech in labs level is finally nerfed + drains energy, but doesn't do damage + pushes player away *********************************************************** TODO ***************************************************** -increase damage for each not picked up power up on the level - -make a laserLayerBoss - add lasers on player's history +boss - tracks the position, velocity, angle of power ups, blocks, and bullets it fires + reactor only? + will rewind time + after damage threshold? + does it track player bullets? button/switch input ideas from Cocoon game pick up blocks that have a rubber band attached to a sliding switch