diff --git a/.DS_Store b/.DS_Store
index 4469fa6..a18c0cc 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index ded5cbb..add0550 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -1519,6 +1519,7 @@ const b = {
if (input.fire && Matter.Query.collides(this, map).length) {
Matter.Body.setPosition(this, Vector.add(this.position, { x: 20 * Math.cos(this.angle), y: 20 * Math.sin(this.angle) }))
if (Matter.Query.collides(this, map).length) {
+ Matter.Body.setVelocity(this, { x: 0, y: 0 });
Matter.Sleeping.set(this, true)
this.endCycle = simulation.cycle + 5
this.dropCaughtPowerUp()
@@ -2605,7 +2606,7 @@ const b = {
},
worm(where, isFreeze = tech.isSporeFreeze) { //used with the tech upgrade in mob.death()
const bIndex = bullet.length;
- const wormSize = 6 + tech.wormSize * 7.2 * Math.random()
+ const wormSize = 6 + tech.wormSize * 7 * Math.random()
if (bIndex < 500) { //can't make over 500 spores
bullet[bIndex] = Bodies.polygon(where.x, where.y, 3, 3, {
inertia: Infinity,
@@ -2616,7 +2617,7 @@ const b = {
frictionAir: 0.025,
thrust: (tech.isFastSpores ? 0.001 : 0.0005) * (1 + 0.5 * (Math.random() - 0.5)),
wormSize: wormSize,
- wormTail: 1 + wormSize,
+ wormTail: 1 + Math.max(4, wormSize - 2 * tech.wormSize),
dmg: (tech.isMutualism ? 7 : 2.9) * wormSize, //bonus damage from tech.isMutualism //2.5 is extra damage as worm
lookFrequency: 100 + Math.floor(37 * Math.random()),
classType: "bullet",
@@ -3329,6 +3330,165 @@ const b = {
y: speed * Math.sin(dir)
});
},
+ // plasmaBall(position, velocity, radius) {
+ // // radius *= Math.sqrt(tech.bulletSize)
+ // const me = bullet.length;
+ // bullet[me] = Bodies.polygon(position.x, position.y, 20, radius, {
+ // density: 0.000001, // 0.001 is normal density
+ // inertia: Infinity,
+ // frictionAir: 0.003,
+ // dmg: 0, //damage on impact
+ // damage: 0, //damage done over time
+ // scale: 1 - 0.006 / tech.isBulletsLastLonger,
+ // classType: "bullet",
+ // collisionFilter: {
+ // category: cat.bullet,
+ // mask: 0 //cat.mob | cat.mobBullet // cat.map | cat.body | cat.mob | cat.mobShield
+ // },
+ // minDmgSpeed: 0,
+ // endCycle: Infinity,
+ // count: 0,
+ // radius: radius,
+ // portFrequency: 5 + Math.floor(5 * Math.random()),
+ // nextPortCycle: Infinity, //disabled unless you have the teleport tech
+ // beforeDmg(who) {
+ // if (!this.target && who.alive) {
+ // this.target = who;
+ // if (who.radius < 20) {
+ // this.targetRelativePosition = {
+ // x: 0,
+ // y: 0
+ // } //find relative position vector for zero mob rotation
+ // } else if (Matter.Query.collides(this, [who]).length > 0) {
+ // const normal = Matter.Query.collides(this, [who])[0].normal
+ // this.targetRelativePosition = Vector.rotate(Vector.sub(Vector.sub(this.position, who.position), Vector.mult(normal, -this.radius)), -who.angle) //find relative position vector for zero mob rotation
+ // } else {
+ // this.targetRelativePosition = Vector.rotate(Vector.sub(this.position, who.position), -who.angle) //find relative position vector for zero mob rotation
+ // }
+ // this.collisionFilter.category = cat.body;
+ // this.collisionFilter.mask = null;
+
+ // let bestVertexDistance = Infinity
+ // let bestVertex = null
+ // for (let i = 0; i < this.target.vertices.length; i++) {
+ // const dist = Vector.magnitude(Vector.sub(this.position, this.target.vertices[i]));
+ // if (dist < bestVertexDistance) {
+ // bestVertex = i
+ // bestVertexDistance = dist
+ // }
+ // }
+ // this.targetVertex = bestVertex
+ // }
+ // },
+ // onEnd() {},
+ // do() {
+ // if (this.count < 20) {
+ // this.count++
+ // //grow
+ // const SCALE = 1.06
+ // Matter.Body.scale(this, SCALE, SCALE);
+ // this.radius *= SCALE;
+ // } else {
+ // //shrink
+ // Matter.Body.scale(this, this.scale, this.scale);
+ // this.radius *= this.scale;
+ // if (this.radius < 8) this.endCycle = 0;
+ // }
+ // if (this.target && this.target.alive) { //if stuck to a target
+ // const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector
+ // if (this.target.isVerticesChange) {
+ // Matter.Body.setPosition(this, this.target.vertices[this.targetVertex])
+ // } else {
+ // Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.target.velocity), this.target.position))
+ // }
+ // if (this.target.isBoss) {
+ // if (this.target.speed > 8) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.98))
+ // } else {
+ // if (this.target.speed > 4) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.95))
+ // }
+
+ // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9);
+ // // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9)
+ // if (this.target.isShielded) {
+ // this.target.damage(m.dmgScale * this.damage, true); //shield damage bypass
+ // const SCALE = 1 - 0.004 / tech.isBulletsLastLonger //shrink if mob is shielded
+ // Matter.Body.scale(this, SCALE, SCALE);
+ // this.radius *= SCALE;
+ // } else {
+ // this.target.damage(m.dmgScale * this.damage);
+ // }
+ // } else if (this.target !== null) { //look for a new target
+ // this.collisionFilter.category = cat.bullet;
+ // this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
+ // if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) {
+ // let targets = []
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
+ // if (dist < 1000000) targets.push(mob[i])
+ // }
+ // const radius = Math.min(this.radius * 0.5, 9)
+ // const len = bullet.length < 80 ? 2 : 1
+ // for (let i = 0; i < len; i++) {
+ // if (targets.length - i > 0) {
+ // const index = Math.floor(Math.random() * targets.length)
+ // const speed = 6 + 6 * Math.random()
+ // const velocity = Vector.mult(Vector.normalise(Vector.sub(targets[index].position, this.position)), speed)
+ // b.foam(this.position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius)
+ // } else {
+ // b.foam(this.position, Vector.rotate({
+ // x: 15 + 10 * Math.random(),
+ // y: 0
+ // }, 2 * Math.PI * Math.random()), radius)
+ // }
+ // }
+ // }
+ // this.target = null
+ // } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map or blocks
+ // const slow = 0.85
+ // Matter.Body.setVelocity(this, {
+ // x: this.velocity.x * slow,
+ // y: this.velocity.y * slow
+ // });
+ // const SCALE = 0.96
+ // Matter.Body.scale(this, SCALE, SCALE);
+ // this.radius *= SCALE;
+ // // } else if (Matter.Query.collides(this, body).length > 0) {
+ // } else if (Matter.Query.point(body, this.position).length > 0) {
+ // const slow = 0.9
+ // Matter.Body.setVelocity(this, {
+ // x: this.velocity.x * slow,
+ // y: this.velocity.y * slow
+ // });
+ // const SCALE = 0.96
+ // Matter.Body.scale(this, SCALE, SCALE);
+ // this.radius *= SCALE;
+ // } else {
+ // this.force.y += this.mass * tech.foamGravity; //gravity
+ // if (tech.isFoamAttract) {
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (!mob[i].isBadTarget && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
+ // this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004)
+ // const slow = 0.9
+ // Matter.Body.setVelocity(this, {
+ // x: this.velocity.x * slow,
+ // y: this.velocity.y * slow
+ // });
+ // break
+ // }
+ // }
+ // }
+ // }
+ // if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isBulletTeleport
+ // this.nextPortCycle = simulation.cycle + this.portFrequency
+ // const range = 15 * Math.sqrt(this.radius) * Math.random()
+ // Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random())))
+ // }
+ // }
+ // });
+ // if (tech.isBulletTeleport) bullet[me].nextPortCycle = simulation.cycle + bullet[me].portFrequency
+ // Composite.add(engine.world, bullet[me]); //add bullet to world
+ // Matter.Body.setVelocity(bullet[me], velocity);
+ // },
foam(position, velocity, radius) {
// radius *= Math.sqrt(tech.bulletSize)
const me = bullet.length;
diff --git a/js/engine.js b/js/engine.js
index 7a5490c..d63bb82 100644
--- a/js/engine.js
+++ b/js/engine.js
@@ -188,7 +188,7 @@ function collisionChecks(event) {
time: simulation.drawTime
});
}
- if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? 1.01 : 1.06
+ if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? 1.005 : 1.05
return;
}
//mob + body collisions
diff --git a/js/index.js b/js/index.js
index 071c08b..4be212f 100644
--- a/js/index.js
+++ b/js/index.js
@@ -326,7 +326,7 @@ ${simulation.isCheating ? "
lore disabled": ""}
${tech.tech[i].link} ${techCountText}${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}`
} else if (tech.tech[i].isLore) {
- text += `
${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
`
+ text += ` ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
`
} else {
text += ` ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
`
}
@@ -379,7 +379,7 @@ ${simulation.isCheating ? "
lore disabled": ""}
if (!who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected");
tech.giveTech(index)
} else if (!tech.tech[index].isNonRefundable) {
- tech.totalCount -= tech.tech[index].count
+ // tech.totalCount -= tech.tech[index].count
tech.removeTech(index);
who.classList.remove("build-tech-selected");
} else {
diff --git a/js/level.js b/js/level.js
index 38f2131..da8a2f1 100644
--- a/js/level.js
+++ b/js/level.js
@@ -15,35 +15,35 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.isHorizontalFlipped = true
- // m.setField("molecular assembler")
- // b.giveGuns("drones")
- // tech.giveTech("autonomous navigation")
- // tech.giveTech("delivery drone")
- // tech.giveTech("dynamo-bot upgrade")
+ // m.setField("metamaterial cloaking")
+ // b.giveGuns("harpoon")
+ // tech.giveTech("grappling hook")
+ // tech.giveTech("bulk modulus")
// for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech");
// for (let i = 0; i < 9; i++) tech.giveTech("dynamo-bot")
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
// powerUps.research.changeRerolls(100000)
- // for (let i = 0; i < 2; i++) tech.giveTech("laser-bot")
+ // for (let i = 0; i < 2; i++) tech.giveTech("undefined")
// tech.tech[297].frequency = 100
+ // m.setField("plasma torch")
+ // tech.giveTech("plasma ball")
// m.immuneCycle = Infinity //you can't take damage
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// simulation.enableConstructMode() //used to build maps in testing mode
// level.reactor();
- // level.testing(); //not in rotation, used for testing
- // level.perplex()
- if (simulation.isTraining) { level.walk(); } else { level.intro(); }
-
+ // level.pavilion(); //not in rotation, used for testing
+ if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************
// powerUps.research.changeRerolls(3000)
// for (let i = 0; i < 30; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false);
// for (let i = 0; i < 3; i++) tech.giveTech("undefined")
// lore.techCount = 3
// simulation.isCheating = false //true;
- // localSettings.loreCount = 2; //this sets what conversation is heard
+ // localSettings.loreCount = 0; //this sets what conversation is heard
// 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.null()
+
// lore.unlockTesting();
// tech.giveTech("tinker"); //show junk tech in experiment mode
} else {
@@ -113,6 +113,9 @@ const level = {
for (let i = 0; i < 2; i++) powerUps.spawn(level.exit.x + 10 * (Math.random() - 0.5), level.exit.y - 100 + 10 * (Math.random() - 0.5), "tech", false) //exit
// for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "tech", false); //start
}
+ if (m.plasmaBall) {
+ m.plasmaBall.isOn = false
+ }
},
trainingText(say) {
simulation.lastLogTime = 0; //clear previous messages
@@ -130,7 +133,7 @@ const level = {
simulation.accelScale = 1 //mob acceleration increases each level
simulation.CDScale = 1 //mob CD time decreases each level
simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels
- simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
+ simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
},
difficultyIncrease(num = 1) {
for (let i = 0; i < num; i++) {
@@ -140,7 +143,7 @@ const level = {
if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level
}
simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels
- simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
+ simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
// console.log(`CD = ${simulation.CDScale}`)
},
difficultyDecrease(num = 1) { //used in easy mode for simulation.reset()
@@ -151,8 +154,8 @@ const level = {
if (simulation.CDScale < 1) simulation.CDScale /= 0.965 //mob CD time decreases each level
}
if (simulation.difficulty < 1) simulation.difficulty = 0;
- simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels
- simulation.healScale = 1 / (1 + simulation.difficulty * 0.055)
+ simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels
+ simulation.healScale = 1 / (1 + simulation.difficulty * 0.052)
},
difficultyText() {
if (simulation.difficultyMode === 1) {
@@ -836,7 +839,7 @@ const level = {
// const block = body[body.length] = Bodies.rectangle(x, y, width, height, {
collisionFilter: {
category: cat.map,
- mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp // | cat.mob | cat.mobBullet
},
isNoSetCollision: true,
inertia: Infinity, //prevents rotation
@@ -3173,9 +3176,12 @@ const level = {
//right
spawn.mapVertex(425 + 437, -50, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80");
spawn.mapRect(325, -100, 1070, 100);
- spawn.mapRect(225, 675, 375, 25);
- spawn.mapRect(675, 450, 375, 25);
- spawn.mapRect(1125, 225, 375, 25);
+ // spawn.mapRect(225, 675, 375, 25);
+ // spawn.mapRect(675, 450, 375, 25);
+ // spawn.mapRect(1125, 225, 375, 25);
+ spawn.mapRect(175, 675, 425, 25);
+ spawn.mapRect(1125, 225, 425, 25);
+ spawn.mapRect(650, 450, 425, 25);
if (Math.random() < 0.33) {
spawn.mapVertex(855, -1000, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300");
@@ -3190,12 +3196,19 @@ const level = {
spawn.mapVertex(-687, -1936, "-612 50 0 100 612 50 612 -50 -612 -50");
//2nd floor right building
- spawn.mapRect(550, -3050, 600, 175);
+ // spawn.mapRect(550, -3050, 600, 175);
+ spawn.mapRect(550, -3050, 600, 75);
spawn.bodyRect(-125, -2025, 475, 25);
//2nd floor left building
- spawn.mapRect(-925, -2350, 675, 200);
- spawn.mapRect(-825, -2825, 425, 275);
+ // if (Math.random() > 0.5) {
+ // spawn.mapRect(-925, -2350, 675, 200);
+ // } else {
+ // }
+
+ spawn.mapRect(-925, -2350, 675, 50);
+ spawn.mapRect(-825, -2825, 425, 50);
+ // spawn.mapRect(-825, -2825, 425, 275);
spawn.mapRect(-450, -3125, 50, 350);
spawn.mapRect(-750, -3150, 350, 50);
spawn.mapRect(-650, -3400, 250, 300);
@@ -3203,8 +3216,11 @@ const level = {
spawn.bodyRect(-375, -2150, 100, 150, 0.2);
//2nd floor left pillar
spawn.mapRect(-1400, -2625, 325, 25);
- spawn.mapRect(-1400, -3225, 325, 25);
- spawn.mapRect(-1400, -3825, 325, 25);
+ spawn.mapRect(-1450, -3225, 425, 25);
+ // spawn.mapRect(-1500, -3825, 525, 25);
+ spawn.mapRect(-1512.5, -3825, 550, 25);
+ // spawn.mapRect(-1400, -3225, 325, 25);
+ // spawn.mapRect(-1400, -3825, 325, 25);
spawn.randomMob(1000, -275, 0.2);
spawn.randomMob(950, -1725, 0.1);
@@ -3231,7 +3247,7 @@ const level = {
slime.min.y += slime.maxHeight
slime.max.y = slime.min.y + slime.height
const elevator1 = level.elevator(-1625, -90, 310, 800, -2000, 0.0025, { up: 0.1, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
- const elevator2 = level.elevator(1175, -3050, 200, 300, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ const elevator2 = level.elevator(1175, -3050, 200, 250, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
let waterFallWidth = 0
let waterFallX = 0
let waterFallSmoothX = 0
@@ -3242,10 +3258,10 @@ const level = {
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// m.immuneCycle = Infinity //you can't take damage
- simulation.isHorizontalFlipped = true
+ // simulation.isHorizontalFlipped = true
if (simulation.isHorizontalFlipped) { //flip the map horizontally
- spawn.mapVertex(584, -2435, "0 0 300 0 150 600 0 600");
- spawn.mapVertex(1116, -2435, "0 0 300 0 300 600 150 600");
+ spawn.mapVertex(584, -2500, "0 0 300 0 150 600 0 600");
+ spawn.mapVertex(1116, -2500, "0 0 300 0 300 600 150 600");
spawn.bodyRect(-200, -125, 625, 25);
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3255,7 +3271,7 @@ const level = {
spinnerArray.push(level.spinner(-110, -3325, 45, 600, 0.003, 0, 0, 0.01)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) {
- const boost1 = level.boost(-900, -2000, 700)
+ const boost1 = level.boost(-900, -2000, 790)
level.setPosToSpawn(500, 850); //normal spawn
level.custom = () => {
ctx.fillStyle = "#c0c3c9" ///!!!!!!!!!! for flipped x: newX = -oldX - width
@@ -3287,11 +3303,11 @@ const level = {
ctx.fill();
//shadow
ctx.fillStyle = "rgba(0,10,30,0.1)"
- ctx.fillRect(-1150, -2900, 600, 925);
+ ctx.fillRect(-1150, -3000, 600, 1025);
ctx.fillRect(450, -3100, 300, 275);
ctx.fillRect(450, -3625, 200, 225);
- ctx.fillRect(400, -2575, 425, 325);
- ctx.fillRect(250, -2150, 675, 150);
+ ctx.fillRect(400, -2775, 425, 450);
+ ctx.fillRect(250, -2300, 675, 300);
slime.query();
if (isWaterfallFilling) {
@@ -3319,6 +3335,8 @@ const level = {
}
};
} else { //not flipped
+ spawn.mapVertex(1116, -2500, "0 0 300 0 150 600 0 600");
+ spawn.mapVertex(584, -2500, "0 0 300 0 300 600 150 600");
if (Math.random() < 0.33) {
spinnerArray.push(level.spinner(65, -300, 40, 450, 0.003, Math.PI / 2))
@@ -3336,7 +3354,7 @@ const level = {
Matter.Body.setVertices(spinnerArray[spinnerArray.length - 1].bodyB, Vertices.fromPath(hexagon))
}
- const boost1 = level.boost(800, -2000, 700)
+ const boost1 = level.boost(800, -2000, 790)
level.custom = () => {
ctx.fillStyle = "#c0c3c9"
@@ -3346,7 +3364,6 @@ const level = {
ctx.fillStyle = "#d0d4d6"
ctx.fillRect(-1100, -1925, 825, 2925) //large pillar background
ctx.fillRect(450, -1925, 825, 2925) //large pillar background
-
ctx.fillStyle = "#cff" //exit
ctx.fillRect(1475, -4900, 525, 425)
level.exit.drawAndCheck();
@@ -3369,11 +3386,11 @@ const level = {
ctx.fill();
//shadow
ctx.fillStyle = "rgba(0,10,30,0.1)"
- ctx.fillRect(550, -2900, 600, 925);
+ ctx.fillRect(550, -3000, 600, 1025);
ctx.fillRect(-750, -3100, 300, 275);
ctx.fillRect(-650, -3625, 200, 225);
- ctx.fillRect(-825, -2575, 425, 325);
- ctx.fillRect(-925, -2150, 675, 150);
+ ctx.fillRect(-825, -2775, 425, 450);
+ ctx.fillRect(-925, -2300, 675, 300);
slime.query();
if (isWaterfallFilling) {
@@ -6019,10 +6036,10 @@ const level = {
const balance = level.spinner(5500, -412.5, 25, 660) //entrance
const rotor = level.rotor(7000, 580, -0.001);
const doorSortieSalle = level.door(8590, -520, 20, 800, 750)
- let buttonSortieSalle
- let portalEnBas
+ // let buttonSortieSalle
+ // let portalEnBas
let portalEnHaut
- let door3isClosing = false;
+ // let door3isClosing = false;
function drawOnTheMapMapRect(x, y, dx, dy) {
spawn.mapRect(x, y, dx, dy);
diff --git a/js/player.js b/js/player.js
index 9306255..ca03267 100644
--- a/js/player.js
+++ b/js/player.js
@@ -34,9 +34,9 @@ const m = {
category: cat.player,
mask: cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield
},
- death() {
- m.death();
- }
+ // death() {
+ // m.death();
+ // }
});
Matter.Body.setMass(player, m.mass);
Composite.add(engine.world, [player]);
@@ -2085,7 +2085,126 @@ const m = {
description: "use energy to emit short range plasma
damages and pushes mobs away",
set() {
b.isExtruderOn = false
- if (tech.isExtruder) {
+ if (m.plasmaBall) {
+ m.plasmaBall.isOn = false
+ Matter.Composite.remove(engine.world, m.plasmaBall);
+ }
+ if (tech.isPlasmaBall) {
+ // m.plasmaBall = {
+ // position: { x: m.pos.x + 10 * Math.cos(m.angle), y: m.pos.y + 10 * Math.sin(m.angle) },
+ // velocity: { x: 0, y: 0 },
+ // radius: 1,
+ // }
+
+ m.plasmaBall = Bodies.circle(m.pos.x + 10 * Math.cos(m.angle), m.pos.y + 10 * Math.sin(m.angle), 1, {
+ collisionFilter: {
+ group: 0,
+ category: 0,
+ mask: 0 //cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield
+ },
+ frictionAir: 0,
+ // radius: 1,
+ // friction: 0,
+ // frictionStatic: 0,
+ // restitution: 0,
+ alpha: 0.6,
+ isAttached: false,
+ isOn: false,
+ drain: 0.0012,
+ radiusLimit: 10,
+ damage: 0.18,
+ setPositionToNose() {
+ 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)), this.circleRadius)));
+ },
+ fire() {
+ this.isAttached = false;
+ const speed = 4 //scale with mass?
+ Matter.Body.setVelocity(this, {
+ x: 0.4 * player.velocity.x + speed * Math.cos(m.angle),
+ y: 0.2 * player.velocity.y + speed * Math.sin(m.angle)
+ });
+ },
+ do() {
+ if (this.isOn) {
+ //collisions with map
+ if (Matter.Query.collides(this, map).length > 0) {
+ const scale = Math.max(0.7, 0.99 - 1 / m.plasmaBall.circleRadius)
+ Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast
+ if (m.plasmaBall.circleRadius < m.plasmaBall.radiusLimit) this.isOn = false
+ }
+ //collisions with mobs
+ const whom = Matter.Query.collides(this, mob)
+ const dmg = this.damage * m.dmgScale
+ for (let i = 0, len = whom.length; i < len; i++) {
+ if (whom[i].bodyA.alive) whom[i].bodyA.damage(dmg);
+ if (whom[i].bodyB.alive) whom[i].bodyB.damage(dmg);
+ }
+
+
+
+ //graphics
+ var gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, this.circleRadius);
+ gradient.addColorStop(0, `rgba(255,255,255,${this.alpha})`);
+ gradient.addColorStop(0.2, `rgba(255,200,255,${this.alpha})`);
+ gradient.addColorStop(1, `rgba(255,0,255,${this.alpha})`);
+ ctx.fillStyle = gradient
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.circleRadius, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ },
+ });
+ Composite.add(engine.world, m.plasmaBall);
+
+ m.hold = function() {
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ m.grabPowerUp();
+ m.lookForPickUp();
+
+ //field is active
+ if (!m.plasmaBall.isAttached) { //return ball to player
+ const scale = 0.7
+ Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast
+ if (m.plasmaBall.circleRadius < m.plasmaBall.radiusLimit) {
+ m.plasmaBall.isAttached = true
+ m.plasmaBall.isOn = true
+ m.plasmaBall.setPositionToNose()
+ }
+ } else if (m.energy > m.plasmaBall.drain) { //charge up when attached
+ m.energy -= m.plasmaBall.drain;
+ const scale = 1 + 5 * Math.pow(Math.max(1, m.plasmaBall.circleRadius), -1.5)
+ Matter.Body.scale(m.plasmaBall, scale, scale); //grow
+ m.plasmaBall.setPositionToNose()
+
+ //add friction for player when holding ball, maybe more friction in vertical
+
+
+ } else {
+ m.fieldCDcycle = m.cycle + 90;
+ m.plasmaBall.fire()
+ }
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ if (m.plasmaBall.isAttached) {
+ m.fieldCDcycle = m.cycle + 30;
+ m.plasmaBall.fire()
+ }
+ }
+ m.drawFieldMeter("rgba(0, 0, 0, 0.2)")
+
+ m.plasmaBall.do()
+ }
+
+
+
+ } else if (tech.isExtruder) {
m.hold = function() {
b.isExtruderOn = false
if (m.isHolding) {
diff --git a/js/simulation.js b/js/simulation.js
index 8fdcf1b..4e980d4 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -821,7 +821,7 @@ const simulation = {
level.zones = [];
simulation.drawList = [];
- if (tech.isDronesTravel) {
+ if (tech.isDronesTravel && player.alive) {
//count drones
let count = 0
let deliveryCount = 0
@@ -945,7 +945,7 @@ const simulation = {
}
}
- if (m.pos.y > simulation.fallHeight) { // if 4000px deep
+ if (m.pos.y > simulation.fallHeight || isNaN(player.position.x)) { // if 4000px deep
Matter.Body.setVelocity(player, {
x: 0,
y: 0
diff --git a/js/spawn.js b/js/spawn.js
index 84a05e9..5e4e4b6 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -3747,7 +3747,7 @@ const spawn = {
if (this.countDown-- < 0) { //explode
this.death();
//hit player
- if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange) {
+ if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange && m.immuneCycle < m.cycle) {
m.damage(0.01 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1));
m.energy -= 0.1 * (tech.isRadioactiveResistance ? 0.25 : 1)
if (m.energy < 0) m.energy = 0
diff --git a/js/tech.js b/js/tech.js
index 37b91cf..7bd62cd 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -58,6 +58,7 @@ const tech = {
simulation.makeTextLog(`tech.removeTech("${tech.tech[index].name}")`)
tech.tech[index].remove();
tech.tech[index].count = 0;
+ tech.totalCount -= totalRemoved
simulation.updateTechHUD();
tech.tech[index].isLost = true
simulation.updateTechHUD();
@@ -211,7 +212,7 @@ const tech = {
},
damageFromTech() {
let dmg = 1 //m.fieldDamage
- if (tech.isTechDebt) dmg *= 4 - 0.1 * tech.totalCount
+ if (tech.isTechDebt) dmg *= 4 - 0.08 * tech.totalCount
if (tech.isAxion && tech.isHarmMACHO) dmg *= 1 + 0.75 * (1 - m.harmReduction())
if (tech.OccamDamage) dmg *= tech.OccamDamage
if (tech.isCloakingDamage) dmg *= 1.35
@@ -370,7 +371,7 @@ const tech = {
if (gunTechPool.length) {
const index = Math.floor(Math.random() * gunTechPool.length)
tech.giveTech(gunTechPool[index]) // choose from the gun pool
- tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under pure science
+ tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under paradigm shift
simulation.makeTextLog(`tech.giveTech("${tech.tech[gunTechPool[index]].name}")`)
}
}
@@ -747,7 +748,7 @@ const tech = {
},
{
name: "regression",
- description: "bullet collisions increase vulnerability to
damage by 6% for mobs (1% for bosses)",
+ description: "bullet collisions increase vulnerability to
damage by 5% for mobs (0.5% for bosses)",
maxCount: 1,
count: 0,
frequency: 1,
@@ -1620,7 +1621,7 @@ const tech = {
},
{
name: "Pauli exclusion",
- description: `after receiving harm from a collision become
immune to harm for 1.5 extra seconds`,
+ description: `after receiving harm from a collision become
immune to harm for 2.5 extra seconds`,
maxCount: 9,
count: 0,
frequency: 1,
@@ -1628,7 +1629,7 @@ const tech = {
allowed() { return true },
requires: "",
effect() {
- tech.collisionImmuneCycles += 90;
+ tech.collisionImmuneCycles += 150;
if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
},
remove() {
@@ -1637,7 +1638,7 @@ const tech = {
},
{
name: "spin–statistics theorem",
- description: `become immune to harm for 1.9 seconds
once every 7 seconds`,
+ description: `become immune to harm for 1.75 seconds
once every 7 seconds`,
maxCount: 3,
count: 0,
frequency: 1,
@@ -1647,7 +1648,7 @@ const tech = {
},
requires: "",
effect() {
- tech.cyclicImmunity += 114;
+ tech.cyclicImmunity += 105;
},
remove() {
tech.cyclicImmunity = 0;
@@ -3068,7 +3069,7 @@ const tech = {
}
},
{
- name: "pure science",
+ name: "paradigm shift",
description: `clicking tech while paused ejects them
4% chance to convert that tech into ${powerUps.orb.research(1)}`,
maxCount: 1,
count: 0,
@@ -3088,7 +3089,7 @@ const tech = {
// description: `increase damage by 300% minus 10% for tech you have learned(${4 - 0.1 * tech.totalCount})`,
// description: `increase damage by 300%, but reduce damage
by 10% for tech you have learned`,
descriptionFunction() {
- return `increase damage by 300% minus 10%
for tech you have learned (${Math.floor(100*(4 - 0.1 * tech.totalCount))-100}%)`
+ return `increase damage by 300% minus 8%
for tech you have learned (${Math.floor(100*(4 - 0.08 * tech.totalCount))-100}%)`
},
maxCount: 1,
count: 0,
@@ -3704,7 +3705,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
- return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals
+ return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals && !tech.isIceShot
},
requires: "nail gun, shotgun, not ice crystal, rivets, rotary cannon, or pneumatic, incendiary, nail-shot, rivets, foam-shot, worm-shot, ice-shot",
effect() {
@@ -3743,7 +3744,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
- return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isNeedles && !tech.isIceCrystals
+ return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isNeedles && !tech.isIceCrystals && !tech.isIceShot
},
requires: "nail gun shot gun, not ice crystal, needles, or pneumatic actuator",
effect() {
@@ -5004,7 +5005,7 @@ const tech = {
name: "annelids",
description: "increase worm size and damage
between 10% and 120%",
isGunTech: true,
- maxCount: 9,
+ maxCount: 3,
count: 0,
frequency: 3,
frequencyDefault: 3,
@@ -6445,7 +6446,7 @@ const tech = {
frequency: 3,
frequencyDefault: 3,
allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
+ return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
},
requires: "molecular assembler, no other manufacturing, no drone tech",
effect() {
@@ -6472,7 +6473,7 @@ const tech = {
frequency: 3,
frequencyDefault: 3,
allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
+ return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
},
requires: "molecular assembler, no other manufacturing, no drone tech",
effect() {
@@ -6499,7 +6500,7 @@ const tech = {
frequency: 3,
frequencyDefault: 3,
allowed() {
- return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
+ return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
},
requires: "molecular assembler, no other manufacturing, no drone tech",
effect() {
@@ -6635,6 +6636,27 @@ const tech = {
if (this.count > 0) powerUps.research.changeRerolls(this.count * 2)
}
},
+ {
+ name: "plasma ball",
+ description: "charge up a ball of plasma and fire it",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isExtruder
+ },
+ requires: "plasma torch, not extruder",
+ effect() {
+ tech.isPlasmaBall = true;
+ m.fieldUpgrades[m.fieldMode].set()
+ },
+ remove() {
+ tech.isPlasmaBall = false;
+ if (this.count) m.fieldUpgrades[m.fieldMode].set()
+ }
+ },
{
name: "extruder",
description: "plasma torch extrudes a thin hot wire
increases damage and energy drain",
@@ -6644,9 +6666,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
- return m.fieldUpgrades[m.fieldMode].name === "plasma torch"
+ return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall
},
- requires: "plasma torch",
+ requires: "plasma torch, not plasma ball",
effect() {
tech.isExtruder = true;
m.fieldUpgrades[m.fieldMode].set()
@@ -7642,54 +7664,6 @@ const tech = {
if (this.count) m.look = m.lookDefault
}
},
- {
- name: "Mech v4.48",
- description: `open a portal to a primordial version of reality`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() { return true },
- requires: "",
- effect() {
- window.open('https://scratch.mit.edu/projects/14005697/fullscreen/', '_blank')
- },
- remove() {}
- },
- {
- name: "planetesimals",
- description: `play planetesimals (an asteroids-like game)
clear levels in planetesimals to spawn tech
if you die in planetesimals you die in n-gon`,
- maxCount: 1,
- count: 0,
- frequency: 0,
- isNonRefundable: true,
- isJunk: true,
- allowed() { return true },
- requires: "",
- effect() {
- window.open('../../planetesimals/index.html', '_blank')
- // powerUps.spawn(m.pos.x, m.pos.y, "tech");
-
- // for communicating to other tabs, like planetesimals
- // Connection to a broadcast channel
- const bc = new BroadcastChannel('planetesimals');
- bc.activated = false
-
- bc.onmessage = function(ev) {
- if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
- if (ev.data === 'death') {
- m.death()
- bc.close(); //end session
- }
- if (ev.data === 'ready' && !bc.activated) {
- bc.activated = true //prevents n-gon from activating multiple copies of planetesimals
- bc.postMessage("activate");
- }
- }
- },
- remove() {}
- },
{
name: "facsimile",
description: `inserts a copy of your current level into the level list`,
@@ -9165,6 +9139,54 @@ const tech = {
},
remove() {}
},
+ {
+ name: "Mech v4.48",
+ description: `open a portal to a primordial version of reality`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ window.open('https://scratch.mit.edu/projects/14005697/fullscreen/', '_blank')
+ },
+ remove() {}
+ },
+ {
+ name: "planetesimals",
+ description: `play planetesimals (an asteroids-like game)
clear levels in planetesimals to spawn tech
if you die in planetesimals you die in n-gon`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ window.open('../../planetesimals/index.html', '_blank')
+ // powerUps.spawn(m.pos.x, m.pos.y, "tech");
+
+ // for communicating to other tabs, like planetesimals
+ // Connection to a broadcast channel
+ const bc = new BroadcastChannel('planetesimals');
+ bc.activated = false
+
+ bc.onmessage = function(ev) {
+ if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ if (ev.data === 'death') {
+ m.death()
+ bc.close(); //end session
+ }
+ if (ev.data === 'ready' && !bc.activated) {
+ bc.activated = true //prevents n-gon from activating multiple copies of planetesimals
+ bc.postMessage("activate");
+ }
+ }
+ },
+ remove() {}
+ },
//**************************************************
//************************************************** undefined / lore
//************************************************** tech
@@ -9537,5 +9559,6 @@ const tech = {
isGrapple: null,
isImmuneGrapple: null,
isDronesTravel: null,
- isTechDebt: null
+ isTechDebt: null,
+ isPlasmaBall: null
}
\ No newline at end of file
diff --git a/style.css b/style.css
index 9d68c28..1c64d15 100644
--- a/style.css
+++ b/style.css
@@ -236,7 +236,7 @@ summary {
margin: 0px;
display: none;
- grid-template-columns: 320px;
+ grid-template-columns: 325px;
/* grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); */
grid-auto-rows: minmax(auto, auto);
grid-gap: 0px;
diff --git a/todo.txt b/todo.txt
index 555b5cc..71b40e8 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,20 +1,62 @@
******************************************************** NEXT PATCH **************************************************
-tech: autonomous navigation - drones travel with you through levels and drones reset durability
-tech: technical debt - increase damage by 300%, but reduce damage by 10% for each tech you have
+plasma ball is now live, but it's still in beta
+ still needs
+ new graphics
+ damage balancing
+ fast decay in mob shields
+ player angle rotation speed while firing adds to fire speed
+ tech upgrade to get electrical arcs that randomly damage nearby mobs
+ current tech synergy
+ capacitor bank,plasma jet(range?)
-molecular assembler now has a higher bullet spawn cap 200->300
- but it increases energy cost per spawn above around 150
+reservoir level is less crowded, so you can dodge mobs easier
+ horizontal flipped version is so reenabled
+pure science renamed paradigm shift
+difficulty scaling for heal and mob damage reduced 2%
-fragments are about 15% fewer
-thermal runaway is about 40% bigger and more damage
-plasma torch: extruder uses less energy
-pilot wave uses less energy
+some possible bug fixes, I don't know...
-bug fixes
******************************************************** TODO ********************************************************
+bug: harpoon attack gave a mob really high levels of health
+ recent events:
+ had 3 harpoons at a time
+ tech: immune with grappling hook, Bulk modulus
+ cancel true colors with pure science
+ attack with harpoon at slasher mobs
+ they didn't die, but they should in one hit instead they got a huge health bar, then I just died for no reason after touching one
+
+bug: maybe I can put in an event listener to reset inputs to false when you tab out to prevent key sticking
+
+
+enemies stuck with foam receive upward force over time
+ only form aerogel tech?
+
+bug: often game puts player position at NaN
+ try:
+ cloaking/harpoon grapple on normal, continue past beating the final boss
+ clues:
+ maybe with vanish or other special blocks and grapple hook
+ very high level for tech, duplication
+ maybe not about JUNK though
+ maybe on tons of bullets
+ maybe grappling hook, Bulk modulus
+ solution: just kill the player if they go NaN
+
+Tech: superglue
+Requires: foam + another gun or plasma torch or molecular assembler
+ Foam bubbles decay 50% slower
+ Enemies stuck with foam cannot move
+ Foam does 0 damage
+ Enemies stuck with foam take 25% more damage
+ should foam bots gets this also or is that too strong
+
+
+buff pilot wave damage or lower energy drain
+lower base harpoon density
+
const ctx = canvas.getContext('2d', {‘willReadFrequently': true});
//deal with game crashes?
@@ -33,22 +75,10 @@ setting to remove UI, except health bar
except active gun? to see ammo
checkbox in pause and in settings
-bug: often game puts player position at NaN
- clues:
- after apoximis?
- very high level for tech, duplication
- maybe not about JUNK though
-
-tech that does less damage the more tech you have?
- tech.totalCount
-
add coyote jump
log game m.cycle when last on ground
for jump check if game cycle is < last on ground cycle -2
-tech - Plasma railgun
- like foam, or phonon?
-
pause time like invariant for other things...
throwing blocks
charging railgun