laserLayer

mob: laserLayer - leaves behind lasers that persist for a few seconds
ghoster mobs do 66% less damage, but they eject your ammo

grappling hook tech rupture renamed swarf
  fires several nails at nearby mobs, not explosions
grappling hook 6->9 energy per second
CIWS 18->10 energy
reel +40->75 energy reeling blocks
wormhole 5->7% duplication
cloaking no longer drains energy, this fixes a can't cloak bug
  dazzler no longer drains energy
    dazzler range reduced by 15%
    dazzler stuns for 3->2 seconds
zero point energy 100->166 max energy
expansion 40->77 max energy
annihilation -33% of max energy -> 10 energy
dynamical systems is no longer a field tech  35->30 damage
tessellation is no longer a field tech  50->35 defense
yield stress removed
  topological defect 80->111% damage
  brittle 80->111% damage
commodities exchange  6-12 -> 10-14 power ups
heat engine 50->40% damage
flame test grenades clusters explode 40% faster
alternator uses 10->0% energy for harpoon

finally made a shared vertexCollision function
  this might cause some bugs with laser-like effects...
This commit is contained in:
landgreen
2024-02-24 15:09:35 -08:00
parent b5e4b0db03
commit 38d993154c
13 changed files with 684 additions and 1808 deletions

View File

@@ -558,46 +558,6 @@ const b = {
y: where.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,
@@ -607,28 +567,8 @@ const b = {
v1: null,
v2: null
};
// if (tech.isPulseAim && !m.crouch) { //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 &&
// !mob[i].isBadTarget &&
// Matter.Query.ray(map, path[0], mob[i].position).length === 0 &&
// Matter.Query.ray(body, path[0], mob[i].position).length === 0 &&
// !mob[i].isInvulnerable
// ) {
// 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);
best = vertexCollision(path[0], path[1], [mob, map, body]);
if (best.dist2 != Infinity) { //if hitting something
path[path.length - 1] = {
x: best.x,
@@ -678,135 +618,20 @@ 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)
// //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())
// });
// }
// },
fireworks(where, size) { //can occur after grenades detonate
clusterExplode(where, size) { //can occur after grenades detonate
const cycle = () => {
if (m.alive) {
if (simulation.paused || m.isBodiesAsleep) {
requestAnimationFrame(cycle)
} else {
count++
if (count < 130) requestAnimationFrame(cycle);
if (!(count % 10)) {
if (count < 84) requestAnimationFrame(cycle);
if (!(count % 7)) {
const unit = Vector.rotate({
x: 1,
y: 0
}, 6.28 * Math.random())
b.explosion(Vector.add(where, Vector.mult(unit, size * (count * 0.01 + 0.02 * Math.random()))), size * (0.4 + Math.random() * 0.35), `hsla(${360 * Math.random()},100%,66%,0.6)`); //makes bullet do explosive damage at end
b.explosion(Vector.add(where, Vector.mult(unit, size * (count * 0.01 + 0.03 * Math.random()))), size * (0.4 + Math.random() * 0.35), `hsla(${360 * Math.random()},100%,66%,0.6)`); //makes bullet do explosive damage at end
}
}
}
@@ -884,7 +709,7 @@ const b = {
} else if (tech.isPetalsExplode) {
b.fireFlower(this.position, this.explodeRad)
} else if (tech.isClusterExplode) {
b.fireworks(this.position, this.explodeRad)
b.clusterExplode(this.position, this.explodeRad)
} else {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
}
@@ -1501,7 +1326,7 @@ const b = {
drawStringControlMagnitude: 1000 + 1000 * Math.random(),
drawStringFlip: (Math.round(Math.random()) ? 1 : -1),
attached: false,
glowColor: tech.isHookExplosion ? "rgba(200,0,0,0.07)" : tech.isHarmReduce ? "rgba(50,100,255,0.1)" : "rgba(0,200,255,0.07)",
glowColor: tech.hookNails ? "rgba(200,0,0,0.07)" : tech.isHarmReduce ? "rgba(50,100,255,0.1)" : "rgba(0,200,255,0.07)",
collisionFilter: {
category: cat.bullet,
mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
@@ -1598,14 +1423,20 @@ const b = {
});
}
if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
if (tech.hookNails) {
// if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles
// b.explosion(this.position, 300 + 150 * Math.random()); //makes bullet do explosive damage at end
b.targetedNail(this.position, tech.hookNails)
const ANGLE = 2 * Math.PI * Math.random() //make a few random ones
for (let i = 0; i < 4; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2)
}
// if (this.powerUpDamage) this.density = 2 * 0.004 //double damage after pick up power up for 8 seconds
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
Matter.Body.setDensity(this, 1.8 * 0.004); //+90% damage after pick up power up for 8 seconds
} else if (tech.isHarpoonFullHealth && who.health === 1) {
Matter.Body.setDensity(this, 1.9 * 0.004); //+90% damage if mob has full health do
Matter.Body.setDensity(this, 2.11 * 0.004); //+90% damage if mob has full health do
simulation.ephemera.push({
name: "grapple outline",
count: 3, //cycles before it self removes
@@ -1688,7 +1519,7 @@ const b = {
if (this.pickUpTarget) {
if (tech.isReel && this.blockDist > 150) {
// console.log(0.0003 * Math.min(this.blockDist, 1000))
m.energy += 0.00044 * Math.min(this.blockDist, 800) //max 0.352 energy
m.energy += 0.0009 * Math.min(this.blockDist, 800) //max 0.352 energy
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
@@ -1758,10 +1589,15 @@ const b = {
if (blocks.length) {
// console.log(blocks)
for (let i = 0; i < blocks.length; i++) {
if (blocks[i].bodyA.classType === "body" && !blocks[i].bodyA.isNotHoldable && !blocks[0].bodyA.mass < 60) {
if (blocks[i].bodyA.classType === "body" && !blocks[i].bodyA.isNotHoldable && blocks[0].bodyA.mass < 60) {
this.retract()
if (tech.isHookExplosion) {
b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
if (tech.hookNails) {
// if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles
// b.explosion(this.position, 300 + 150 * Math.random()); //makes bullet do explosive damage at end
b.targetedNail(this.position, 3 * tech.hookNails)
const ANGLE = 2 * Math.PI * Math.random() //make a few random ones
for (let i = 0; i < 13; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2)
const blockVertices = blocks[i].bodyA.vertices
Composite.remove(engine.world, blocks[i].bodyA)
body.splice(body.indexOf(blocks[i].bodyA), 1)
@@ -1785,12 +1621,20 @@ const b = {
this.pickUpTarget = blocks[i].bodyA
this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos))
}
} else if (blocks[i].bodyB.classType === "body" && !blocks[i].bodyB.isNotHoldable && !blocks[0].bodyB.mass < 60) {
this.retract()
this.pickUpTarget = blocks[i].bodyB
this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos))
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
}
// else if (blocks[i].bodyB.classType === "body" && !blocks[i].bodyB.isNotHoldable && blocks[0].bodyB.mass < 60) {
// this.retract()
// this.pickUpTarget = blocks[i].bodyB
// this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos))
// if (tech.hookNails) {
// // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles
// // b.explosion(this.position, 300 + 150 * Math.random()); //makes bullet do explosive damage at end
// b.targetedNail(this.position, tech.hookNails)
// const ANGLE = 2 * Math.PI * Math.random() //make a few random ones
// for (let i = 0; i < 4; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2)
// }
// }
}
// if (blocks[0].bodyA.mass > 2.5 && blocks[0].bodyA.mass > 15) {
@@ -1855,7 +1699,14 @@ const b = {
if (input.field && 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) {
if (tech.isHookExplosion) b.explosion(this.position, 150 + 50 * Math.random()); //makes bullet do explosive damage at end
if (tech.hookNails) {
// if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles
// b.explosion(this.position, 200 + 150 * Math.random()); //makes bullet do explosive damage at end
b.targetedNail(this.position, tech.hookNails)
const ANGLE = 2 * Math.PI * Math.random() //make a few random ones
for (let i = 0; i < 4; i++) b.nail(this.position, { x: 10.5 * Math.cos(ANGLE), y: 10.5 * Math.sin(ANGLE) }, 1.2)
}
this.attached = true
Matter.Body.setVelocity(this, { x: 0, y: 0 });
Matter.Sleeping.set(this, true)
@@ -1976,7 +1827,7 @@ const b = {
friction: 1,
frictionAir: 0.4,
// thrustMag: 0.1,
drain: tech.isRailEnergy ? 0.0006 : 0.006,
drain: tech.isRailEnergy ? 0 : 0.006,
turnRate: isReturn ? 0.1 : 0.03, //0.015
drawStringControlMagnitude: 3000 + 5000 * Math.random(),
drawStringFlip: (Math.round(Math.random()) ? 1 : -1),
@@ -2022,7 +1873,7 @@ const b = {
if (tech.isHarpoonPowerUp && simulation.cycle - 480 < tech.harpoonPowerUpCycle) {
Matter.Body.setDensity(this, 1.8 * tech.harpoonDensity); //+90% damage after pick up power up for 8 seconds
} else if (tech.isHarpoonFullHealth && who.health === 1) {
Matter.Body.setDensity(this, 1.9 * tech.harpoonDensity); //+90% damage if mob has full health do
Matter.Body.setDensity(this, 2.11 * tech.harpoonDensity); //+90% damage if mob has full health do
simulation.ephemera.push({
name: "harpoon outline",
count: 2, //cycles before it self removes
@@ -2435,7 +2286,6 @@ const b = {
}
//calculate laser collision
let best;
let range = tech.isPlasmaRange * (120 + (m.crouch ? 400 : 300) * Math.sqrt(Math.random())) //+ 100 * Math.sin(m.cycle * 0.3);
// const dir = m.angle // + 0.04 * (Math.random() - 0.5)
const path = [{
@@ -2447,49 +2297,8 @@ const b = {
y: m.pos.y + range * Math.sin(m.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 = {
let best = {
x: null,
y: null,
dist2: Infinity,
@@ -2497,14 +2306,9 @@ const b = {
v1: null,
v2: null
};
vertexCollision(path[0], path[1], mob);
vertexCollision(path[0], path[1], map);
vertexCollision(path[0], path[1], body);
best = vertexCollision(path[0], path[1], [mob, map, body]);
if (best.dist2 != Infinity) { //if hitting something
path[path.length - 1] = {
x: best.x,
y: best.y
};
path[path.length - 1] = { x: best.x, y: best.y };
if (best.who.alive) {
const dmg = 0.9 * m.dmgScale; //********** SCALE DAMAGE HERE *********************
best.who.damage(dmg);
@@ -2571,6 +2375,7 @@ const b = {
}, dmg = tech.laserDamage, reflections = tech.laserReflections, isThickBeam = false, push = 1) {
const reflectivity = 1 - 1 / (reflections * 3)
let damage = m.dmgScale * dmg
let best = {
x: 1,
y: 1,
@@ -2586,59 +2391,9 @@ const b = {
x: whereEnd.x,
y: whereEnd.y
}];
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]
};
}
}
}
};
const checkForCollisions = function () {
best = {
x: 1,
y: 1,
dist2: Infinity,
who: null,
v1: 1,
v2: 1
};
vertexCollision(path[path.length - 2], path[path.length - 1], mob);
vertexCollision(path[path.length - 2], path[path.length - 1], map);
vertexCollision(path[path.length - 2], path[path.length - 1], body);
best = vertexCollision(path[path.length - 2], path[path.length - 1], [mob, map, body]);
};
const laserHitMob = function () {
if (best.who.alive) {
@@ -2895,7 +2650,7 @@ const b = {
} else if (tech.isSuperMine) {
b.targetedBall(this.position, 22 + 2 * tech.extraSuperBalls)
} else {
b.targetedNail(this.position, 22, 40 + 10 * Math.random(), 1200, true, 2.2) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) {
b.targetedNail(this.position, 22, 40 + 10 * Math.random(), 1200, 2.2)
}
}
},
@@ -2993,7 +2748,7 @@ const b = {
if (Math.random() < 0.33) b.targetedBall(this.position, 1, 42 + 12 * Math.random(), 1200, false)
}
} else {
this.shots -= b.targetedNail(this.position, 1, 45 + 5 * Math.random(), 1100, false, 2.3) //targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) {
this.shots -= b.targetedNail(this.position, 1, 45 + 5 * Math.random(), 1100, 2.3)
}
if (this.shots < 0) this.endCycle = 0
if (!(simulation.cycle % (this.lookFrequency * 6))) {
@@ -3508,10 +3263,7 @@ const b = {
}
requestAnimationFrame(respawnDrones);
},
drone(where = {
x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5),
y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5)
}, speed = 1) {
drone(where = { x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) }, speed = 1) {
const me = bullet.length;
const THRUST = 0.0015
const dir = m.angle + 0.2 * (Math.random() - 0.5);
@@ -3688,7 +3440,7 @@ const b = {
for (let i = 0, len = powerUp.length; i < len; ++i) { //grab, but don't lock onto nearby power up
if (
Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 20000 &&
(powerUp[i].name !== "heal" || m.health < 0.93 * m.maxHealth || tech.isDroneGrab) &&
(powerUp[i].name !== "heal" || m.health < 0.97 * m.maxHealth || tech.isDroneGrab) &&
(powerUp[i].name !== "field" || !tech.isSuperDeterminism)
// &&(b.inventory.length > 1 || powerUp[i].name !== "ammo" || b.guns[b.activeGun].ammo !== Infinity || tech.isDroneGrab)
) {
@@ -3719,7 +3471,7 @@ const b = {
let closeDist = Infinity;
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (
(powerUp[i].name !== "heal" || m.health < 0.93 * m.maxHealth || tech.isDroneGrab) &&
(powerUp[i].name !== "heal" || m.health < 0.97 * m.maxHealth || tech.isDroneGrab) &&
(powerUp[i].name !== "field" || !tech.isSuperDeterminism)
// &&(b.inventory.length > 1 || powerUp[i].name !== "ammo" || b.guns[b.activeGun].ammo !== Infinity || tech.isDroneGrab)
) {
@@ -3748,8 +3500,7 @@ const b = {
}
//look for power ups to lock onto
if (
Matter.Query.ray(map, this.position, powerUp[i].position).length === 0 &&
Matter.Query.ray(body, this.position, powerUp[i].position).length === 0
Matter.Query.ray(map, this.position, powerUp[i].position).length === 0 //&& Matter.Query.ray(body, this.position, powerUp[i].position).length === 0
) {
const TARGET_VECTOR = Vector.sub(this.position, powerUp[i].position)
const DIST = Vector.magnitude(TARGET_VECTOR);
@@ -4545,7 +4296,7 @@ const b = {
Matter.Body.setVelocity(who, velocity);
}
},
targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true, damage = 1.4) {
targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, damage = 1.4) {
let shotsFired = 0
const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) {
@@ -4570,7 +4321,7 @@ const b = {
}
b.nail(position, Vector.mult(Vector.normalise(Vector.sub(WHERE, position)), speed), damage)
shotsFired++
} else if (isRandomAim) { // aim in random direction
} else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random()
b.nail(position, {
x: speed * Math.cos(ANGLE),
@@ -5634,59 +5385,9 @@ const b = {
const perp2 = Vector.mult(Vector.rotate({ x: 1, y: 0 }, m.angle + Math.PI / 2), 0.6 * this.lockedOn.radius * Math.sin(simulation.cycle / this.lookFrequency))
const path = [{ x: this.vertices[0].x, y: this.vertices[0].y }, Vector.add(this.lockedOn.position, perp2)];
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]
};
}
}
}
};
const checkForCollisions = function () {
best = {
x: 1,
y: 1,
dist2: Infinity,
who: null,
v1: 1,
v2: 1
};
vertexCollision(path[path.length - 2], path[path.length - 1], mob);
vertexCollision(path[path.length - 2], path[path.length - 1], map);
vertexCollision(path[path.length - 2], path[path.length - 1], body);
best = { x: 1, y: 1, dist2: Infinity, who: null, v1: 1, v2: 1 };
best = vertexCollision(path[path.length - 2], path[path.length - 1], [mob, map, body]);
};
const laserHitMob = function () {
if (best.who.alive) {
@@ -5717,19 +5418,13 @@ const b = {
}
if (tech.isLaserPush) { //push mobs away
const index = path.length - 1
Matter.Body.setVelocity(best.who, {
x: best.who.velocity.x * 0.97,
y: best.who.velocity.y * 0.97
});
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
Matter.Body.applyForce(best.who, path[index], force)
}
} else if (tech.isLaserPush && best.who.classType === "body") {
const index = path.length - 1
Matter.Body.setVelocity(best.who, {
x: best.who.velocity.x * 0.97,
y: best.who.velocity.y * 0.97
});
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
Matter.Body.applyForce(best.who, path[index], force)
}
@@ -5746,20 +5441,14 @@ const b = {
let lastBestOdd
let lastBestEven = best.who //used in hack below
if (best.dist2 !== Infinity) { //if hitting something
path[path.length - 1] = {
x: best.x,
y: best.y
};
path[path.length - 1] = { x: best.x, y: best.y };
laserHitMob();
for (let i = 0; i < tech.laserReflections; i++) {
reflection();
checkForCollisions();
if (best.dist2 !== Infinity) { //if hitting something
lastReflection = best
path[path.length - 1] = {
x: best.x,
y: best.y
};
path[path.length - 1] = { x: best.x, y: best.y };
damage *= reflectivity
laserHitMob();
//I'm not clear on how this works, but it gets rid of a bug where the laser reflects inside a block, often vertically.
@@ -5947,51 +5636,9 @@ const b = {
let best;
let range = tech.isPlasmaRange * (120 + 300 * Math.sqrt(Math.random()))
const path = [{ x: this.position.x, y: this.position.y }, { x: this.position.x + range * unit.x, y: this.position.y + range * unit.y }];
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 };
vertexCollision(path[0], path[1], mob);
vertexCollision(path[0], path[1], map);
vertexCollision(path[0], path[1], body);
best = vertexCollision(path[0], path[1], [mob, map, body]);
if (best.dist2 != Infinity) { //if hitting something
path[path.length - 1] = { x: best.x, y: best.y };
if (best.who.alive) {
@@ -6001,12 +5648,7 @@ const b = {
//push mobs away
const force = Vector.mult(Vector.normalise(Vector.sub(m.pos, path[1])), -0.007 * Math.min(5, best.who.mass))
Matter.Body.applyForce(best.who, path[1], force)
if (best.who.speed > 2.5) {
Matter.Body.setVelocity(best.who, { //friction
x: best.who.velocity.x * 0.75,
y: best.who.velocity.y * 0.75
});
}
if (best.who.speed > 2.5) Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.75, y: best.who.velocity.y * 0.75 });
//draw mob damage circle
if (best.who.damageReduction) {
simulation.drawList.push({
@@ -7729,7 +7371,7 @@ const b = {
charge: 0,
railDo() {
if (this.charge > 0) {
const DRAIN = (tech.isRailEnergy ? 0.0002 : 0.002)
const DRAIN = (tech.isRailEnergy ? 0 : 0.002)
//exit railgun charging without firing
if (m.energy < DRAIN) {
// m.energy += 0.025 + this.charge * 22 * this.drain

View File

@@ -229,8 +229,8 @@ function collisionChecks(event) {
y: mob[k].velocity.y - 8 * Math.sin(angle)
});
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy && mob[k].damageReduction > 0) {
m.energy -= 0.33 * Math.max(m.maxEnergy, m.energy) //0.33 * m.energy
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.1 && mob[k].damageReduction > 0) {
m.energy -= 0.1 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy
if (m.immuneCycle === m.cycle + m.collisionImmuneCycles) m.immuneCycle = 0; //player doesn't go immune to collision damage
mob[k].death();
simulation.drawList.push({ //add dmg to draw queue

View File

@@ -39,6 +39,96 @@ function shuffle(array) {
}
return array;
}
// function vertexCollision(v1, v1End, domain, best) {
// let results
// 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) {
// best = {
// x: results.x,
// y: results.y,
// dist2: dist2,
// who: domain[i],
// v1: vertices[0],
// v2: vertices[len]
// };
// }
// }
// }
// return best
// }
//this function is used for finding the point where a ray hits things, used for lasers mostly
function vertexCollision(v1, v1End, domains) { //= [map, body, [playerBody, playerHead]] //m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]
let results
let best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
for (let j = 0; j < domains.length; j++) {
let domain = domains[j]
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) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
}
}
return best
}
//collision groups
// cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.mobShield | cat.phased

View File

@@ -19,26 +19,26 @@ const level = {
// simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
// simulation.isHorizontalFlipped = true
// tech.giveTech("performance")
// level.difficultyIncrease(8 * 2) //30 is near max on hard //60 is near max on why
// m.maxHealth = m.health = 1
// level.difficultyIncrease(3 * 2) //30 is near max on hard //60 is near max on why
// m.maxHealth = m.health = 100000000
// m.maxEnergy = m.energy = 10000000
// tech.isRerollDamage = true
// powerUps.research.changeRerolls(99999)
// m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100
// m.couplingChange(10)
// m.setField("metamaterial cloaking") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// m.setField("plasma torch") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// m.energy = 0
// tech.isHookWire = true
// m.energy = 0
// simulation.molecularMode = 2
// m.damage(0.1);
// b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("drones") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") });
// for (let i = 0; i < 1; ++i) tech.giveTech("optical amplifier")
// for (let i = 0; i < 1; ++i) tech.giveTech("depolarization")
// for (let i = 0; i < 1; ++i) tech.giveTech("flame test")
// for (let i = 0; i < 1; ++i) tech.giveTech("dazzler")
// for (let i = 0; i < 1; ++i) tech.giveTech("mass production")
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") });
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) });
@@ -46,26 +46,30 @@ const level = {
// for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide")
// m.lastKillCycle = m.cycle
// for (let i = 0; i < 1; ++i) tech.giveTech("depolarization")
// for (let i = 0; i < 1; ++i) tech.giveTech("swarf")
// for (let i = 0; i < 1; ++i) tech.giveTech("CPT symmetry")
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling");
// level.arena();
// spawn.mapRect(575, -700, 25, 425); //block mob line of site on testing
// level.testing();
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
// for (let i = 0; i < 4; ++i) spawn.stinger(1900, -500)
// for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500)
// for (let i = 0; i < 1; ++i) spawn.laserLayer(1400, -500)
// Matter.Body.setPosition(player, { x: -200, y: -3330 });
// for (let i = 0; i < 4; ++i) spawn.laserLayer(1300, -500 + 100 * Math.random())
// for (let i = 0; i < 3; ++i) spawn.laser(1900, -500)
// for (let i = 0; i < 1; ++i) spawn.laserBombingBoss(1900, -2500)
// spawn.beetleBoss(1900, -500, 25)
// spawn.slasher2(2000, -1150)
// spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color)
// for (let i = 0; i < 5; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random())
// tech.addJunkTechToPool(2)
// tech.tech[322].frequency = 100
// spawn.tetherBoss(1900, -500, { x: 1900, y: -500 })
// for (let i = 0; i < 40; ++i) tech.giveTech()
level[simulation.isTraining ? "walk" : "initial"]() //normal starting level **************************************************
// for (let i = 0; i < 2; i++) spawn.ghoster(1300, -500) //ghosters need to spawn after the map loads
// spawn.bodyRect(2425, -120, 200, 200);
// console.log(body[body.length - 1].mass)
// simulation.isAutoZoom = false; //look in close
@@ -289,8 +293,8 @@ const level = {
simulation.updateTechHUD();
simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map
//pop up new level info screen for a few seconds
if (!localSettings.isHideHUD && !simulation.isChoosing && !simulation.isCheating && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor" || level.levels[level.onLevel] === "subway")) {
//pop up new level info screen for a few seconds //|| level.levels[level.onLevel] === "subway"
if (!localSettings.isHideHUD && !simulation.isCheating && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor")) {
//pause
if (!simulation.paused) {
simulation.paused = true;
@@ -325,7 +329,7 @@ const level = {
simulation.draw.cons();
simulation.draw.body();
level.customTopLayer();
let count = countMax = simulation.testing ? 0 : 180
let count = countMax = simulation.testing ? 0 : 240
let newLevelDraw = () => {
count--
if (count > 0) {
@@ -346,40 +350,46 @@ const level = {
simulation.wipe();
m.look();
simulation.camera();
// if (count < 30) {
// }
// if (count < 60) {
// simulation.draw.cons();
// simulation.draw.body();
// level.customTopLayer();
// simulation.draw.body();
// simulation.draw.drawMapPath();
// mobs.draw();
// } else
// if (count < 240) {
// ctx.lineDashOffset = 900 * Math.random()
// ctx.setLineDash([3, -8 + 0.5 * count]);
const scale = 10
const scale = 15
ctx.setLineDash([scale * (countMax - count), scale * count]);
simulation.draw.wireFrame();
ctx.setLineDash([]);
// }
// else if (count === 91) { //hide text boss
// document.getElementById("choose-grid").style.opacity = "0"
// setTimeout(() => {
// document.getElementById("choose-grid").style.visibility = "hidden"
// }, 1000);
// }
ctx.restore();
simulation.drawCursor();
}
requestAnimationFrame(newLevelDraw);
}
// else {
// //pause
// if (!simulation.paused) {
// simulation.paused = true;
// simulation.isChoosing = true; //stops p from un pausing on key down
// }
// let count = countMax = simulation.testing ? 0 : 60
// let newLevelDraw = () => {
// count--
// if (count > 0) {
// requestAnimationFrame(newLevelDraw);
// } else { //unpause
// // if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 30; //player is immune to damage for 30 cycles
// if (simulation.paused) requestAnimationFrame(cycle);
// if (m.alive) simulation.paused = false;
// simulation.isChoosing = false; //stops p from un pausing on key down
// build.unPauseGrid()
// }
// //draw
// simulation.wipe();
// m.look();
// simulation.camera();
// const scale = 30
// ctx.setLineDash([scale * (countMax - count), scale * count]);
// simulation.draw.wireFrame();
// ctx.setLineDash([]);
// ctx.restore();
// simulation.drawCursor();
// }
// requestAnimationFrame(newLevelDraw);
// }
}
},
unPause() {

197
js/mob.js
View File

@@ -505,89 +505,48 @@ const mobs = {
ctx.fill();
}
},
laser() {
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) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
}
};
if (this.seePlayer.recall && !this.isSlowed) {
const seeRange = 2500;
best = {
x: null,
y: null,
dist2: Infinity,
who: null,
v1: null,
v2: null
};
const look = {
x: this.position.x + seeRange * Math.cos(this.angle),
y: this.position.y + seeRange * Math.sin(this.angle)
};
vertexCollision(this.position, look, map);
vertexCollision(this.position, look, body);
if (!m.isCloak) vertexCollision(this.position, look, [player]);
// hitting player
if (best.who === player) {
if (m.immuneCycle < m.cycle) {
const dmg = 0.0014 * simulation.dmgScale;
m.damage(dmg);
ctx.fillStyle = "#f00"; //draw damage
ctx.beginPath();
ctx.arc(best.x, best.y, dmg * 10000, 0, 2 * Math.PI);
ctx.fill();
}
}
//draw beam
if (best.dist2 === Infinity) {
best = look;
}
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
ctx.lineTo(best.x, best.y);
ctx.strokeStyle = "#f00"; // Purple path
ctx.lineWidth = 1;
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
ctx.stroke(); // Draw it
ctx.setLineDash([]);
}
},
// laser() {
// if (this.seePlayer.recall && !this.isSlowed) {
// const seeRange = 2500;
// best = {
// x: null,
// y: null,
// dist2: Infinity,
// who: null,
// v1: null,
// v2: null
// };
// const look = {
// x: this.position.x + seeRange * Math.cos(this.angle),
// y: this.position.y + seeRange * Math.sin(this.angle)
// };
// best = vertexCollision(this.position, look, m.isCloak ? [map, body] : [map, body, [player]]);
// // hitting player
// if (best.who === player) {
// if (m.immuneCycle < m.cycle) {
// const dmg = 0.0014 * simulation.dmgScale;
// m.damage(dmg);
// ctx.fillStyle = "#f00"; //draw damage
// ctx.beginPath();
// ctx.arc(best.x, best.y, dmg * 10000, 0, 2 * Math.PI);
// ctx.fill();
// }
// }
// //draw beam
// if (best.dist2 === Infinity) {
// best = look;
// }
// ctx.beginPath();
// ctx.moveTo(this.position.x, this.position.y);
// ctx.lineTo(best.x, best.y);
// ctx.strokeStyle = "#f00"; // Purple path
// ctx.lineWidth = 1;
// ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
// ctx.stroke(); // Draw it
// ctx.setLineDash([]);
// }
// },
wing(a, radius = 250, ellipticity = 0.4, dmg = 0.0006) {
const minorRadius = radius * ellipticity
const perp = { x: Math.cos(a), y: Math.sin(a) } //
@@ -658,47 +617,6 @@ const mobs = {
ctx.fillStyle = "rgba(0,0,0,0.07)";
ctx.fill();
//spring to random place on map
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) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
}
};
//move to a random location
if (!(simulation.cycle % (this.seePlayerFreq * 4))) {
best = {
x: null,
@@ -713,8 +631,7 @@ const mobs = {
x: this.position.x + seeRange * Math.cos(this.angle),
y: this.position.y + seeRange * Math.sin(this.angle)
};
vertexCollision(this.position, look, map);
vertexCollision(this.position, look, body);
best = vertexCollision(this.position, look, [map, body]);
if (best.dist2 != Infinity) {
if (Math.random() > 0.5) {
this.springTarget.x = best.x;
@@ -1135,32 +1052,8 @@ const mobs = {
dmg *= tech.damageFromTech()
if (this.isDropPowerUp) {
if (this.health === 1) {
if (tech.isMobFullHealth) {
dmg *= 1.55
simulation.ephemera.push({
name: "damage outline",
count: 5, //cycles before it self removes
vertices: this.vertices,
do() {
this.count--
if (this.count < 0) simulation.removeEphemera(this.name)
//draw body
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
ctx.strokeStyle = `#f05` //"rgba(150,150,225,0.5)";
ctx.stroke();
},
})
} else if (tech.isMobFullHealthCloak) {
dmg *= 1.88
if (tech.isMobFullHealthCloak) {
dmg *= 2.11
simulation.ephemera.push({
name: "damage outline",
count: 7, //cycles before it self removes

View File

@@ -559,7 +559,7 @@ const m = {
// 1.25 + Math.sin(m.cycle * 0.01)
if (tech.isDiaphragm) dmg *= 0.56 + 0.36 * Math.sin(m.cycle * 0.0075);
if (tech.isZeno) dmg *= 0.15
if (tech.isFieldHarmReduction) dmg *= 0.5
if (tech.isFieldHarmReduction) dmg *= 0.65
if (tech.isHarmMACHO) dmg *= 0.4
if (tech.isImmortal) dmg *= 0.7
if (tech.energyRegen === 0) dmg *= 0.34
@@ -2192,7 +2192,7 @@ const m = {
}
},
setMaxEnergy(isMessage = true) {
m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2.66 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 1.5 * (m.fieldMode === 1) + (m.fieldMode === 0 || m.fieldMode === 1) * 0.05 * m.coupling + 0.4 * tech.isStandingWaveExpand
m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2.66 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 1.5 * (m.fieldMode === 1) + (m.fieldMode === 0 || m.fieldMode === 1) * 0.05 * m.coupling + 0.77 * tech.isStandingWaveExpand
if (isMessage) simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-f'>maxEnergy</span> <span class='color-symbol'>=</span> ${(m.maxEnergy.toFixed(2))}`)
},
fieldMeterColor: "#0cf",
@@ -2243,6 +2243,8 @@ const m = {
m.fieldRegen = 0.001667 //10 energy per second plasma torch
} else if (m.fieldMode === 8) {
m.fieldRegen = 0.001667 //10 energy per second pilot wave
} else if (m.fieldMode === 10) {
m.fieldRegen = 0.0015 //9 energy per second grappling hook
} else {
m.fieldRegen = 0.001 //6 energy per second
}
@@ -3631,15 +3633,9 @@ const m = {
// if (!this.isAttached && !mob[i].isMobBullet) this.isPopping = true
mob[i].damage(dmg);
if (mob[i].speed > 5) {
Matter.Body.setVelocity(mob[i], { //friction
x: mob[i].velocity.x * 0.6,
y: mob[i].velocity.y * 0.6
});
Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.6, y: mob[i].velocity.y * 0.6 });
} else {
Matter.Body.setVelocity(mob[i], { //friction
x: mob[i].velocity.x * 0.93,
y: mob[i].velocity.y * 0.93
});
Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.93, y: mob[i].velocity.y * 0.93 });
}
} else if (sub < dischargeRange + mob[i].radius && Matter.Query.ray(map, mob[i].position, this.position).length === 0) {
arcList.push(mob[i]) //populate electrical arc list
@@ -3684,10 +3680,7 @@ const m = {
//slowly slow down if too fast
if (this.speed > 10) {
const scale = 0.998
Matter.Body.setVelocity(this, {
x: scale * this.velocity.x,
y: scale * this.velocity.y
});
Matter.Body.setVelocity(this, { x: scale * this.velocity.x, y: scale * this.velocity.y });
}
//graphics
@@ -3703,10 +3696,7 @@ const m = {
ctx.arc(this.position.x, this.position.y, radius, 0, 2 * Math.PI);
ctx.fill();
//draw arcs
const unit = Vector.rotate({
x: 1,
y: 0
}, Math.random() * 6.28)
const unit = Vector.rotate({ x: 1, y: 0 }, Math.random() * 6.28)
let len = 8
const step = this.circleRadius / len
let x = this.position.x
@@ -3761,13 +3751,6 @@ const m = {
// m.plasmaBall.reset()
}
// 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
if (tech.isCapacitor) {
m.energy -= m.plasmaBall.drain * 2;
@@ -4233,16 +4216,14 @@ const m = {
//not shooting (or using field) enable cloak
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
if (m.fireCDcycle + 10 < m.cycle && !input.fire) { //automatically cloak if not firing
const drain = 0.02
if (!m.isCloak && m.energy > drain + 0.03) {
m.energy -= drain
// const drain = 0.02
if (!m.isCloak) { //&& m.energy > drain + 0.03
// m.energy -= drain
m.isCloak = true //enter cloak
m.fieldHarmReduction = 0.33; //66% reduction
m.enterCloakCycle = m.cycle
if (tech.isCloakHealLastHit && m.lastHit > 0) {
const heal = Math.min(0.75 * m.lastHit, m.energy)
// if (m.energy > heal) {
// m.energy -= heal * 0.8
m.addHealth(heal); //heal from last hit
m.lastHit = 0
simulation.drawList.push({ //add dmg to draw queue
@@ -4252,7 +4233,6 @@ const m = {
color: "rgba(0,255,200,0.6)",
time: 16
});
// }
}
if (tech.isIntangible) {
for (let i = 0; i < bullet.length; i++) {
@@ -4272,26 +4252,26 @@ const m = {
}
if (tech.isCloakStun) { //stun nearby mobs after exiting cloak
let isMobsAround = false
const stunRange = m.fieldDrawRadius * 1.5
const drain = 0.1
if (m.energy > drain) {
for (let i = 0, len = mob.length; i < len; ++i) {
if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) < stunRange && Matter.Query.ray(map, mob[i].position, m.pos).length === 0 && !mob[i].isBadTarget) {
isMobsAround = true
mobs.statusStun(mob[i], 180)
}
}
if (isMobsAround) {
m.energy -= drain
simulation.drawList.push({
x: m.pos.x,
y: m.pos.y,
radius: stunRange,
color: "hsla(0,50%,100%,0.7)",
time: 7
});
const stunRange = m.fieldDrawRadius * 1.25
// const drain = 0.01
// if (m.energy > drain) {
for (let i = 0, len = mob.length; i < len; ++i) {
if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) < stunRange && Matter.Query.ray(map, mob[i].position, m.pos).length === 0 && !mob[i].isBadTarget) {
isMobsAround = true
mobs.statusStun(mob[i], 120)
}
}
// if (isMobsAround) {
// m.energy -= drain
// simulation.drawList.push({
// x: m.pos.x,
// y: m.pos.y,
// radius: stunRange,
// color: "hsla(0,50%,100%,0.7)",
// time: 7
// });
// }
// }
}
}
@@ -4580,13 +4560,13 @@ const m = {
{
name: "wormhole",
//<strong class='color-worm'>wormholes</strong> attract <strong class='color-block'>blocks</strong> and power ups<br>
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+5%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+7%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
drain: 0,
effect: function () {
m.fieldMeterColor = "#bbf" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
m.duplicateChance = 0.05
m.duplicateChance = 0.07
m.fieldRange = 0
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
@@ -4639,10 +4619,7 @@ const m = {
if (dist2 < 600000) { //&& !(m.health === m.maxHealth && powerUp[i].name === "heal")
powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
Matter.Body.setVelocity(powerUp[i], { //extra friction
x: powerUp[i].velocity.x * 0.05,
y: powerUp[i].velocity.y * 0.05
});
Matter.Body.setVelocity(powerUp[i], { x: powerUp[i].velocity.x * 0.05, y: powerUp[i].velocity.y * 0.05 });
if (dist2 < 1000 && !simulation.isChoosing) { //use power up if it is close enough
// if (true) { //AoE radiation effect
@@ -4811,10 +4788,7 @@ const m = {
this.drain = tech.isFreeWormHole ? 0 : 0.05 + 0.005 * Math.sqrt(mag)
}
const unit = Vector.perp(Vector.normalise(sub))
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}
const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025))
const edge2a = Vector.add(Vector.mult(unit, 1.5 * m.fieldRange), simulation.mouseInGame)
const edge2b = Vector.add(Vector.mult(unit, -1.5 * m.fieldRange), simulation.mouseInGame)
@@ -5135,7 +5109,7 @@ const m = {
{
name: "grappling hook",
// description: `use <strong class='color-f'>energy</strong> to pull yourself towards the <strong>map</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
description: `use <strong class='color-f'>energy</strong> to fire a hook that <strong>pulls</strong> player<br><strong class='color-d'>damages</strong> mobs and grabs <strong class='color-block'>blocks</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
description: `use <strong class='color-f'>energy</strong> to fire a hook that <strong>pulls</strong> player<br><strong class='color-d'>damages</strong> mobs and grabs <strong class='color-block'>blocks</strong><br>generate <strong>9</strong> <strong class='color-f'>energy</strong> per second`,
effect: () => {
m.fieldFire = true;
// m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping
@@ -5159,7 +5133,7 @@ const m = {
m.grabPowerUp();
} 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 (tech.isHookDefense && m.energy > 0.33 && m.fieldCDcycle < m.cycle) {
if (tech.isHookDefense && m.energy > 0.15 && m.fieldCDcycle < m.cycle) {
const range = 300
for (let i = 0; i < mob.length; i++) {
if (!mob[i].isBadTarget &&
@@ -5167,7 +5141,7 @@ const m = {
Vector.magnitude(Vector.sub(m.pos, mob[i].position)) < range &&
Matter.Query.ray(map, m.pos, mob[i].position).length === 0
) {
m.energy -= 0.18
m.energy -= 0.1
if (m.fieldCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 30
const angle = Math.atan2(mob[i].position.y - player.position.y, mob[i].position.x - player.position.x);
b.harpoon(m.pos, mob[i], angle, 0.75, true, 20) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {

View File

@@ -332,7 +332,7 @@ const powerUps = {
simulation.circleFlare(0.043);
}
if (tech.isCancelRerolls) {
for (let i = 0, len = 6 + 6 * Math.random(); i < len; i++) {
for (let i = 0, len = 10 + 4 * Math.random(); i < len; i++) {
let spawnType
if (Math.random() < 0.4 && !tech.isEnergyNoAmmo) {
spawnType = "ammo"

File diff suppressed because it is too large Load Diff

View File

@@ -218,7 +218,7 @@ const tech = {
}
},
hasExplosiveDamageCheck() {
return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isHookExplosion
return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)
},
damage: 1, //used for tech changes to player damage that don't have complex conditions
damageFromTech() {
@@ -1215,6 +1215,38 @@ const tech = {
b.setFireCD();
}
},
{
name: "dynamical systems",
description: `use ${powerUps.orb.research(2)}<br><strong>+30%</strong> <strong class='color-d'>damage</strong>`,
// isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return powerUps.research.count > 1 || build.isExperimentSelection
},
requires: "",
// allowed() {
// return (m.fieldMode === 5 || m.fieldMode === 7 || m.fieldMode === 8) && (build.isExperimentSelection || powerUps.research.count > 1)
// },
// requires: "cloaking, pilot wave, or plasma torch",
damage: 1.3,
effect() {
tech.damage *= this.damage
tech.isCloakingDamage = true
for (let i = 0; i < 2; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.isCloakingDamage = false
if (this.count > 0) {
tech.damage /= this.damage
powerUps.research.changeRerolls(2)
}
}
},
{
name: "heuristics",
description: "<strong>+22%</strong> <strong><em>fire rate</em></strong><br>spawn a <strong class='color-g'>gun</strong>",
@@ -1412,24 +1444,24 @@ const tech = {
tech.healSpawn = 0;
}
},
{
name: "yield stress",
description: "<strong>+55%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return m.fieldMode !== 7 && tech.mobSpawnWithHealth === 0
},
requires: "not cloaking, reaction inhibitor",
effect() {
tech.isMobFullHealth = true
},
remove() {
tech.isMobFullHealth = false
}
},
// {
// name: "yield stress",
// description: "<strong>+55%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
// maxCount: 1,
// count: 0,
// frequency: 1,
// frequencyDefault: 1,
// allowed() {
// return m.fieldMode !== 7 && tech.mobSpawnWithHealth === 0
// },
// requires: "not cloaking, reaction inhibitor",
// effect() {
// tech.isMobFullHealth = true
// },
// remove() {
// tech.isMobFullHealth = false
// }
// },
{
name: "cascading failure",
description: "<strong>+222%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> below <strong>25%</strong> <strong>health</strong>",
@@ -1456,7 +1488,7 @@ const tech = {
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isMobFullHealth
return !tech.isMobFullHealthCloak
},
requires: "not topological defect",
effect() {
@@ -2676,6 +2708,34 @@ const tech = {
tech.isHarmArmor = false;
}
},
{
name: "tessellation",
description: `use ${powerUps.orb.research(2)}<br><strong>+35%</strong> <strong class='color-defense'>defense</strong>`,
// description: "use <strong>4</strong> <strong class='color-r'>research</strong><br>reduce <strong class='color-defense'>defense</strong> by <strong>50%</strong>",
// isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return powerUps.research.count > 1 || build.isExperimentSelection
},
requires: "",
// allowed() {
// return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 3)
// },
// requires: "perfect diamagnetism, negative mass, grappling hook, pilot wave",
effect() {
tech.isFieldHarmReduction = true
for (let i = 0; i < 2; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.isFieldHarmReduction = false
if (this.count > 0) powerUps.research.changeRerolls(2)
}
},
{
name: "Pauli exclusion",
description: `after mob collisions<br>become <strong>invulnerable</strong> for <strong>+3.5</strong> seconds`,
@@ -2796,14 +2856,14 @@ const tech = {
},
{
name: "heat engine",
description: `<strong>+50%</strong> <strong class='color-d'>damage</strong><br><strong>50</strong> maximum <strong class='color-f'>energy</strong>`,
description: `<strong>+40%</strong> <strong class='color-d'>damage</strong><br><strong>50</strong> maximum <strong class='color-f'>energy</strong>`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed: () => true,
requires: "not CPT",
damage: 1.5,
damage: 1.4,
effect() {
tech.damage *= this.damage
tech.isMaxEnergyTech = true;
@@ -4184,7 +4244,7 @@ const tech = {
{
name: "commodities exchange",
descriptionFunction() {
return `clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns <strong>6-12</strong> ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
return `clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns <strong>10-14</strong> ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
},
maxCount: 1,
count: 0,
@@ -4912,7 +4972,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
return tech.hookNails + tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
},
requires: "nails, nail gun, rivets, shotgun, super balls, mine",
effect() {
@@ -4951,7 +5011,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || ((tech.isMineDrop || tech.haveGunCheck("mine")) && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot))
return tech.isNailBotUpgrade || tech.hookNails || tech.fragments || tech.nailsDeathMob || ((tech.isMineDrop || tech.haveGunCheck("mine")) && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot))
},
requires: "nail gun, nails, rivets, mine, not ceramic needles",
effect() {
@@ -5842,7 +5902,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || tech.isHookExplosion || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
},
requires: "an explosive damage source, not rocket propelled grenade",
effect() {
@@ -6123,7 +6183,7 @@ const tech = {
frequencyDefault: 2,
allowed() {
// return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines"))
return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles)
return tech.isMineDrop || tech.isNailBotUpgrade || tech.hookNails || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles)
},
//
requires: "nail gun, not rotary cannon, rivets, or needles",
@@ -7074,7 +7134,7 @@ const tech = {
// },
{
name: "alternator",
description: "<strong>+90%</strong> <strong>harpoon</strong> <strong class='color-f'>energy</strong> efficiency",
description: "<strong>harpoon</strong> no longer uses any <strong class='color-f'>energy</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -7113,7 +7173,7 @@ const tech = {
{
name: "Bessemer process",
descriptionFunction() {
return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}% <strong>harpoon</strong> size and <strong class='color-d'>damage</strong><br><em>(1/10 √ harpoon <strong class='color-ammo'>ammo</strong>)</em>`
return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}% <strong>harpoon</strong> size and <strong class='color-d'>damage</strong><br><em>(effect scales by 1/10 √ harpoon <strong class='color-ammo'>ammo</strong>)</em>`
},
isGunTech: true,
maxCount: 1,
@@ -7179,7 +7239,7 @@ const tech = {
{
name: "UHMWPE",
descriptionFunction() {
return `+${(b.guns[9].ammo * 1.25).toFixed(0)}% <strong>harpoon</strong> <strong>rope</strong> <strong>length</strong><br><em>(1/80 of harpoon <strong class='color-ammo'>ammo</strong>)</em>`
return `+${(b.guns[9].ammo * 1.25).toFixed(0)}% <strong>harpoon</strong> <strong>rope</strong> <strong>length</strong><br><em>(effect scales by 1/80 of harpoon <strong class='color-ammo'>ammo</strong>)</em>`
},
isGunTech: true,
maxCount: 1,
@@ -7219,7 +7279,7 @@ const tech = {
},
{
name: "brittle",
description: "<strong>+88%</strong> <strong>harpoon</strong>/<strong>grapple</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
description: "<strong>+111%</strong> <strong>harpoon</strong>/<strong>grapple</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -7673,7 +7733,7 @@ const tech = {
},
{
name: "zero point energy",
description: `use ${powerUps.orb.research(2)}<br><strong>+100</strong> maximum <strong class='color-f'>energy</strong>`,
description: `use ${powerUps.orb.research(2)}<br><strong>+166</strong> maximum <strong class='color-f'>energy</strong>`,
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -7684,7 +7744,7 @@ const tech = {
},
requires: "standing wave, pilot wave, time dilation",
effect() {
tech.harmonicEnergy = 1
tech.harmonicEnergy = 1.66
m.setMaxEnergy()
for (let i = 0; i < 2; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
@@ -7698,7 +7758,7 @@ const tech = {
},
{
name: "expansion",
description: "using <strong>standing wave</strong> field <strong>expands</strong> its <strong>radius</strong><br><strong>+40</strong> maximum <strong class='color-f'>energy</strong>",
description: "using <strong>standing wave</strong> field <strong>expands</strong> its <strong>radius</strong><br><strong>+77</strong> maximum <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -7860,30 +7920,6 @@ const tech = {
tech.isBigField = false;
}
},
{
name: "tessellation",
description: `use ${powerUps.orb.research(2)}<br><strong>+50%</strong> <strong class='color-defense'>defense</strong>`,
// description: "use <strong>4</strong> <strong class='color-r'>research</strong><br>reduce <strong class='color-defense'>defense</strong> by <strong>50%</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 3)
},
requires: "perfect diamagnetism, negative mass, grappling hook, pilot wave",
effect() {
tech.isFieldHarmReduction = true
for (let i = 0; i < 2; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.isFieldHarmReduction = false
if (this.count > 0) powerUps.research.changeRerolls(2)
}
},
{
name: "radiative equilibrium",
descriptionFunction() {
@@ -7978,7 +8014,7 @@ const tech = {
},
{
name: "annihilation",
description: "after <strong>colliding</strong> with non-boss mobs<br>they are <strong>annihilated</strong> and <strong>33%</strong> <strong class='color-f'>energy</strong>",
description: "after <strong>colliding</strong> with non-boss mobs<br>they are <strong>annihilated</strong> and <strong>10</strong> <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -8291,9 +8327,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldMode === 5 || m.fieldMode === 6 || m.fieldMode === 7 || m.fieldMode === 8 || m.fieldMode === 4
return m.fieldMode === 6 || m.fieldMode === 7 || m.fieldMode === 8
},
requires: "cloaking, molecular assembler, plasma torch, pilot wave",
requires: "time dilation, cloaking, pilot wave",
damage: 1.35,
effect() {
tech.damage *= this.damage
@@ -8315,9 +8351,9 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) && !tech.isPrinter && !tech.isReel && !tech.isHookExplosion
return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) && !tech.isPrinter && !tech.isReel && !tech.hookNails
},
requires: "plasma torch, molecular assembler, grappling hook, not printer, reel, rupture",
requires: "plasma torch, molecular assembler, grappling hook, not printer, reel, swarf",
effect() {
tech.isTokamak = true;
},
@@ -8705,7 +8741,7 @@ const tech = {
{
name: "dazzler",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Dazzler_(weapon)' class="link">dazzler</a>`,
description: "after <strong class='color-cloaked'>decloaking</strong> <strong>stun</strong> nearby mobs<br>and drain <strong>10</strong> <strong class='color-f'>energy</strong>",
description: "after <strong class='color-cloaked'>decloaking</strong><br><strong>stun</strong> nearby mobs for 2 second",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -8724,16 +8760,16 @@ const tech = {
},
{
name: "topological defect",
description: "<strong>+88%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
description: "<strong>+111%</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return (m.fieldMode === 8 || m.fieldMode === 7) && tech.mobSpawnWithHealth === 0 && !tech.isMobFullHealth
return (m.fieldMode === 8 || m.fieldMode === 7) && tech.mobSpawnWithHealth === 0
},
requires: "cloaking, pilot wave, not reaction inhibitor, yield stress",
requires: "cloaking, pilot wave, not reaction inhibitor",
effect() {
tech.isMobFullHealthCloak = true
},
@@ -8760,34 +8796,6 @@ const tech = {
// tech.sneakAttackDmg = 4.33 //333% + 100%
// }
// },
{
name: "dynamical systems",
description: `use ${powerUps.orb.research(2)}<br><strong>+35%</strong> <strong class='color-d'>damage</strong>`,
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldMode === 5 || m.fieldMode === 7 || m.fieldMode === 8) && (build.isExperimentSelection || powerUps.research.count > 1)
},
requires: "cloaking, pilot wave, or plasma torch",
damage: 1.35,
effect() {
tech.damage *= this.damage
tech.isCloakingDamage = true
for (let i = 0; i < 2; i++) {
if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
}
},
remove() {
tech.isCloakingDamage = false
if (this.count > 0) {
tech.damage /= this.damage
powerUps.research.changeRerolls(2)
}
}
},
{
name: "WIMPs",
description: `at the end of each <strong>level</strong> spawn ${powerUps.orb.research(4)}<br> and a dangerous particle that slowly <strong>chases</strong> you`,
@@ -8818,9 +8826,9 @@ const tech = {
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9 || m.fieldMode === 10) && (build.isExperimentSelection || powerUps.research.count > 2)
return (m.fieldMode === 8 || m.fieldMode === 6 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2)
},
requires: "wormhole, time dilation, negative mass, pilot wave, grappling hook",
requires: "wormhole, time dilation, negative mass, pilot wave",
effect() {
tech.fieldDuplicate = 0.11
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
@@ -8988,7 +8996,7 @@ const tech = {
},
{
name: "CIWS",
description: "<strong>grappling hook</strong> uses <strong>18</strong> <strong class='color-f'>energy</strong><br> to fire <strong>harpoons</strong> at nearby mobs",
description: "<strong>grappling hook</strong> uses <strong>10</strong> <strong class='color-f'>energy</strong><br> to fire <strong>harpoons</strong> at nearby mobs",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -9006,10 +9014,11 @@ const tech = {
}
},
{
name: "rupture",
description: "after <strong>grappling hook</strong> impacts solid objects<br>generate an <strong class='color-e'>explosion</strong>",
name: "swarf",
// description: "after <strong>grappling hook</strong> impacts solid objects generate an <strong class='color-e'>explosion</strong> and become briefly <strong>invulnerable</strong>",
description: "after <strong>grappling hook</strong> impacts something<br>eject <strong>nails</strong> splinters towards nearby mobs",
isFieldTech: true,
maxCount: 1,
maxCount: 3,
count: 0,
frequency: 2,
frequencyDefault: 2,
@@ -9018,24 +9027,24 @@ const tech = {
},
requires: "grappling hook, not reel, tokamak",
effect() {
tech.isHookExplosion = true
tech.hookNails += 4
},
remove() {
tech.isHookExplosion = false
tech.hookNails = 0
}
},
{
name: "reel",
description: "<strong>+400%</strong> <strong class='color-block'>block</strong> collision <strong class='color-d'>damage</strong><br><strong>+30</strong> <strong class='color-f'>energy</strong> when reeling in far away <strong class='color-block'>blocks</strong>",
description: "<strong>+400%</strong> <strong class='color-block'>block</strong> collision <strong class='color-d'>damage</strong><br>up to <strong>+75</strong> <strong class='color-f'>energy</strong> after reeling in <strong class='color-block'>blocks</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return m.fieldMode === 10 && !tech.isTokamak && tech.blockDamage === 0.075 && !tech.isHookExplosion
return m.fieldMode === 10 && !tech.isTokamak && tech.blockDamage === 0.075 && !tech.hookNails
},
requires: "grappling hook, not mass driver, rupture, tokamak",
requires: "grappling hook, not mass driver, swarf, tokamak",
effect() {
tech.blockDamage = 0.375
tech.isReel = true
@@ -11910,7 +11919,7 @@ const tech = {
isFastFoam: null,
isSporeGrowth: null,
isStimulatedEmission: null,
nailGun: null,
// nailGun: null,
nailInstantFireRate: null,
isCapacitor: null,
isEnergyNoAmmo: null,
@@ -12148,12 +12157,11 @@ const tech = {
isPrinter: null,
// isHookWire: null,
isHookDefense: null,
isHookExplosion: null,
hookNails: null,
isHarpoonDefense: null,
isReel: null,
harpoonPowerUpCycle: null,
isHarpoonFullHealth: null,
isMobFullHealth: null,
isMobFullHealthCloak: null,
isMobLowHealth: null,
isDamageCooldown: null,