pulse charge

pulse laser now charges up with energy before you fire, but it fires 3 overlapping explosions
  please give feedback on balance (too strong, too weak?)

tech shockwave: now applies to all explosions

foam gun now gets 20% less ammo
This commit is contained in:
landgreen
2021-04-27 05:10:36 -07:00
parent 07a78743be
commit e619a2d57b
8 changed files with 351 additions and 308 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -51,8 +51,6 @@ const b = {
if (m.fireCDcycle < m.cycle && player.speed < 0.5 && m.onGround && Math.abs(m.yOff - m.yOffGoal) < 1) {
if (b.guns[b.activeGun].ammo > 0) {
b.fireWithAmmo()
} else {
b.outOfAmmo()
}
if (m.holdingTarget) m.drop();
}
@@ -297,17 +295,17 @@ const b = {
}
},
explosionRange() {
return tech.explosiveRadius * (tech.isExplosionHarm ? 1.8 : 1) * (tech.isSmallExplosion ? 0.8 : 1) * (tech.isExplodeRadio ? 1.25 : 1)
return tech.explosiveRadius * (tech.isExplosionHarm ? 1.8 : 1) * (tech.isSmallExplosion ? 0.66 : 1) * (tech.isExplodeRadio ? 1.25 : 1)
},
explosion(where, radius, color = "rgba(255,25,0,0.6)") { // typically explode is used for some bullets with .onEnd
radius *= tech.explosiveRadius
let dist, sub, knock;
let dmg = radius * 0.013;
let dmg = radius * 0.013 * (tech.isExplosionStun ? 0.6 : 1);
if (tech.isExplosionHarm) radius *= 1.8 // 1/sqrt(2) radius -> area
if (tech.isSmallExplosion) {
color = "rgba(255,0,30,0.7)"
radius *= 0.8
dmg *= 1.6
radius *= 0.66
dmg *= 1.66
}
if (tech.isExplodeRadio) { //radiation explosion
@@ -430,6 +428,7 @@ const b = {
knock = Vector.mult(Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) * 0.01);
mob[i].force.x += knock.x;
mob[i].force.y += knock.y;
if (tech.isExplosionStun) mobs.statusStun(mob[i], 120)
radius *= 0.95 //reduced range for each additional explosion target
damageScale *= 0.87 //reduced damage for each additional explosion target
} else if (!mob[i].seePlayer.recall && dist < alertRange) {
@@ -437,15 +436,16 @@ const b = {
knock = Vector.mult(Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) * 0.006);
mob[i].force.x += knock.x;
mob[i].force.y += knock.y;
if (tech.isExplosionStun) mobs.statusStun(mob[i], 60)
}
}
}
}
},
pulse(energy, angle = m.angle) {
pulse(charge, angle = m.angle) {
let best;
let explosionRadius = 1250 * energy
let range = 3000
let explosionRadius = 6 * charge
let range = 5000
const path = [{
x: m.pos.x + 20 * Math.cos(angle),
y: m.pos.y + 20 * Math.sin(angle)
@@ -529,26 +529,23 @@ const b = {
};
}
}
if (best.who) b.explosion(path[1], explosionRadius)
if (tech.isPulseStun) {
const range = 100 + 2000 * energy
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isShielded) {
dist = Vector.magnitude(Vector.sub(path[1], mob[i].position)) - mob[i].radius;
if (dist < range) mobs.statusStun(mob[i], 30 + Math.floor(energy * 60))
}
}
if (best.who) {
b.explosion(path[1], explosionRadius)
const off = explosionRadius
b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius)
b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius)
}
//draw laser beam
ctx.beginPath();
ctx.moveTo(path[0].x, path[0].y);
ctx.lineTo(path[1].x, path[1].y);
ctx.strokeStyle = "rgba(255,0,0,0.13)"
ctx.lineWidth = 60 * energy / 0.2
if (charge > 50) {
ctx.strokeStyle = "rgba(255,0,0,0.10)"
ctx.lineWidth = 70
ctx.stroke();
ctx.strokeStyle = "rgba(255,0,0,0.2)"
ctx.lineWidth = 18
}
ctx.strokeStyle = "rgba(255,0,0,0.25)"
ctx.lineWidth = 20
ctx.stroke();
ctx.strokeStyle = "#f00";
ctx.lineWidth = 4
@@ -557,7 +554,7 @@ const b = {
//draw little dots along the laser path
const sub = Vector.sub(path[1], path[0])
const mag = Vector.magnitude(sub)
for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) {
for (let i = 0, len = Math.floor(mag * 0.0005 * charge); i < len; i++) {
const dist = Math.random()
simulation.drawList.push({
x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5),
@@ -568,121 +565,121 @@ const b = {
});
}
},
photon(where, angle = m.angle) {
let best;
const path = [{
x: m.pos.x + 20 * Math.cos(angle),
y: m.pos.y + 20 * Math.sin(angle)
},
{
x: m.pos.x + range * Math.cos(angle),
y: m.pos.y + range * Math.sin(angle)
}
];
const vertexCollision = function(v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
for (let j = 0; j < len; j++) {
results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
if (results.onLine1 && results.onLine2) {
const dx = v1.x - results.x;
const dy = v1.y - results.y;
const dist2 = dx * dx + dy * dy;
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[j],
v2: vertices[j + 1]
};
}
}
}
results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
if (results.onLine1 && results.onLine2) {
const dx = v1.x - results.x;
const dy = v1.y - results.y;
const dist2 = dx * dx + dy * dy;
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
}
};
//check for collisions
best = {
x: null,
y: null,
dist2: Infinity,
who: null,
v1: null,
v2: null
};
if (tech.isPulseAim) { //find mobs in line of sight
let dist = 2200
for (let i = 0, len = mob.length; i < len; i++) {
const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position))
if (explosionRadius < newDist &&
newDist < dist &&
Matter.Query.ray(map, path[0], mob[i].position).length === 0 &&
Matter.Query.ray(body, path[0], mob[i].position).length === 0) {
dist = newDist
best.who = mob[i]
path[path.length - 1] = mob[i].position
}
}
}
if (!best.who) {
vertexCollision(path[0], path[1], mob);
vertexCollision(path[0], path[1], map);
vertexCollision(path[0], path[1], body);
if (best.dist2 != Infinity) { //if hitting something
path[path.length - 1] = {
x: best.x,
y: best.y
};
}
}
if (best.who) b.explosion(path[1], explosionRadius)
// photon(where, angle = m.angle) {
// let best;
// const path = [{
// x: m.pos.x + 20 * Math.cos(angle),
// y: m.pos.y + 20 * Math.sin(angle)
// },
// {
// x: m.pos.x + range * Math.cos(angle),
// y: m.pos.y + range * Math.sin(angle)
// }
// ];
// const vertexCollision = function(v1, v1End, domain) {
// for (let i = 0; i < domain.length; ++i) {
// let vertices = domain[i].vertices;
// const len = vertices.length - 1;
// for (let j = 0; j < len; j++) {
// results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
// if (results.onLine1 && results.onLine2) {
// const dx = v1.x - results.x;
// const dy = v1.y - results.y;
// const dist2 = dx * dx + dy * dy;
// if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
// best = {
// x: results.x,
// y: results.y,
// dist2: dist2,
// who: domain[i],
// v1: vertices[j],
// v2: vertices[j + 1]
// };
// }
// }
// }
// results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
// if (results.onLine1 && results.onLine2) {
// const dx = v1.x - results.x;
// const dy = v1.y - results.y;
// const dist2 = dx * dx + dy * dy;
// if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
// best = {
// x: results.x,
// y: results.y,
// dist2: dist2,
// who: domain[i],
// v1: vertices[0],
// v2: vertices[len]
// };
// }
// }
// }
// };
// //check for collisions
// best = {
// x: null,
// y: null,
// dist2: Infinity,
// who: null,
// v1: null,
// v2: null
// };
// if (tech.isPulseAim) { //find mobs in line of sight
// let dist = 2200
// for (let i = 0, len = mob.length; i < len; i++) {
// const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position))
// if (explosionRadius < newDist &&
// newDist < dist &&
// Matter.Query.ray(map, path[0], mob[i].position).length === 0 &&
// Matter.Query.ray(body, path[0], mob[i].position).length === 0) {
// dist = newDist
// best.who = mob[i]
// path[path.length - 1] = mob[i].position
// }
// }
// }
// if (!best.who) {
// vertexCollision(path[0], path[1], mob);
// vertexCollision(path[0], path[1], map);
// vertexCollision(path[0], path[1], body);
// if (best.dist2 != Infinity) { //if hitting something
// path[path.length - 1] = {
// x: best.x,
// y: best.y
// };
// }
// }
// if (best.who) b.explosion(path[1], explosionRadius)
//draw laser beam
ctx.beginPath();
ctx.moveTo(path[0].x, path[0].y);
ctx.lineTo(path[1].x, path[1].y);
ctx.strokeStyle = "rgba(255,0,0,0.13)"
ctx.lineWidth = 60 * energy / 0.2
ctx.stroke();
ctx.strokeStyle = "rgba(255,0,0,0.2)"
ctx.lineWidth = 18
ctx.stroke();
ctx.strokeStyle = "#f00";
ctx.lineWidth = 4
ctx.stroke();
// //draw laser beam
// ctx.beginPath();
// ctx.moveTo(path[0].x, path[0].y);
// ctx.lineTo(path[1].x, path[1].y);
// ctx.strokeStyle = "rgba(255,0,0,0.13)"
// ctx.lineWidth = 60 * energy / 0.2
// ctx.stroke();
// ctx.strokeStyle = "rgba(255,0,0,0.2)"
// ctx.lineWidth = 18
// ctx.stroke();
// ctx.strokeStyle = "#f00";
// ctx.lineWidth = 4
// ctx.stroke();
//draw little dots along the laser path
const sub = Vector.sub(path[1], path[0])
const mag = Vector.magnitude(sub)
for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) {
const dist = Math.random()
simulation.drawList.push({
x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5),
y: path[0].y + sub.y * dist + 13 * (Math.random() - 0.5),
radius: 1 + 4 * Math.random(),
color: "rgba(255,0,0,0.5)",
time: Math.floor(2 + 33 * Math.random() * Math.random())
});
}
},
// //draw little dots along the laser path
// const sub = Vector.sub(path[1], path[0])
// const mag = Vector.magnitude(sub)
// for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) {
// const dist = Math.random()
// simulation.drawList.push({
// x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5),
// y: path[0].y + sub.y * dist + 13 * (Math.random() - 0.5),
// radius: 1 + 4 * Math.random(),
// color: "rgba(255,0,0,0.5)",
// time: Math.floor(2 + 33 * Math.random() * Math.random())
// });
// }
// },
grenade() {
},
@@ -2226,7 +2223,7 @@ const b = {
if (this.target.isShielded) {
this.target.damage(b.dmgScale * this.damage, true); //shield damage bypass
//shrink if mob is shielded
const SCALE = 1 - 0.014 / tech.isBulletsLastLonger
const SCALE = 1 - 0.01 / tech.isBulletsLastLonger
Matter.Body.scale(this, SCALE, SCALE);
this.radius *= SCALE;
} else {
@@ -2873,7 +2870,7 @@ const b = {
let closeDist = this.range;
for (let i = 0, len = mob.length; i < len; ++i) {
const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius;
if (DIST < closeDist && mob[i].isDropPowerUp &&
if (DIST < closeDist &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
closeDist = DIST;
@@ -4049,16 +4046,18 @@ const b = {
name: "foam",
description: "spray bubbly foam that <strong>sticks</strong> to mobs<br><strong class='color-s'>slows</strong> mobs and does <strong class='color-d'>damage</strong> over time",
ammo: 0,
ammoPack: 30,
ammoPack: 27,
have: false,
charge: 0,
isDischarge: false,
do() {
if (this.charge > 0) {
//draw charge level
ctx.fillStyle = "rgba(0,50,50,0.2)";
ctx.fillStyle = "rgba(0,50,50,0.3)";
ctx.beginPath();
ctx.arc(m.pos.x + 35 * Math.cos(m.angle), m.pos.y + 35 * Math.sin(m.angle), 10 * Math.sqrt(this.charge), 0, 2 * Math.PI);
const radius = 10 * Math.sqrt(this.charge)
const mag = 11 + radius
ctx.arc(m.pos.x + mag * Math.cos(m.angle), m.pos.y + mag * Math.sin(m.angle), radius, 0, 2 * Math.PI);
ctx.fill();
if (this.isDischarge) {
@@ -4094,15 +4093,15 @@ const b = {
x: position.x,
y: position.y,
radius: 5,
color: "rgba(0,0,0,0.1)",
color: "rgba(0,50,50,0.3)",
time: 15 * tech.foamFutureFire
});
setTimeout(() => {
if (!simulation.paused) {
b.foam(position, Vector.rotate(velocity, spread), radius)
bullet[bullet.length - 1].damage = (1 + 1.27 * tech.foamFutureFire) * (tech.isFastFoam ? 0.048 : 0.012) //double damage
bullet[bullet.length - 1].damage = (1 + 0.9 * tech.foamFutureFire) * (tech.isFastFoam ? 0.048 : 0.012) //double damage
}
}, 250 * tech.foamFutureFire);
}, 300 * tech.foamFutureFire);
} else {
b.foam(position, Vector.rotate(velocity, spread), radius)
}
@@ -4467,14 +4466,43 @@ const b = {
ammo: 0,
ammoPack: Infinity,
have: false,
nextFireCycle: 0, //use to remember how longs its been since last fire, used to reset count
charge: 0,
do() {},
fire() {
},
fire() {},
chooseFireMethod() {
this.do = () => {};
if (tech.isPulseLaser) {
this.fire = this.firePulse
this.fire = () => {
const drain = 0.01 * tech.isLaserDiode / b.fireCD
if (m.energy > drain) {
m.energy -= m.fieldRegen
if (this.charge < 50 * m.maxEnergy) {
m.energy -= drain
this.charge += 1 / b.fireCD
}
}
}
this.do = () => {
if (this.charge > 0) {
//draw charge level
ctx.fillStyle = `rgba(255,0,0,${0.09 * Math.sqrt(this.charge)})`;
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 4.2 * Math.sqrt(this.charge), 0, 2 * Math.PI);
ctx.fill();
if (!input.fire) {
m.fireCDcycle = m.cycle + 10; // cool down
if (tech.beamSplitter) {
const divergence = m.crouch ? 0.2 : 0.5
const angle = m.angle - tech.beamSplitter * divergence / 2
for (let i = 0; i < 1 + tech.beamSplitter; i++) b.pulse(this.charge, angle + i * divergence)
} else {
b.pulse(1.75 * this.charge, m.angle)
}
this.charge = 0;
}
}
};
} else if (tech.beamSplitter) {
this.fire = this.fireSplit
} else if (tech.historyLaser) {
@@ -4627,27 +4655,27 @@ const b = {
ctx.stroke();
}
},
firePulse() {
m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down
let energy = 0.3 * Math.min(m.energy, 1.5)
m.energy -= energy * tech.isLaserDiode
if (tech.beamSplitter) {
// energy *= Math.pow(0.9, tech.beamSplitter)
// b.pulse(energy, m.angle)
// for (let i = 1; i < 1 + tech.beamSplitter; i++) {
// b.pulse(energy, m.angle - i * 0.27)
// b.pulse(energy, m.angle + i * 0.27)
// firePulse() {
// m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCD); // cool down
// let energy = 0.3 * Math.min(m.energy, 1.5)
// m.energy -= energy * tech.isLaserDiode
// if (tech.beamSplitter) {
// // energy *= Math.pow(0.9, tech.beamSplitter)
// // b.pulse(energy, m.angle)
// // for (let i = 1; i < 1 + tech.beamSplitter; i++) {
// // b.pulse(energy, m.angle - i * 0.27)
// // b.pulse(energy, m.angle + i * 0.27)
// // }
// const divergence = m.crouch ? 0.2 : 0.5
// const angle = m.angle - tech.beamSplitter * divergence / 2
// for (let i = 0; i < 1 + tech.beamSplitter; i++) {
// b.pulse(energy, angle + i * divergence)
// }
const divergence = m.crouch ? 0.2 : 0.5
const angle = m.angle - tech.beamSplitter * divergence / 2
for (let i = 0; i < 1 + tech.beamSplitter; i++) {
b.pulse(energy, angle + i * divergence)
}
} else {
b.pulse(energy, m.angle)
}
},
// } else {
// b.pulse(energy, m.angle)
// }
// },
},
],
gunRewind: { //this gun is added with a tech

View File

@@ -794,17 +794,7 @@ window.addEventListener("keydown", function(event) {
simulation.testing = true;
simulation.loop = simulation.testingLoop
if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'inline'
if (!simulation.isCheating) {
simulation.isCheating = true;
level.levelAnnounce();
lore.techCount = 0;
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0;
tech.tech[i].count = 0;
}
}
}
if (simulation.testing) tech.setCheating();
simulation.makeTextLog(
`<table class="pause-table">
<tr>

View File

@@ -12,14 +12,15 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(50)
// level.difficultyIncrease(30)
// simulation.zoomScale = 1000;
// simulation.setZoom();
// m.setField("nano-scale manufacturing")
// b.giveGuns("foam")
// b.giveGuns("laser")
// tech.isExplodeRadio = true
// for (let i = 0; i < 9; i++) tech.giveTech("auto-loading heuristics")
// tech.giveTech("superfluidity")
// tech.giveTech("pulse")
// tech.giveTech("ice crystal nucleation")
// tech.giveTech("needle gun")
// tech.giveTech("cardinality")
@@ -1109,9 +1110,8 @@ const level = {
spawn.mapRect(6700, -1800, 800, 2600); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
// simulation.difficulty = 30
spawn.starter(1900, -500, 100) //big boy
spawn.grower(1900, -500)
spawn.starter(1900, -500, 200) //big boy
// spawn.grower(1900, -500)
// spawn.pulsarBoss(1900, -500)
// spawn.shooterBoss(1900, -500)
// spawn.launcherBoss(1200, -500)

View File

@@ -1145,20 +1145,20 @@ const m = {
m.fieldCDcycle = m.cycle + 15;
m.isHolding = false;
//bullet-like collisions
m.holdingTarget.collisionFilter.category = cat.bullet; //cat.body;
// m.holdingTarget.collisionFilter.category = cat.bullet; //cat.body;
m.holdingTarget.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield;
//check every second to see if player is away from thrown body, and make solid
const solid = function(that) {
const dx = that.position.x - player.position.x;
const dy = that.position.y - player.position.y;
if (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) {
that.collisionFilter.category = cat.body; //make solid
// that.collisionFilter.category = cat.body; //make solid
that.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; //can hit player now
} else {
setTimeout(solid, 50, that);
setTimeout(solid, 40, that);
}
};
setTimeout(solid, 500, m.holdingTarget);
setTimeout(solid, 200, m.holdingTarget);
const charge = Math.min(m.throwCharge / 5, 1)
//***** scale throw speed with the first number, 80 *****

View File

@@ -1621,9 +1621,9 @@ const spawn = {
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(120,0,255,0.2)";
ctx.strokeStyle = "rgba(120,0,255,0.3)";
ctx.stroke();
ctx.lineWidth = 4;
ctx.lineWidth = 5;
ctx.strokeStyle = "rgba(120,0,255,1)";
ctx.stroke();
} else { //delay before firing
@@ -1631,7 +1631,7 @@ const spawn = {
//draw explosion outline
ctx.beginPath();
ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(120,0,255,0.05)";
ctx.fillStyle = "rgba(120,0,255,0.07)";
ctx.fill();
//draw path from mob to explosion
ctx.beginPath();
@@ -1639,7 +1639,7 @@ const spawn = {
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(120,0,255,0.2)";
ctx.strokeStyle = "rgba(120,0,255,0.3)";
ctx.stroke();
ctx.setLineDash([0, 0]);
}
@@ -1741,9 +1741,9 @@ const spawn = {
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(255,0,100,0.2)";
ctx.strokeStyle = "rgba(255,0,100,0.3)";
ctx.stroke();
ctx.lineWidth = 4;
ctx.lineWidth = 5;
ctx.strokeStyle = "rgba(255,0,100,1)";
ctx.stroke();
} else { //delay before firing
@@ -1754,7 +1754,7 @@ const spawn = {
//draw explosion outline
ctx.beginPath();
ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(255,0,100,0.05)";
ctx.fillStyle = "rgba(255,0,100,0.07)";
ctx.fill();
//draw path from mob to explosion
ctx.beginPath();
@@ -1762,7 +1762,7 @@ const spawn = {
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(255,0,100,0.2)";
ctx.strokeStyle = "rgba(255,0,100,0.3)";
ctx.stroke();
ctx.setLineDash([0, 0]);
}

View File

@@ -107,6 +107,17 @@
}
}
},
setCheating() {
simulation.isCheating = true;
level.levelAnnounce();
lore.techCount = 0;
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isLore) {
tech.tech[i].frequency = 0;
tech.tech[i].count = 0;
}
}
},
haveGunCheck(name) {
if (
!build.isExperimentSelection &&
@@ -745,7 +756,7 @@
},
{
name: "nitroglycerin",
description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>60%</strong><br>decrease <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>20%</strong>",
description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>66%</strong><br>decrease <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>33%</strong>",
maxCount: 1,
count: 0,
frequency: 2,
@@ -778,6 +789,24 @@
tech.isExplosionHarm = false;
}
},
{
name: "shock wave",
description: "<strong class='color-e'>explosions</strong> <strong>stun</strong> mobs for <strong>1-2</strong> seconds<br>decrease <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>40%</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1)
},
requires: "an explosive damage source, not iridium-192",
effect() {
tech.isExplosionStun = true;
},
remove() {
tech.isExplosionStun = false;
}
},
{
name: "electric reactive armor",
// description: "<strong class='color-e'>explosions</strong> do no <strong class='color-harm'>harm</strong><br> while your <strong class='color-f'>energy</strong> is above <strong>98%</strong>",
@@ -1443,9 +1472,9 @@
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole"
return tech.throwChargeRate > 1 && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isEnergyHealth
},
requires: "mass driver, a field that can hold things",
requires: "mass driver, a field that can hold things, not mass-energy",
effect() {
tech.isBlockHarm = true
},
@@ -1687,23 +1716,6 @@
tech.isHarmFreeze = false;
}
},
{
name: "osmoprotectant",
description: `collisions with <strong>stunned</strong> or <strong class='color-s'>frozen</strong> mobs<br>cause you <strong>no</strong> <strong class='color-harm'>harm</strong>`,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return tech.isStunField || tech.isPulseStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1
},
requires: "a freezing or stunning effect",
effect() {
tech.isFreezeHarmImmune = true;
},
remove() {
tech.isFreezeHarmImmune = false;
}
},
{
name: "superfluidity",
description: "<strong class='color-s'>freeze</strong> effects are applied to a small area",
@@ -1721,6 +1733,40 @@
tech.isAoESlow = false
}
},
{
name: "osmoprotectant",
description: `collisions with <strong>stunned</strong> or <strong class='color-s'>frozen</strong> mobs<br>cause you <strong>no</strong> <strong class='color-harm'>harm</strong>`,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return tech.isStunField || tech.isExplosionStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1
},
requires: "a freezing or stunning effect",
effect() {
tech.isFreezeHarmImmune = true;
},
remove() {
tech.isFreezeHarmImmune = false;
}
},
{
name: "fracture analysis",
description: "bullet impacts do <strong>400%</strong> <strong class='color-d'>damage</strong><br>to <strong>stunned</strong> mobs",
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isPerpetualStun || tech.isExplosionStun
},
requires: "a stun effect",
effect() {
tech.isCrit = true;
},
remove() {
tech.isCrit = false;
}
},
{
name: "ablative drones",
description: "rebuild your broken parts as <strong>drones</strong><br>chance to occur after receiving <strong class='color-harm'>harm</strong>",
@@ -2124,9 +2170,9 @@
frequency: 4,
frequencyDefault: 4,
allowed() {
return tech.isDamageAfterKill
return tech.isDamageAfterKill && !tech.isEnergyHealth
},
requires: "dormancy",
requires: "dormancy, not mass-energy",
effect() {
tech.isHarmReduceAfterKill = true;
},
@@ -2553,6 +2599,7 @@
if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech
tech.setupAllTech(); // remove all tech
if (simulation.isCheating) tech.setCheating();
lore.techCount = 0;
// tech.addLoreTechToPool();
for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups
@@ -4006,7 +4053,7 @@
},
{
name: "quantum foam",
description: "<strong>foam</strong> gun fires <strong>0.25</strong> seconds into the <strong>future</strong><br>increase <strong>foam</strong> gun <strong class='color-d'>damage</strong> by <strong>127%</strong>",
description: "<strong>foam</strong> gun fires <strong>0.30</strong> seconds into the <strong>future</strong><br>increase <strong>foam</strong> gun <strong class='color-d'>damage</strong> by <strong>90%</strong>",
isGunTech: true,
maxCount: 9,
count: 0,
@@ -4302,7 +4349,7 @@
},
{
name: "pulse",
description: "use <strong>25%</strong> of your <strong class='color-f'>energy</strong> in a pulsed <strong class='color-laser'>laser</strong><br>that instantly initiates a fusion <strong class='color-e'>explosion</strong>",
description: "charge your <strong class='color-f'>energy</strong> and release it as a<br><strong class='color-laser'>laser</strong> pulse that initiates an <strong class='color-e'>explosion</strong> cluster",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -4326,27 +4373,9 @@
}
}
},
{
name: "shock wave",
description: "mobs caught in <strong class='color-laser'>pulse</strong>'s explosion are <strong>stunned</strong><br>for up to <strong>2 seconds</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return tech.isPulseLaser
},
requires: "pulse",
effect() {
tech.isPulseStun = true;
},
remove() {
tech.isPulseStun = false;
}
},
{
name: "neocognitron",
description: "<strong class='color-laser'>pulse</strong> automatically <strong>aims</strong> at a nearby mob<br><strong>50%</strong> decreased <strong><em>delay</em></strong> after firing",
description: "<strong class='color-laser'>pulse</strong> automatically <strong>aims</strong> at a nearby mob",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -4366,6 +4395,28 @@
//************************************************** field
//************************************************** tech
//**************************************************
{
name: "frequency resonance",
description: "<strong>standing wave harmonics</strong> shield is retuned<br>increase <strong>size</strong> and <strong>blocking</strong> efficiency by <strong>50%</strong>",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics"
},
requires: "standing wave harmonics",
effect() {
tech.frequencyResonance = this.count + 1 // +1 because count updates later
m.fieldRange = 175 + 175 * 0.25 * tech.frequencyResonance
m.fieldShieldingScale = Math.pow(0.5, tech.frequencyResonance)
},
remove() {
m.fieldRange = 175;
m.fieldShieldingScale = 1;
tech.frequencyResonance = 0
}
},
{
name: "bremsstrahlung",
description: "<strong>blocking</strong> does <strong class='color-d'>damage</strong> to mobs",
@@ -4402,28 +4453,6 @@
tech.blockingIce = 0;
}
},
{
name: "frequency resonance",
description: "<strong>standing wave harmonics</strong> shield is retuned<br>increase <strong>size</strong> and <strong>blocking</strong> efficiency by <strong>50%</strong>",
isFieldTech: true,
maxCount: 9,
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics"
},
requires: "standing wave harmonics",
effect() {
tech.frequencyResonance = this.count + 1 // +1 because count updates later
m.fieldRange = 175 + 175 * 0.25 * tech.frequencyResonance
m.fieldShieldingScale = Math.pow(0.5, tech.frequencyResonance)
},
remove() {
m.fieldRange = 175;
m.fieldShieldingScale = 1;
tech.frequencyResonance = 0
}
},
{
name: "flux pinning",
description: "blocking with your <strong>field</strong><br><strong>stuns</strong> mobs for <strong>+2</strong> second",
@@ -4442,24 +4471,6 @@
tech.isStunField = 0;
}
},
{
name: "fracture analysis",
description: "bullet impacts do <strong>400%</strong> <strong class='color-d'>damage</strong><br>to <strong>stunned</strong> mobs",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isPerpetualStun
},
requires: "a stun effect",
effect() {
tech.isCrit = true;
},
remove() {
tech.isCrit = false;
}
},
{
name: "eddy current brake",
description: "project a field that limits the <strong>top speed</strong> of mobs<br>field <strong>radius</strong> scales with stored <strong class='color-f'>energy</strong>",
@@ -4478,25 +4489,6 @@
tech.isPerfectBrake = false;
}
},
{
name: "pair production",
description: "picking up a <strong>power up</strong> gives you <strong>250</strong> <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
requires: "nano-scale manufacturing",
effect: () => {
tech.isMassEnergy = true // used in m.grabPowerUp
m.energy += 3
},
remove() {
tech.isMassEnergy = false;
}
},
{
name: "bot manufacturing",
description: "use <strong>nano-scale manufacturing</strong><br>to build <strong>3</strong> random <strong class='color-bot'>bots</strong>",
@@ -4608,6 +4600,25 @@
},
remove() {}
},
{
name: "pair production",
description: "picking up a <strong>power up</strong> gives you <strong>250</strong> <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
requires: "nano-scale manufacturing",
effect: () => {
tech.isMassEnergy = true // used in m.grabPowerUp
m.energy += 3
},
remove() {
tech.isMassEnergy = false;
}
},
{
name: "mycelium manufacturing",
description: "<strong>nano-scale manufacturing</strong> is repurposed<br>excess <strong class='color-f'>energy</strong> used to grow <strong class='color-p' style='letter-spacing: 2px;'>spores</strong>",
@@ -4688,9 +4699,9 @@
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "negative mass field"
return m.fieldUpgrades[m.fieldMode].name === "negative mass field" && !tech.isEnergyHealth
},
requires: "negative mass field",
requires: "negative mass field, not mass-energy",
effect() {
tech.isHarmReduce = true
},
@@ -6304,7 +6315,7 @@
isSporeFollow: null,
isNailRadiation: null,
isEnergyHealth: null,
isPulseStun: null,
isExplosionStun: null,
restDamage: null,
isRPG: null,
missileCount: null,

View File

@@ -1,5 +1,11 @@
******************************************************** NEXT PATCH ********************************************************
pulse laser now charges up with energy before you fire, but it fires 3 overlapping explosions
please give feedback on balance (too strong, too weak?)
tech shockwave: now applies to all explosions
foam gun now gets 20% less ammo
******************************************************** BUGS ********************************************************
@@ -18,9 +24,9 @@ fix door.isOpen actually meaning isClosed?
wasn't able to understand bug after extensive testing
had tech: complex spin statistics
(always) make it so that when you are immune to harm you can either jump on mobs or you pass through them
make it so that when you are immune to harm you can either jump on mobs or you pass through them
(always) is there a way to check if the player is stuck inside the map or block
is there a way to check if the player is stuck inside the map or block
trigger a short term non-collide if that occurs
(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause
@@ -33,8 +39,16 @@ fix door.isOpen actually meaning isClosed?
******************************************************** TODO ********************************************************
edit foam gun text?
add a foam charge meter would be nice
avoid taking collision damage by teleporting to a random power up
removes the power up
make a tech that improves all charge guns
for: pulse, foam, rail gun
effect:
faster charge rate?
fire speed already does that...
harm reduction while charging
less ammo/energy used while charging?
apply the new gun.do functions to other guns
rail gun