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

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

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,

View File

@@ -1,16 +1,71 @@
******************************************************** NEXT PATCH **************************************************
tech: hyperpolarization - reduce the CD on depolarization by 1 second
mob: laserLayer - leaves behind lasers that persist for a few seconds
ghoster mobs do 66% less damage, but they eject your ammo
metamaterial absorber 22->25% chance to get power up for mobs not killed
symbiosis -0.5 -> 0.25 max health after killing a mob
dazzler -15->10 energy after decloaking and stunning mobs
Hilbert space 142->300% damage
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...
fixed bug with 1000x more frequent enthalpy
*********************************************************** TODO *****************************************************
increase damage for each not picked up power up on the level
make a laserLayerBoss
add lasers on player's history
button/switch input ideas from Cocoon game
pick up blocks that have a rubber band attached to a sliding switch
as player moves the vector direction of the rubber band will move the slider left or right
use this to open doors, move larger blocks, ...
switches that toggle left, right when player presses input.field while standing nearby
replace laser off on switch?
platform that rises up when player presses input.field while standing
How to instruct player to use field on these?
color with field #0ff
draw field effect
make it still functional without the field button
tech: - getting a new gun also gives you 2 random tech for that gun
or a field?
can these guntech tech be converted into a player choice?
tech: interest - research and ammo increases by 10% at the start of each level?
spawn research and ammo at start of new level
extend to current health?
how to reduce the number of clicks and keypresses
auto fire mode
player shoots at whatever is nearby
should player have to look towards mobs?
increase ammo?
animate egg laying mobs
just draw a circle when it happens?
improve new player experience
training is too long to be a tutorial
before nail gun level offer player option to continue or switch to normal game
@@ -51,7 +106,7 @@ make grappling hook of different shapes
longer
circular with spikes
indicate tech upgrades?
rupture, reel, tokamak
swarf, reel, tokamak
do this in draw or in verticies?
draw can have different colors
@@ -1097,6 +1152,7 @@ possible names for tech
Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity
Unruh effect - accelerating makes heat/thermal particles
configuration space - holds the position of everything
stressenergy tensor
******************************************************** CARS IMAGES ********************************************************