field tech: patch - after cloaking recover 75% of last health lost using that much energy
  taking damage now forces decloaking
field tech: dynamic equilibrium - increase damage by 5% the value of your last health loss

foam has less velocity after a mob it's stuck to dies
snakeBoss becomes vulnerable if you remove any of the first 3 body segments
  body segments have more health

bug fix: quantum eraser now removes mobs in a more random order
  it used to have a too low chance to remove bosses
This commit is contained in:
landgreen
2022-07-26 08:26:05 -07:00
parent cf3ba7d5f2
commit 3e8f07ab04
9 changed files with 288 additions and 161 deletions

View File

@@ -1450,7 +1450,7 @@ const b = {
} }
if (tech.isFoamBall) { if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random() const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 2 * this.mass; i < len; i++) { for (let i = 0, len = 2 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
} }
@@ -1732,7 +1732,7 @@ const b = {
if (tech.isFoamBall) { if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random() const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 2 * this.mass; i < len; i++) { for (let i = 0, len = 2 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
} }
@@ -3707,6 +3707,10 @@ const b = {
} }
} }
this.targetVertex = bestVertex this.targetVertex = bestVertex
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
} }
}, },
onEnd() {}, onEnd() {},
@@ -3778,6 +3782,10 @@ const b = {
} else if (this.target !== null) { //look for a new target } else if (this.target !== null) { //look for a new target
this.collisionFilter.category = cat.bullet; this.collisionFilter.category = cat.bullet;
this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
Matter.Body.setVelocity(this, {
x: this.target.velocity.x,
y: this.target.velocity.y
});
if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) { if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) {
let targets = [] let targets = []
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
@@ -5645,7 +5653,8 @@ const b = {
} }
if (tech.isFoamBall) { if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random() const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } // const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 }
const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 6 * this.mass; i < len; i++) { for (let i = 0, len = 6 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
} }
@@ -5693,7 +5702,7 @@ const b = {
} }
if (tech.isFoamBall) { if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random() const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 6 * this.mass; i < len; i++) { for (let i = 0, len = 6 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
} }
@@ -5745,7 +5754,7 @@ const b = {
} }
if (tech.isFoamBall) { if (tech.isFoamBall) {
const radius = 5 + 8 * Math.random() const radius = 5 + 8 * Math.random()
const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 }
for (let i = 0, len = 6 * this.mass; i < len; i++) { for (let i = 0, len = 6 * this.mass; i < len; i++) {
b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius)
} }

View File

@@ -224,10 +224,6 @@ window.onresize = () => {
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].link) tech.tech[i].link = `<a target="_blank" href='https://en.wikipedia.org/w/index.php?search=${encodeURIComponent(tech.tech[i].name).replace(/'/g, '%27')}&title=Special:Search' class="link">${tech.tech[i].name}</a>` if (!tech.tech[i].link) tech.tech[i].link = `<a target="_blank" href='https://en.wikipedia.org/w/index.php?search=${encodeURIComponent(tech.tech[i].name).replace(/'/g, '%27')}&title=Special:Search' class="link">${tech.tech[i].name}</a>`
} }
//<br>effective <strong class='color-defense'>defense</strong>: ${(1-simulation.dmgScale*m.harmReduction()).toPrecision(3)}
//<br>effective <strong class='color-d'>damage</strong>: ${(tech.damageFromTech() * m.dmgScale).toPrecision(3)}
const build = { const build = {
pauseGrid() { pauseGrid() {
//left side //left side

View File

@@ -16,7 +16,7 @@ const level = {
start() { start() {
if (level.levelsCleared === 0) { //this code only runs on the first level if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode // simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(8 * 4) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(4 * 4) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// m.maxHealth = m.health = 100 // m.maxHealth = m.health = 100
// powerUps.research.changeRerolls(100000) // powerUps.research.changeRerolls(100000)
@@ -24,19 +24,19 @@ const level = {
// powerUps.research.changeRerolls(100) // powerUps.research.changeRerolls(100)
// tech.tech[297].frequency = 100 // tech.tech[297].frequency = 100
// b.guns[0].ammo = 10000 // b.guns[0].ammo = 10000
// m.setField("metamaterial cloaking") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole // m.setField("metamaterial cloaking") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass
// b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 matter 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 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// tech.giveTech("robotics") // tech.giveTech("dynamic equilibrium")
// tech.giveTech("CPT symmetry"); // tech.giveTech("quantum eraser");
// tech.giveTech("lens"); // tech.giveTech("patch");
// tech.giveTech("robotics") // tech.giveTech("polyurethane foam")
// for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot") // for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot")
// for (let i = 0; i < 1; ++i) tech.giveTech("electric generator") // for (let i = 0; i < 1; ++i) tech.giveTech("electric generator")
// for (let i = 0; i < 9; i++) tech.giveTech("compound lens") // for (let i = 0; i < 9; i++) tech.giveTech("compound lens")
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research");
// spawn.starter(1900, -500) // spawn.starter(1900, -500, 100)
// spawn.laserTargetingBoss(1900, -500) // spawn.snakeBoss(1900, -500)
// for (let i = 0; i < 10; ++i) spawn.grower(1900, -500) // for (let i = 0; i < 10; ++i) spawn.grower(1900, -500)
// level.testing(); //not in rotation, used for testing // level.testing(); //not in rotation, used for testing
// for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); // for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research");

View File

@@ -363,11 +363,8 @@ const m = {
m.health = m.health * (1 + 0.5 * (Math.random() - 0.5)) m.health = m.health * (1 + 0.5 * (Math.random() - 0.5))
if (m.health > 1) m.health = 1; if (m.health > 1) m.health = 1;
m.displayHealth(); m.displayHealth();
//randomize field //randomize field
m.setField(Math.ceil(Math.random() * (m.fieldUpgrades.length - 1))) m.setField(Math.ceil(Math.random() * (m.fieldUpgrades.length - 1)))
//removes guns and ammo //removes guns and ammo
b.inventory = []; b.inventory = [];
b.activeGun = null; b.activeGun = null;
@@ -726,7 +723,11 @@ const m = {
document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4);
} }
if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding if (dmg > 0.03) {
m.lastHit = dmg;
if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding // m.holdingMassScale = 0.5 for most fields
if (m.isCloak) m.fireCDcycle = m.cycle //forced exit cloak
}
const normalFPS = function() { const normalFPS = function() {
if (m.defaultFPSCycle < m.cycle) { //back to default values if (m.defaultFPSCycle < m.cycle) { //back to default values
simulation.fpsCap = simulation.fpsCapDefault simulation.fpsCap = simulation.fpsCapDefault
@@ -908,6 +909,7 @@ const m = {
fieldShieldingScale: 1, fieldShieldingScale: 1,
// fieldDamage: 1, // fieldDamage: 1,
isSneakAttack: false, isSneakAttack: false,
lastHit: 0, //stores value of last damage player took above a threshold, in m.damage
sneakAttackCycle: 0, sneakAttackCycle: 0,
enterCloakCycle: 0, enterCloakCycle: 0,
duplicateChance: 0, duplicateChance: 0,
@@ -950,6 +952,7 @@ const m = {
m.fieldShieldingScale = 1; m.fieldShieldingScale = 1;
m.fieldBlockCD = 10; m.fieldBlockCD = 10;
m.fieldHarmReduction = 1; m.fieldHarmReduction = 1;
m.lastHit = 0
m.isSneakAttack = false m.isSneakAttack = false
m.duplicateChance = 0 m.duplicateChance = 0
powerUps.setDupChance(); powerUps.setDupChance();
@@ -1015,7 +1018,7 @@ const m = {
m.regenEnergy(); m.regenEnergy();
const xOff = m.pos.x - m.radius * m.maxEnergy const xOff = m.pos.x - m.radius * m.maxEnergy
const yOff = m.pos.y - 50 const yOff = m.pos.y - 50
ctx.fillStyle = "rgba(0, 0, 0, 0.3)" // ctx.fillStyle = "rgba(0, 0, 0, 0.2)" //
ctx.fillRect(xOff, yOff, 60 * m.maxEnergy, 10); ctx.fillRect(xOff, yOff, 60 * m.maxEnergy, 10);
ctx.fillStyle = "#fff" //m.cycle > m.lastKillCycle + 300 ? "#000" : "#fff" //"#fff"; ctx.fillStyle = "#fff" //m.cycle > m.lastKillCycle + 300 ? "#000" : "#fff" //"#fff";
ctx.fillRect(xOff, yOff, 60 * m.energy, 10); ctx.fillRect(xOff, yOff, 60 * m.energy, 10);
@@ -2750,39 +2753,27 @@ const m = {
m.fieldFire = true; m.fieldFire = true;
m.fieldMeterColor = "#333"; m.fieldMeterColor = "#333";
m.eyeFillColor = m.fieldMeterColor m.eyeFillColor = m.fieldMeterColor
// m.eyeFillColor = '#333'
m.fieldPhase = 0; m.fieldPhase = 0;
m.isCloak = false m.isCloak = false
// m.fieldDamage = 2.46 // 1 + 146/100
m.fieldDrawRadius = 0 m.fieldDrawRadius = 0
m.isSneakAttack = true; m.isSneakAttack = true;
// m.sneakAttackCharge = 0;
m.sneakAttackCycle = 0; m.sneakAttackCycle = 0;
m.enterCloakCycle = 0; m.enterCloakCycle = 0;
const drawRadius = 800
m.drawCloak = function() { m.drawCloak = function() {
m.fieldPhase += 0.007 m.fieldPhase += 0.007
const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5) const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5)
ctx.beginPath(); ctx.beginPath();
ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI); ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
// if (m.fireCDcycle > m.cycle && (input.field)) {}
ctx.fillStyle = "#fff" ctx.fillStyle = "#fff"
ctx.lineWidth = 2; ctx.lineWidth = 2;
ctx.strokeStyle = "#000" ctx.strokeStyle = "#000"
ctx.stroke() ctx.stroke()
// ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*m.energy})`;
ctx.globalCompositeOperation = "destination-in"; ctx.globalCompositeOperation = "destination-in";
ctx.fill(); ctx.fill();
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
ctx.clip(); ctx.clip();
} }
m.hold = function() { m.hold = function() {
// if (m.isCloak) {
// if (m.sneakAttackCharge < 120) m.sneakAttackCharge += 0.5
// } else {
// if (m.sneakAttackCharge > 0) m.sneakAttackCharge--
// }
if (m.isHolding) { if (m.isHolding) {
m.drawHold(m.holdingTarget); m.drawHold(m.holdingTarget);
m.holding(); m.holding();
@@ -2801,7 +2792,31 @@ const m = {
if (!m.isCloak) { if (!m.isCloak) {
m.isCloak = true //enter cloak m.isCloak = true //enter cloak
m.enterCloakCycle = m.cycle m.enterCloakCycle = m.cycle
// console.log(m.enterCloakCycle) if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy)
m.energy -= heal
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
radius: Math.sqrt(heal) * 200,
color: "rgba(0,255,200,0.6)",
time: 16
});
m.addHealth(heal); //heal from last hit
// if (tech.isEnergyHealth) {
// simulation.drawList.push({ //add dmg to draw queue
// x: m.pos.x,
// y: m.pos.y,
// radius: Math.sqrt(heal) * 200,
// color: "#0ad", //simulation.mobDmgColor
// time: 16
// });
// m.energy += heal
// } else {
// }
m.lastHit = 0
// simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(heal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
}
if (tech.isIntangible) { if (tech.isIntangible) {
for (let i = 0; i < bullet.length; i++) { for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType && bullet[i].botType !== "orbit") bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield if (bullet[i].botType && bullet[i].botType !== "orbit") bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield
@@ -2841,12 +2856,12 @@ const m = {
} }
} }
if (m.isCloak) { if (m.isCloak) {
this.fieldRange = this.fieldRange * 0.9 + 0.1 * drawRadius m.fieldRange = m.fieldRange * 0.9 + 80
m.fieldDrawRadius = this.fieldRange * 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy)); m.fieldDrawRadius = m.fieldRange * 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak() m.drawCloak()
} else if (this.fieldRange < 4000) { } else if (m.fieldRange < 4000) {
this.fieldRange += 50 m.fieldRange += 50
m.fieldDrawRadius = this.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy)); m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
m.drawCloak() m.drawCloak()
} }
if (tech.isIntangible) { if (tech.isIntangible) {

View File

@@ -980,7 +980,6 @@ const simulation = {
} }
if (tech.isQuantumEraser) { if (tech.isQuantumEraser) {
// tech.quantumEraserCount = 0
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isDropPowerUp && mob[i].alive) tech.quantumEraserCount++ if (mob[i].isDropPowerUp && mob[i].alive) tech.quantumEraserCount++
} }

View File

@@ -48,7 +48,13 @@ const spawn = {
}, },
quantumEraserCheck() { //remove mobs from tech: quantum eraser quantumEraserCheck() { //remove mobs from tech: quantum eraser
if (tech.isQuantumEraser && tech.quantumEraserCount > 0) { if (tech.isQuantumEraser && tech.quantumEraserCount > 0) {
for (let i = 0, len = mob.length; i < len; i++) {
//start at a random location in array
const randomMiddle = Math.floor(mob.length * Math.random())
let i = randomMiddle
for (let j = 0; j < mob.length; j++) {
i++
if (i > mob.length - 1) i = 0
if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss
if (mob[i].isFinalBoss) { if (mob[i].isFinalBoss) {
tech.quantumEraserCount = 0; tech.quantumEraserCount = 0;
@@ -86,6 +92,47 @@ const spawn = {
if (tech.quantumEraserCount < 1) break if (tech.quantumEraserCount < 1) break
} }
} }
// for (let i = 0, len = mob.length; i < len; i++) {
// if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss
// if (mob[i].isFinalBoss) {
// tech.quantumEraserCount = 0;
// return
// } else {
// tech.isQuantumEraserDuplication = true
// mob[i].death()
// tech.isQuantumEraserDuplication = false
// }
// //graphics
// const color = 'rgba(255,255,255, 0.8)'
// simulation.drawList.push({
// x: mob[i].position.x,
// y: mob[i].position.y,
// radius: mob[i].radius * 2,
// color: color, //"rgba(0,0,0,0.6)",
// time: 60
// });
// simulation.drawList.push({
// x: mob[i].position.x,
// y: mob[i].position.y,
// radius: mob[i].radius * 1,
// color: color, //"rgba(0,0,0,0.85)",
// time: 90
// });
// simulation.drawList.push({
// x: mob[i].position.x,
// y: mob[i].position.y,
// radius: mob[i].radius * 0.5,
// color: color, //"rgb(0,0,0)",
// time: 120
// });
// tech.quantumEraserCount--
// simulation.makeTextLog(`<span class='color-var'>tech</span>.quantumEraserCount <span class='color-symbol'>=</span> ${tech.quantumEraserCount}`)
// if (tech.quantumEraserCount < 1) break
// }
// }
} }
}, },
randomMob(x, y, chance = 1) { randomMob(x, y, chance = 1) {
@@ -2786,6 +2833,7 @@ const spawn = {
mobs.spawn(x, y, 3, radius, "rgb(0,235,255)"); mobs.spawn(x, y, 3, radius, "rgb(0,235,255)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
Matter.Body.rotate(me, Math.random() * Math.PI * 2); Matter.Body.rotate(me, Math.random() * Math.PI * 2);
@@ -2808,11 +2856,29 @@ const spawn = {
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
}; };
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.targetingCount = 0; me.targetingCount = 0;
me.targetingTime = 60 - Math.min(58, 3 * simulation.difficulty) me.targetingTime = 60 - Math.min(58, 3 * simulation.difficulty)
me.do = function() { me.do = function() {
// this.armor();
// //wings
// const wing = (simulation.cycle % 9) > 4 ? this.vertices[0] : this.vertices[2] //Vector.add(this.position, { x: 100, y: 0 })
// const radius = 200
// //draw
// ctx.beginPath();
// ctx.arc(wing.x, wing.y, radius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
// ctx.fillStyle = "rgba(0,235,255,0.3)";
// ctx.fill();
// //check damage
// const hitPlayer = Matter.Query.ray([player], this.position, wing, radius)
// if (hitPlayer.length && m.immuneCycle < m.cycle) {
// m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
// m.damage(0.02 * simulation.dmgScale);
// }
this.seePlayerByLookingAt(); this.seePlayerByLookingAt();
this.checkStatus(); this.checkStatus();
this.attraction(); this.attraction();
@@ -5566,7 +5632,7 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.accelMag = 0.0003 + 0.0002 * Math.sqrt(simulation.accelScale) me.accelMag = 0.0004 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250; me.memory = 250;
me.laserRange = 500; me.laserRange = 500;
Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
@@ -5576,13 +5642,12 @@ const spawn = {
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < mob.length; i++) { //wake up tail mobs me.onDeath = function() {
if (mob[i].isSnakeTail && mob[i].alive) { powerUps.spawnBossPowerUp(this.position.x, this.position.y)
mob[i].isSnakeTail = false; for (let i = 0, len = mob.length; i < len; i++) {
mob[i].do = mob[i].doActive if (this.id === mob[i].snakeHeadID && mob[i].alive) mob[i].death()
// mob[i].removeConsBB();
} }
} };
}; };
me.canFire = false; me.canFire = false;
me.closestVertex1 = 0; me.closestVertex1 = 0;
@@ -5660,7 +5725,7 @@ const spawn = {
spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20); spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20);
// mag -= 5 // mag -= 5
// spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20); // spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20);
if (i === 0) mob[mob.length - 1].snakeHeadID = me.id if (i < 3) mob[mob.length - 1].snakeHeadID = me.id
mob[mob.length - 1].previousTailID = previousTailID mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id previousTailID = mob[mob.length - 1].id
} }
@@ -5703,9 +5768,9 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.accelMag = 0.00045 + 0.0002 * Math.sqrt(simulation.accelScale) me.accelMag = 0.0009 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250; me.memory = 250;
me.laserRange = 500; me.laserRange = 400;
Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0 me.damageReduction = 0
@@ -5713,6 +5778,9 @@ const spawn = {
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0, len = mob.length; i < len; i++) {
if (this.id === mob[i].snakeHeadID && mob[i].alive) mob[i].death()
}
}; };
me.do = function() { me.do = function() {
this.seePlayerByHistory() this.seePlayerByHistory()
@@ -5738,7 +5806,7 @@ const spawn = {
angle -= 0.15 + i * 0.008 angle -= 0.15 + i * 0.008
mag -= (i < 2) ? -15 : 5 mag -= (i < 2) ? -15 : 5
spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20); spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20);
if (i === 0) mob[mob.length - 1].snakeHeadID = me.id if (i < 3) mob[mob.length - 1].snakeHeadID = me.id
mob[mob.length - 1].previousTailID = previousTailID mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id previousTailID = mob[mob.length - 1].id
} }
@@ -5775,11 +5843,13 @@ const spawn = {
mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)"); mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body
me.accelMag = 0.0007 * simulation.accelScale; me.damageReduction = 0.2
Matter.Body.setDensity(me, 0.005); //normal is 0.001
// me.accelMag = 0.0007 * simulation.accelScale;
me.leaveBody = Math.random() < 0.33 ? true : false; me.leaveBody = Math.random() < 0.33 ? true : false;
me.showHealthBar = false; me.showHealthBar = false;
me.isDropPowerUp = false; me.isDropPowerUp = false;
Matter.Body.setDensity(me, 0.005); //normal is 0.001
me.frictionAir = 0.015; me.frictionAir = 0.015;
me.isSnakeTail = true; me.isSnakeTail = true;
me.stroke = "transparent" me.stroke = "transparent"
@@ -5792,16 +5862,16 @@ const spawn = {
mob[i].damageReduction = mob[i].startingDamageReduction mob[i].damageReduction = mob[i].startingDamageReduction
} }
} }
}, 150); }, 500);
}; };
me.do = function() { me.do = function() {
this.checkStatus(); this.checkStatus();
}; };
me.doActive = function() { // me.doActive = function() {
this.checkStatus(); // this.checkStatus();
this.alwaysSeePlayer(); // this.alwaysSeePlayer();
this.attraction(); // this.attraction();
}; // };
}, },
tetherBoss(x, y, constraint, radius = 90) { tetherBoss(x, y, constraint, radius = 90) {
// constrained mob boss for the towers level // constrained mob boss for the towers level

View File

@@ -239,7 +239,6 @@ const tech = {
if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance()) if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
if (tech.isDamageForGuns) dmg *= 1 + 0.13 * b.inventory.length if (tech.isDamageForGuns) dmg *= 1 + 0.13 * b.inventory.length
if (tech.isLowHealthDmg) dmg *= 1 + Math.max(0, 1 - m.health) * 0.5 if (tech.isLowHealthDmg) dmg *= 1 + Math.max(0, 1 - m.health) * 0.5
if (tech.isHarmDamage && m.lastHarmCycle + 600 > m.cycle) dmg *= 3;
if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25 if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25
if (tech.isAcidDmg && m.health > 1) dmg *= 1.35; if (tech.isAcidDmg && m.health > 1) dmg *= 1.35;
if (tech.isRerollDamage) dmg *= 1 + 0.038 * powerUps.research.count if (tech.isRerollDamage) dmg *= 1 + 0.038 * powerUps.research.count
@@ -251,10 +250,10 @@ const tech = {
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2
if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165) if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165)
if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.6 if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.6
// if (m.isSneakAttack && m.cycle > m.lastKillCycle + 240) dmg *= tech.sneakAttackDmg
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= tech.sneakAttackDmg if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= tech.sneakAttackDmg
// if (m.isSneakAttack && m.sneakAttackCharge > 0) dmg *= tech.sneakAttackDmg
if (tech.isAxion && tech.isHarmMACHO) dmg *= 2 - m.harmReduction() if (tech.isAxion && tech.isHarmMACHO) dmg *= 2 - m.harmReduction()
if (tech.isHarmDamage && m.lastHarmCycle + 600 > m.cycle) dmg *= 3;
if (tech.isLastHitDamage && m.lastHit) dmg *= 1 + 5 * m.lastHit // if (!simulation.paused) m.lastHit = 0
return dmg * tech.slowFire * tech.aimDamage return dmg * tech.slowFire * tech.aimDamage
}, },
duplicationChance() { duplicationChance() {
@@ -2115,24 +2114,6 @@ const tech = {
tech.isHarmArmor = false; tech.isHarmArmor = false;
} }
}, },
// {
// name: "radiative equilibrium",
// description: "for <strong>10 seconds</strong> after receiving <strong class='color-defense'>defense</strong><br>increase <strong class='color-d'>damage</strong> by <strong>200%</strong>",
// maxCount: 1,
// count: 0,
// frequency: 1,
// frequencyDefault: 1,
// allowed() {
// return true
// },
// requires: "",
// effect() {
// tech.isHarmDamage = true;
// },
// remove() {
// tech.isHarmDamage = false;
// }
// },
{ {
name: "CPT symmetry", name: "CPT symmetry",
// description: "<strong>charge</strong>, <strong>parity</strong>, and <strong>time</strong> invert to undo <strong class='color-defense'>defense</strong><br><strong class='color-rewind'>rewind</strong> <strong>(1.5—5)</strong> seconds for <strong>(66—220)</strong> <strong class='color-f'>energy</strong>", // description: "<strong>charge</strong>, <strong>parity</strong>, and <strong>time</strong> invert to undo <strong class='color-defense'>defense</strong><br><strong class='color-rewind'>rewind</strong> <strong>(1.5—5)</strong> seconds for <strong>(66—220)</strong> <strong class='color-f'>energy</strong>",
@@ -2272,42 +2253,42 @@ const tech = {
} }
} }
}, },
{ // {
name: "weak interaction", // name: "weak interaction",
description: "for each unused <strong>power up</strong> at the end of a <strong>level</strong><br><strong>+10</strong> maximum <strong class='color-f'>energy</strong>", // <em>(up to 51 health per level)</em>", // description: "for each unused <strong>power up</strong> at the end of a <strong>level</strong><br><strong>+10</strong> maximum <strong class='color-f'>energy</strong>", // <em>(up to 51 health per level)</em>",
maxCount: 1, // maxCount: 1,
count: 0, // count: 0,
frequency: 1, // frequency: 1,
frequencyDefault: 1, // frequencyDefault: 1,
allowed() { // allowed() {
return !tech.isDroneGrab // return !tech.isDroneGrab
}, // },
requires: "not delivery drone", // requires: "not delivery drone",
effect() { // effect() {
tech.isExtraMaxEnergy = true; //tracked by tech.extraMaxHealth // tech.isExtraMaxEnergy = true; //tracked by tech.extraMaxHealth
}, // },
remove() { // remove() {
tech.isExtraMaxEnergy = false; // tech.isExtraMaxEnergy = false;
} // }
}, // },
{ // {
name: "electroweak interaction", // name: "electroweak interaction",
description: "unused <strong>power ups</strong> at the end of a <strong>level</strong><br>are still activated <em>(selections are random)</em>", // description: "unused <strong>power ups</strong> at the end of a <strong>level</strong><br>are still activated <em>(selections are random)</em>",
maxCount: 1, // maxCount: 1,
count: 0, // count: 0,
frequency: 2, // frequency: 2,
frequencyDefault: 2, // frequencyDefault: 2,
allowed() { // allowed() {
return tech.isExtraMaxEnergy // return tech.isExtraMaxEnergy
}, // },
requires: "weak interaction", // requires: "weak interaction",
effect() { // effect() {
tech.isEndLevelPowerUp = true; // tech.isEndLevelPowerUp = true;
}, // },
remove() { // remove() {
tech.isEndLevelPowerUp = false; // tech.isEndLevelPowerUp = false;
} // }
}, // },
{ {
name: "electronegativity", name: "electronegativity",
description: "<strong>+1%</strong> <strong class='color-d'>damage</strong> per <strong>8</strong> stored <strong class='color-f'>energy</strong>", description: "<strong>+1%</strong> <strong class='color-d'>damage</strong> per <strong>8</strong> stored <strong class='color-f'>energy</strong>",
@@ -4107,7 +4088,7 @@ const tech = {
{ {
name: "spin-statistics", name: "spin-statistics",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Spin%E2%80%93statistics_theorem' class="link">spin-statistics</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Spin%E2%80%93statistics_theorem' class="link">spin-statistics</a>`,
description: "<strong>invulnerable</strong> while firing the <strong>shotgun</strong><br>shotgun has <strong>50%</strong> fewer shots", description: "after firing the <strong>shotgun</strong> you are <strong>invulnerable</strong><br>shotgun has <strong>50%</strong> fewer shots",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -6665,8 +6646,8 @@ const tech = {
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 2,
frequencyDefault: 1, frequencyDefault: 2,
allowed() { allowed() {
return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" return m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass"
}, },
@@ -6678,6 +6659,26 @@ const tech = {
tech.isHarmDamage = false; tech.isHarmDamage = false;
} }
}, },
{
name: "dynamic equilibrium",
descriptionFunction() { return `increase <strong class='color-d'>damage</strong> by <strong>5%</strong><br>of your last ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"} loss` },
// description: `increase <strong class='color-d'>damage</strong> by <strong>500%</strong><br>of your last <strong class='color-h'>health</strong> loss`,
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "standing wave") && !tech.isCloakHealLastHit
},
requires: "negative mass, pilot wave, not patch",
effect() {
tech.isLastHitDamage = true;
},
remove() {
tech.isLastHitDamage = false;
}
},
{ {
name: "neutronium", name: "neutronium",
description: `<strong>move</strong> and <strong>jump</strong> <strong>25%</strong> <strong>slower</strong><br>if your <strong class='color-f'>field</strong> is active <strong>+90%</strong> <strong class='color-defense'>defense</strong>`, description: `<strong>move</strong> and <strong>jump</strong> <strong>25%</strong> <strong>slower</strong><br>if your <strong class='color-f'>field</strong> is active <strong>+90%</strong> <strong class='color-defense'>defense</strong>`,
@@ -7347,6 +7348,26 @@ const tech = {
} }
} }
}, },
{
name: "patch",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Patch_(computing)' class="link">patch</a>`,
description: "after <strong class='color-cloaked'>cloaking</strong> recover <strong>75%</strong> of your<br>last <strong class='color-h'>health</strong> loss using that much <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" && !tech.isLastHitDamage && !tech.isEnergyHealth
},
requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy",
effect() {
tech.isCloakHealLastHit = true;
},
remove() {
tech.isCloakHealLastHit = false;
}
},
{ {
name: "dazzler", name: "dazzler",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Dazzler_(weapon)' class="link">dazzler</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Dazzler_(weapon)' class="link">dazzler</a>`,
@@ -10528,5 +10549,7 @@ const tech = {
isLaserLens: null, isLaserLens: null,
laserCrit: null, laserCrit: null,
isSporeColony: null, isSporeColony: null,
isExtraBotOption: null isExtraBotOption: null,
isLastHitDamage: null,
isCloakHealLastHit: null
} }

View File

@@ -532,6 +532,8 @@ summary {
transition: opacity 0.25s; transition: opacity 0.25s;
pointer-events: none; pointer-events: none;
user-select: none; user-select: none;
/* white-space: pre;
font-family: 'Menlo', 'Monaco', monospace; */
} }
/* color for in game console output */ /* color for in game console output */

View File

@@ -1,43 +1,62 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
tech: electric generator - deflecting mobs generates energy for molecular assembler field tech: patch - after cloaking recover 75% of last health lost using that much energy
tech: homeostasis - for each health below 100 +0.8% defense taking damage now forces decloaking
tech: compound lens - +77% laser lens damage, +10° lens arc field tech: dynamic equilibrium - increase damage by 5% the value of your last health loss
tech: robotics - 2 random bots, power up choices include a bot tech option foam has less velocity after a mob it's stuck to dies
tech: open-source - 3 random bots, 4x bot tech frequency snakeBoss becomes vulnerable if you remove any of the first 3 body segments
renamed from previous robotics tech body segments have more health
slightly buffed all bot upgrades
+9% iceIX damage bug fix: quantum eraser now removes mobs in a more random order
catabolism uses energy instead of health if you have mass-energy it used to have a too low chance to remove bosses
optical amplifier laser tech options include laser-bot
rule 90 and rule 30 looks better on more browsers, I hope
*********************************************************** TODO ***************************************************** *********************************************************** TODO *****************************************************
labs room:
low gravity zone
a button that toggles it on/off
boss mechanics
bullets hit player and stay attached for 4-5 seconds, slowing player
hopperBullets?
black hole sucker effect on tail
flickering wings
draw pair of circles at 2 different locations, like beetle wings flapping
draw as ellipse
damage player if caught in wings
tech: ricochet after nails do damage, the nail fires at a different nearby mobs
can reuse some targeted nail code
don't target 'who' you just damaged
tech: You can place an extra perfect diamagnatism field on the map
standing wave no longer pushes mobs away, but it can do damage to mobs caught in area effect
negative mass field does damage to mobs inside field
combine with standing wave effect? pilot wave?
store value of last hit health lost store value of last hit health lost
names: patch
tech: after cloaking regen 1/2 of the last hit
spawning a heal power up is annoying because you'd be cloaked, so direct healing?
time limit for effect?
while still under ambush damage?
tech: killing the mob that caused the last hit spawns a heal power up equal to 1/2 of last hit tech: killing the mob that caused the last hit spawns a heal power up equal to 1/2 of last hit
time limit for effect? 3-4 seconds? time limit for effect?
need to also store who hit player
tech: doing damage can recover up to 1/2 of the last hit
spawn a heal equal to 1/2 of last hit
time limit for effect? 3-4 seconds?
tech increase damage by how much health was lost in last hit
+damage = 3x health lost?
if you went from 100 -> 60 health = +40%*3 = 120% damage
negative mass field tech?
too similar to radiative equilibrium
pick between them?
add small SVG pics to in-game console
when?
one for each field?
use stuff on physics notes:
simulation.makeTextLog(`
<svg class="SVG-title" width="160" height="120">
<g fill="transparent" stroke="#333" stroke-width="1" transform="translate(78,75)" stroke-linecap="round">
<path d="M-34 -34 l31 31 m6 6 l31 31 M34 -34 l-31 31 m-6 6 l-31 31"></path>
<ellipse cx="0" cy="35" rx="34.5" ry="7"/>
<ellipse cx="0" cy="-35" rx="34.5" ry="7"/>
<g stroke="none" fill="#333">
<circle cx="0" cy="0" r="1.5" />
</g>
</g>
</svg>
`);
path-finding path-finding
build a path-finding map on level load build a path-finding map on level load
@@ -49,12 +68,6 @@ path-finding
drones? drones?
bots that can go far from player and return bots that can go far from player and return
tech ______ effect that last until you get hit
field or bots can check your health every cycle and see if it lower
if it's high update the health check value
effect:
+damage until getting hit for cloaking field
make plasma ball power up and block pick up still work when you have no no energy make plasma ball power up and block pick up still work when you have no no energy
make a unique CD var for plasma ball? make a unique CD var for plasma ball?