tech: fleas - replace spores with little hoppers

frame-dragging - time dilation field stops time when you aren't moving or firing, +33% defense
  the odds of finding this tech is low because I find it kinda annoying, but maybe you will like it

molecular assembler field energy meter is yellow
  wormhole is lavender
  perfect diamagnetism is blue
  time dilation is green blue
  pilot wave is black

new room in labs:  hopBossMom
harpoon now auto targets by default, but disabled when crouched
pulse + neocognitron auto targeting also disabled when crouched

bug fixes
This commit is contained in:
landgreen
2022-07-12 07:52:13 -07:00
parent fc12f85f17
commit 4e29a517fc
10 changed files with 738 additions and 270 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -583,7 +583,7 @@ const b = {
v1: null, v1: null,
v2: null v2: null
}; };
if (tech.isPulseAim) { //find mobs in line of sight if (tech.isPulseAim && input.down) { //find mobs in line of sight
let dist = 2200 let dist = 2200
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position))
@@ -2386,9 +2386,9 @@ const b = {
if (best.who.alive) { if (best.who.alive) {
best.who.locatePlayer(); best.who.locatePlayer();
if (best.who.damageReduction) { if (best.who.damageReduction) {
if ( //crit if ( //iridescence
tech.laserCrit && !best.who.shield && tech.laserCrit && !best.who.shield &&
Vector.dot(Vector.normalise(Vector.sub(best.who.position, path[path.length - 1])), Vector.normalise(Vector.sub(path[path.length - 1], path[path.length - 2]))) > 0.99 - 0.6 / best.who.radius Vector.dot(Vector.normalise(Vector.sub(best.who.position, path[path.length - 1])), Vector.normalise(Vector.sub(path[path.length - 1], path[path.length - 2]))) > 0.995 - 0.6 / best.who.radius
) { ) {
damage *= 1 + tech.laserCrit damage *= 1 + tech.laserCrit
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
@@ -2663,8 +2663,7 @@ const b = {
!mob[i].isBadTarget && !mob[i].isBadTarget &&
Vector.magnitude(Vector.sub(this.position, mob[i].position)) < 700 + mob[i].radius + random && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < 700 + mob[i].radius + random &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 && Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0 && Matter.Query.ray(body, this.position, mob[i].position).length === 0
!mob[i].isInvulnerable
) { ) {
if (tech.isStun) b.AoEStunEffect(this.position, 700 + mob[i].radius + random); //AoEStunEffect(where, range, cycles = 90 + 60 * Math.random()) { if (tech.isStun) b.AoEStunEffect(this.position, 700 + mob[i].radius + random); //AoEStunEffect(where, range, cycles = 90 + 60 * Math.random()) {
if (tech.isMineSentry) { if (tech.isMineSentry) {
@@ -2961,7 +2960,7 @@ const b = {
friction: 0, friction: 0,
frictionAir: 0.023, frictionAir: 0.023,
restitution: 0.9, restitution: 0.9,
dmg: 1, //damage done in addition to the damage from momentum dmg: 1.2, //damage done in addition to the damage from momentum
lookFrequency: 14 + Math.floor(8 * Math.random()), lookFrequency: 14 + Math.floor(8 * Math.random()),
endCycle: simulation.cycle + 100 * tech.isBulletsLastLonger + Math.floor(25 * Math.random()), endCycle: simulation.cycle + 100 * tech.isBulletsLastLonger + Math.floor(25 * Math.random()),
classType: "bullet", classType: "bullet",
@@ -3022,6 +3021,128 @@ const b = {
// y: m.Vy / 2 + speed * Math.sin(dir) // y: m.Vy / 2 + speed * Math.sin(dir)
// }); // });
}, },
flea(where, velocity, radius = 7 + 3 * Math.random()) {
const me = bullet.length;
bullet[me] = Bodies.polygon(where.x, where.y, 5, radius, {
isFlea: true,
angle: 0.5 * Math.random(),
friction: 1,
frictionStatic: 1,
frictionAir: 0, //0.01,
restitution: 0,
density: 0.0005, // 0.001 is normal density
dmg: 9 * (tech.isMutualism ? 2.5 : 1), //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18
lookFrequency: 19 + Math.floor(11 * Math.random()),
endCycle: simulation.cycle + Math.floor((780 * tech.isBulletsLastLonger + 360 * Math.random()) + Math.max(0, 150 - bullet.length)), // 13 - 19s
classType: "bullet",
collisionFilter: {
category: cat.bullet,
mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
},
minDmgSpeed: 0,
lockedOn: null,
delay: 50,
cd: simulation.cycle + 10,
beforeDmg(who) {
// this.endCycle = 0
Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target
this.endCycle -= 180
this.cd = simulation.cycle + this.delay;
// this.collisionFilter.mask = cat.map
if (tech.isSporeFreeze) mobs.statusSlow(who, 90)
if (tech.isSpawnBulletsOnDeath && who.alive && who.isDropPowerUp) {
setTimeout(() => {
if (!who.alive) {
for (let i = 0; i < 3; i++) { //spawn 3 more
const speed = 10 + 5 * Math.random()
const angle = 2 * Math.PI * Math.random()
b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) })
}
}
this.endCycle = 0;
}, 1);
}
},
onEnd() {},
gravity: 0.002 + 0.002 * tech.isSporeFollow,
do() {
// if (true && this.lockedOn && this.cd < simulation.cycle) { //blink towards mobs
// //needs it's own cooldown variables
// // this.cd = simulation.cycle + this.delay;
// const sub = Vector.sub(this.lockedOn.position, this.position);
// const distMag = Vector.magnitude(sub);
// if (distMag < 500) {
// const unit = Vector.normalise(sub)
// Matter.Body.setVelocity(this, Vector.mult(unit, Math.max(20, this.speed * 1.5)));
// ctx.beginPath();
// ctx.moveTo(this.position.x, this.position.y);
// Matter.Body.translate(this, Vector.mult(unit, Math.min(350, distMag - this.lockedOn.radius + 10)));
// ctx.lineTo(this.position.x, this.position.y);
// ctx.lineWidth = radius * 2;
// ctx.strokeStyle = "rgba(0,0,0,0.5)";
// ctx.stroke();
// }
// }
this.force.y += this.gravity * this.mass
if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { //if on the ground and not on jump cooldown //
// this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield
this.cd = simulation.cycle + this.delay;
this.lockedOn = null; //find a target
let closeDist = Infinity;
for (let i = 0, len = mob.length; i < len; ++i) {
if (
!mob[i].isBadTarget &&
!mob[i].isInvulnerable &&
mob[i].alive &&
this.position.y - mob[i].position.y < 1500 && //this is about how high fleas can jump with capMaxY = 0.12 + 0.04 * Math.random()
this.position.y - mob[i].position.y > -300 && //not too far below the flea (note that fleas should be on the ground most of the time when doing this check)
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0
) {
const TARGET_VECTOR = Vector.sub(this.position, mob[i].position)
const DIST = Vector.magnitude(TARGET_VECTOR);
if (DIST < closeDist) {
closeDist = DIST;
this.lockedOn = mob[i]
}
}
}
if (tech.isSporeFollow && !this.lockedOn && Matter.Query.ray(map, this.position, m.pos).length === 0) {
this.lockedOn = { //make target player if there are no mobs to target
position: m.pos,
velocity: { x: 0, y: 0 }
}
}
if (this.lockedOn) { //hop towards mob target
const where = Vector.add(this.lockedOn.position, Vector.mult(this.lockedOn.velocity, 5)) //estimate where the mob will be in 5 cycles
const Dy = Math.max(0, this.position.y - where.y) //can't be negative because you can't hop down
const Dx = this.position.x - where.x
const Vx = -0.06 * Dx / Math.sqrt(2 * Dy / this.gravity) //calibrated to hit target, don't mess with this
const Vy = 0.085 * Math.sqrt(this.gravity * Dy) //calibrated to hit target, don't mess with this
const capX = 0.07 + 0.02 * tech.isSporeFollow
const capMaxY = 0.12 + 0.04 * Math.random() + 0.05 * tech.isSporeFollow
const capMinY = closeDist > 500 ? 0.05 + 0.02 * Math.random() : 0.02 + 0.01 * Math.random() //don't jump super low, unless you are very close to mob target
this.force.x = Math.max(-capX, Math.min(capX, Vx)) * this.mass;
this.force.y = -Math.max(capMinY, Math.min(capMaxY, Vy)) * this.mass
} else { //random hops
if (Math.random() < 0.5) { //chance to continue in the same horizontal direction
this.force.x = (0.01 + 0.03 * Math.random()) * this.mass * (this.velocity.x > 0 ? 1 : -1); //random move
} else {
this.force.x = (0.01 + 0.03 * Math.random()) * this.mass * (Math.random() < 0.5 ? 1 : -1); //random move
}
this.force.y = -(0.03 + 0.08 * Math.random()) * this.mass
}
Matter.Body.setVelocity(this, { x: 0, y: 0 });
}
}
})
Composite.add(engine.world, bullet[me]); //add bullet to world
Matter.Body.setVelocity(bullet[me], velocity);
},
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 me = bullet.length;
const THRUST = 0.0015 const THRUST = 0.0015
@@ -3774,7 +3895,13 @@ const b = {
this.force.y += this.mass * tech.foamGravity; //gravity this.force.y += this.mass * tech.foamGravity; //gravity
if (tech.isFoamAttract) { if (tech.isFoamAttract) {
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (!mob[i].isBadTarget && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { if (
!mob[i].isBadTarget &&
Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 &&
mob[i].alive &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
!mob[i].isInvulnerable
) {
this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004) this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004)
const slow = 0.9 const slow = 0.9
Matter.Body.setVelocity(this, { Matter.Body.setVelocity(this, {
@@ -3800,7 +3927,7 @@ const b = {
targetedBlock(who, speed = 50 - Math.min(20, who.mass * 2), range = 1600) { targetedBlock(who, speed = 50 - Math.min(20, who.mass * 2), range = 1600) {
let closestMob, dist let closestMob, dist
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (who !== mob[i] && !mob[i].isBadTarget) { if (who !== mob[i] && !mob[i].isBadTarget && !mob[i].isInvulnerable) {
dist = Vector.magnitude(Vector.sub(who.position, mob[i].position)); dist = Vector.magnitude(Vector.sub(who.position, mob[i].position));
if (dist < range && Matter.Query.ray(map, who.position, mob[i].position).length === 0) { //&& Matter.Query.ray(body, position, mob[i].position).length === 0 if (dist < range && Matter.Query.ray(map, who.position, mob[i].position).length === 0) { //&& Matter.Query.ray(body, position, mob[i].position).length === 0
closestMob = mob[i] closestMob = mob[i]
@@ -4331,7 +4458,7 @@ const b = {
minDmgSpeed: 2, minDmgSpeed: 2,
// lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20, // lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20,
lastLookCycle: simulation.cycle + 60 * Math.random(), lastLookCycle: simulation.cycle + 60 * Math.random(),
delay: Math.floor((tech.isNailBotUpgrade ? 21 : 110) * b.fireCDscale), delay: Math.floor((tech.isNailBotUpgrade ? 20 : 105) * b.fireCDscale),
acceleration: 0.005 * (1 + 0.5 * Math.random()), acceleration: 0.005 * (1 + 0.5 * Math.random()),
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(), range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(),
endCycle: Infinity, endCycle: Infinity,
@@ -4492,7 +4619,7 @@ const b = {
let target let target
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
const dist2 = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)); const dist2 = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist2 < 1000000 && !mob[i].isBadTarget && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { if (dist2 < 1000000 && !mob[i].isBadTarget && Matter.Query.ray(map, this.position, mob[i].position).length === 0 && !mob[i].isInvulnerable) {
this.cd = simulation.cycle + this.delay; this.cd = simulation.cycle + this.delay;
target = Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist2) / 60)) target = Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist2) / 60))
const radius = 6 + 7 * Math.random() const radius = 6 + 7 * Math.random()
@@ -4523,10 +4650,7 @@ const b = {
restitution: 0.5 * (1 + 0.5 * Math.random()), restitution: 0.5 * (1 + 0.5 * Math.random()),
acceleration: 0.0015 * (1 + 0.3 * Math.random()), acceleration: 0.0015 * (1 + 0.3 * Math.random()),
playerRange: 140 + Math.floor(30 * Math.random()) + 2 * b.totalBots(), playerRange: 140 + Math.floor(30 * Math.random()) + 2 * b.totalBots(),
offPlayer: { offPlayer: { x: 0, y: 0, },
x: 0,
y: 0,
},
dmg: 0, //damage done in addition to the damage from momentum dmg: 0, //damage done in addition to the damage from momentum
minDmgSpeed: 2, minDmgSpeed: 2,
lookFrequency: 40 + Math.floor(7 * Math.random()) - 10 * tech.isLaserBotUpgrade, lookFrequency: 40 + Math.floor(7 * Math.random()) - 10 * tech.isLaserBotUpgrade,
@@ -4562,11 +4686,14 @@ const b = {
let closeDist = this.range; let closeDist = this.range;
for (let i = 0, len = mob.length; i < len; ++i) { for (let i = 0, len = mob.length; i < len; ++i) {
const DIST = Vector.magnitude(Vector.sub(this.vertices[0], mob[i].position)); const DIST = Vector.magnitude(Vector.sub(this.vertices[0], mob[i].position));
if (DIST - mob[i].radius < closeDist && if (
DIST - mob[i].radius < closeDist &&
!mob[i].isShielded && !mob[i].isShielded &&
(!mob[i].isBadTarget || mob[i].isMobBullet) && (!mob[i].isBadTarget || mob[i].isMobBullet) &&
Matter.Query.ray(map, this.vertices[0], mob[i].position).length === 0 && Matter.Query.ray(map, this.vertices[0], mob[i].position).length === 0 &&
Matter.Query.ray(body, this.vertices[0], mob[i].position).length === 0) { Matter.Query.ray(body, this.vertices[0], mob[i].position).length === 0 &&
!mob[i].isInvulnerable
) {
closeDist = DIST; closeDist = DIST;
this.lockedOn = mob[i] this.lockedOn = mob[i]
} }
@@ -4686,10 +4813,13 @@ const b = {
let closeDist = this.range; let closeDist = this.range;
for (let i = 0, len = mob.length; i < len; ++i) { for (let i = 0, len = mob.length; i < len; ++i) {
const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius; const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius;
if (DIST < closeDist && if (
DIST < closeDist &&
!mob[i].isBadTarget && !mob[i].isBadTarget &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 && Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) { Matter.Query.ray(body, this.position, mob[i].position).length === 0 &&
!mob[i].isInvulnerable
) {
closeDist = DIST; closeDist = DIST;
this.lockedOn = mob[i] this.lockedOn = mob[i]
} }
@@ -4842,7 +4972,7 @@ const b = {
y: best.y y: best.y
}; };
if (best.who.alive) { if (best.who.alive) {
const dmg = 0.6 * m.dmgScale; //********** SCALE DAMAGE HERE ********************* const dmg = 0.65 * m.dmgScale; //********** SCALE DAMAGE HERE *********************
best.who.damage(dmg); best.who.damage(dmg);
best.who.locatePlayer(); best.who.locatePlayer();
//push mobs away //push mobs away
@@ -4948,7 +5078,7 @@ const b = {
}) })
for (let i = 0; i < q.length; i++) { for (let i = 0; i < q.length; i++) {
if (!q[i].isShielded) { if (!q[i].isShielded) {
mobs.statusStun(q[i], 180) mobs.statusStun(q[i], 210)
const dmg = 0.4 * m.dmgScale * (this.isUpgraded ? 4 : 1) * (tech.isCrit ? 4 : 1) const dmg = 0.4 * m.dmgScale * (this.isUpgraded ? 4 : 1) * (tech.isCrit ? 4 : 1)
q[i].damage(dmg); q[i].damage(dmg);
if (q[i].alive) q[i].foundPlayer(); if (q[i].alive) q[i].foundPlayer();
@@ -6273,12 +6403,17 @@ const b = {
this.stuck(); //runs different code based on what the bullet is stuck to this.stuck(); //runs different code based on what the bullet is stuck to
let scale = 1.01 let scale = 1.01
if (tech.isSporeGrowth && !(simulation.cycle % 40)) { //release a spore if (tech.isSporeGrowth && !(simulation.cycle % 40)) { //release a spore
if (tech.isSporeWorm) { if (tech.isSporeFlea) {
if (!(simulation.cycle % 80)) {
const speed = 10 + 5 * Math.random()
const angle = 2 * Math.PI * Math.random()
b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) })
}
} else if (tech.isSporeWorm) {
if (!(simulation.cycle % 80)) b.worm(this.position) if (!(simulation.cycle % 80)) b.worm(this.position)
} else { } else {
b.spore(this.position) b.spore(this.position)
} }
// this.totalSpores--
scale = 0.96 scale = 0.96
if (this.stuckTo && this.stuckTo.alive) scale = 0.9 if (this.stuckTo && this.stuckTo.alive) scale = 0.9
Matter.Body.scale(this, scale, scale); Matter.Body.scale(this, scale, scale);
@@ -6289,18 +6424,21 @@ const b = {
this.radius *= scale this.radius *= scale
if (this.radius > this.maxRadius) this.endCycle = 0; if (this.radius > this.maxRadius) this.endCycle = 0;
} }
// this.force.y += this.mass * 0.00045;
//draw green glow //draw green glow
ctx.fillStyle = "rgba(0,200,125,0.16)"; ctx.fillStyle = "rgba(0,200,125,0.16)";
ctx.beginPath(); ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI); ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI);
ctx.fill(); ctx.fill();
}; };
//spawn bullets on end //spawn bullets on end
bullet[me].onEnd = function() { bullet[me].onEnd = function() {
if (tech.isSporeWorm) { if (tech.isSporeFlea) {
for (let i = 0, len = this.totalSpores * 0.5; i < len; i++) {
const speed = 10 + 5 * Math.random()
const angle = 2 * Math.PI * Math.random()
b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) })
}
} else if (tech.isSporeWorm) {
for (let i = 0, len = this.totalSpores * 0.5; i < len; i++) b.worm(this.position) for (let i = 0, len = this.totalSpores * 0.5; i < len; i++) b.worm(this.position)
} else { } else {
for (let i = 0; i < this.totalSpores; i++) b.spore(this.position) for (let i = 0; i < this.totalSpores; i++) b.spore(this.position)
@@ -6549,7 +6687,7 @@ const b = {
if (dot > 0.95 - Math.min(dist * 0.00015, 0.3)) { //lower dot product threshold for targeting then if you only have one harpoon //target closest mob that player is looking at and isn't too close to target if (dot > 0.95 - Math.min(dist * 0.00015, 0.3)) { //lower dot product threshold for targeting then if you only have one harpoon //target closest mob that player is looking at and isn't too close to target
// if (this.ammo > -1) { // if (this.ammo > -1) {
// this.ammo-- // this.ammo--
b.harpoon(where, input.down ? mob[i] : null, angle, harpoonSize, false) //Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 }) b.harpoon(where, input.down ? null : mob[i], angle, harpoonSize, false) //Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 })
angle += SPREAD angle += SPREAD
targetCount++ targetCount++
if (targetCount > tech.extraHarpoons) break if (targetCount > tech.extraHarpoons) break
@@ -6574,7 +6712,7 @@ const b = {
//look for closest mob in player's LoS //look for closest mob in player's LoS
const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product
for (let i = 0, len = mob.length; i < len; ++i) { for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0) { if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0 && !mob[i].isInvulnerable) {
const dot = Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, m.pos))) //the dot product of diff and dir will return how much over lap between the vectors const dot = Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, m.pos))) //the dot product of diff and dir will return how much over lap between the vectors
const dist = Vector.magnitude(Vector.sub(where, mob[i].position)) const dist = Vector.magnitude(Vector.sub(where, mob[i].position))
if (dist < closest.distance && dot > 0.98 - Math.min(dist * 0.00014, 0.3)) { //target closest mob that player is looking at and isn't too close to target if (dist < closest.distance && dot > 0.98 - Math.min(dist * 0.00014, 0.3)) { //target closest mob that player is looking at and isn't too close to target
@@ -7066,7 +7204,11 @@ const b = {
fire() {}, fire() {},
chooseFireMethod() { chooseFireMethod() {
this.lensDamage = 1 this.lensDamage = 1
if (tech.isLaserLens) this.do = this.lens if (tech.isLaserLens) {
this.do = this.lens
} else {
this.do = this.stuckOn
}
if (tech.isPulseLaser) { if (tech.isPulseLaser) {
this.fire = () => { this.fire = () => {
const drain = 0.01 * tech.isLaserDiode * (tech.isCapacitor ? 10 : 1) const drain = 0.01 * tech.isLaserDiode * (tech.isCapacitor ? 10 : 1)

View File

@@ -263,9 +263,8 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${build.nameLink(b.guns[b.inventory[i]].name)} - <span style="font-size:100%;font-weight: 100;">${b.guns[b.inventory[i]].ammo}</span></div> ${b.guns[b.inventory[i]].description}</div>` text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${build.nameLink(b.guns[b.inventory[i]].name)} - <span style="font-size:100%;font-weight: 100;">${b.guns[b.inventory[i]].ammo}</span></div> ${b.guns[b.inventory[i]].description}</div>`
} }
let el = document.getElementById("pause-grid-left") let el = document.getElementById("pause-grid-left")
el.style.display = "grid" el.style.display = tech.isNoDraftPause ? "none" : "grid" //disabled for eternalism because eternalism lets the player play while this menu is up but the menu doesn't update
el.innerHTML = text el.innerHTML = text
//right side //right side
text = ""; text = "";
if (tech.isPauseSwitchField && !simulation.isChoosing) { if (tech.isPauseSwitchField && !simulation.isChoosing) {
@@ -304,7 +303,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
} }
} }
el = document.getElementById("pause-grid-right") el = document.getElementById("pause-grid-right")
el.style.display = "grid" el.style.display = tech.isNoDraftPause ? "none" : "grid" //disabled for eternalism because eternalism lets the player play while this menu is up but the menu doesn't update
el.innerHTML = text el.innerHTML = text
document.getElementById("tech").style.display = "none" document.getElementById("tech").style.display = "none"
@@ -933,7 +932,7 @@ window.addEventListener("keydown", function(event) {
if (m.alive && localSettings.loreCount > 0) { if (m.alive && localSettings.loreCount > 0) {
if (simulation.difficultyMode > 4) { if (simulation.difficultyMode > 4) {
simulation.makeTextLog("<em>testing mode disabled for this difficulty</em>"); simulation.makeTextLog("<em>testing mode disabled for this difficulty</em>");
break // break
} }
if (simulation.testing) { if (simulation.testing) {
simulation.testing = false; simulation.testing = false;

View File

@@ -15,40 +15,31 @@ const level = {
levels: [], levels: [],
start() { start() {
if (level.levelsCleared === 0) { //this code only runs on the first level if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// m.addHealth(Infinity) // m.addHealth(Infinity)
// m.setField("time dilation") // m.setField("molecular assembler")
// b.giveGuns("laser") // b.giveGuns("spores")
// tech.giveTech("fleas")
// tech.giveTech("flagella")
// b.guns[0].ammo = 10000 // b.guns[0].ammo = 10000
// // b.giveGuns("mine") // for (let i = 0; i < 1; ++i) tech.giveTech("mycelium manufacturing")
// tech.giveTech("lens") // for (let i = 0; i < 9; ++i) tech.giveTech("WIMPs")
// for (let i = 0; i < 2; ++i) tech.giveTech("diffraction grating")
// for (let i = 0; i < 9; ++i) tech.giveTech("propagator")
// for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot") // for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot")
// for (let i = 0; i < 9; ++i) tech.giveTech("emergence") // for (let i = 0; i < 1; ++i) tech.giveTech("necrophage")
// tech.giveTech("laser-bot") // for (let i = 0; i < 1; i++) tech.giveTech("cryodesiccation")
// tech.giveTech("slow light")
// tech.giveTech("iridescence")
// m.maxHealth = 100
// m.health = m.maxHealth
// for (let i = 0; i < 10; i++) tech.giveTech("tungsten carbide")
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research");
// for (let i = 0; i < 15; i++) tech.giveTech() // m.maxHealth = m.health = 100
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
// powerUps.research.changeRerolls(100000) // powerUps.research.changeRerolls(100000)
// tech.tech[297].frequency = 100
// m.immuneCycle = Infinity //you can't take damage // m.immuneCycle = Infinity //you can't take damage
// simulation.enableConstructMode() //used to build maps in testing mode
// level.temple();
// spawn.cellBossCulture(1900, -500)
// powerUps.research.changeRerolls(100) // powerUps.research.changeRerolls(100)
// spawn.starter(1900, -500, 40) // tech.tech[297].frequency = 100
// spawn.starter(1900, -500, 20) // spawn.starter(1900, -500, 200)
// spawn.starter(1900, -500, 100) // for (let i = 0; i < 10; ++i) spawn.hopBullet(1900, -500)
// for (let i = 0; i < 20; ++i) spawn.exploder(1900, -500) // spawn.hopMomBoss(1900, -500)
// spawn.timeSkipBoss(1900, -500) // spawn.grenadier(1900, -1450, 10)
// level.difficultyIncrease(50) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(8 * 4) //30 is near max on hard //60 is near max on why
// level.testing(); //not in rotation, used for testing // level.testing(); //not in rotation, used for testing
// for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); // for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research");
// for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); // for (let i = 0; i < 4; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
@@ -2215,11 +2206,124 @@ const level = {
// spawn.randomLevelBoss(x + 950, y + -2200); // spawn.randomLevelBoss(x + 950, y + -2200);
// }, // },
// (x = offset.x, y = offset.y) => { //hopBoss1
// const button = level.button(x + 935, y + 0)
// button.isUp = true
// // spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //left ledges
// // spawn.mapVertex(x + 1995, y + -1318, "0 0 0 -250 -125 -250"); // right ledges
// doCustomTopLayer.push(
// () => {
// button.draw();
// if (button.isUp) {
// button.query();
// if (!button.isUp) {
// // doCustomTopLayer.push(() => {
// // ctx.fillStyle = "rgba(150,255,220,0.15)"
// // ctx.fillRect(x + 250, y + -2725, 625, 725)
// // })
// const mapStartingLength = map.length //track this so you know how many you added when running addMapToLevelInProgress
// addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
// who.collisionFilter.category = cat.map;
// who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
// Matter.Body.setStatic(who, true); //make static
// Composite.add(engine.world, who); //add to world
// }
// //map elements go here
// // spawn.mapRect(x + -50, y + -1875, 875, 200);
// // spawn.mapRect(x + 650, y + -2700, 125, 625);
// // spawn.mapRect(x + 1200, y + -2250, 250, 25);
// spawn.mapRect(x + -25, y + -1875, 1250, 200);
// // spawn.mapRect(x + 1075, y + -2700, 100, 650);
// spawn.mapRect(x + 1325, y + -1875, 475, 200);
// // spawn.mapRect(x + 1900, y + -1600, 125, 25);
// // spawn.mapRect(x + 900, y + -1875, 325, 25);
// // spawn.mapRect(x + 1375, y + -1875, 350, 25);
// // spawn.mapRect(x + 675, y + -2725, 50, 650);
// spawn.mapRect(x + 1900, y + -1675, 125, 25);
// spawn.mapRect(x + 1700, y + -1400, 325, 25);
// spawn.mapRect(x + -50, y + -1400, 325, 25);
// spawn.mapRect(x + -25, y + -700, 500, 25);
// spawn.mapRect(x + 675, y + -700, 600, 25);
// spawn.mapRect(x + 1475, y + -700, 500, 25);
// spawn.mapRect(x + 475, y + -1025, 200, 25);
// spawn.mapRect(x + 1275, y + -1025, 200, 25);
// spawn.mapRect(x + 475, y + -300, 200, 25);
// spawn.mapRect(x + 1275, y + -300, 200, 25);
// for (let i = 0, numberOfMapElementsAdded = map.length - mapStartingLength; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
// simulation.draw.setPaths() //update map graphics
// //mobs go here
// powerUps.directSpawn(x + 50, y - 1525, "ammo");
// powerUps.directSpawn(x + 1950, y - 1525, "ammo");
// spawn.hopMomBoss(x + 550, y + -2325)
// for (let i = 0; i < 20; ++i) spawn.hopBullet(x + 50 + 1900 * Math.random(), y + -2325)
// // spawn.hopper(x + 1500, y + -775);
// // spawn.hopper(x + 525, y + -775);
// }
// }
// }
// )
// },
(x = offset.x, y = offset.y) => { //hopBoss2
const button = level.button(x + 935, y + 0)
button.isUp = true
// spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //left ledges
// spawn.mapVertex(x + 1995, y + -1318, "0 0 0 -250 -125 -250"); // right ledges
doCustomTopLayer.push(
() => {
button.draw();
if (button.isUp) {
button.query();
if (!button.isUp) {
const mapStartingLength = map.length //track this so you know how many you added when running addMapToLevelInProgress
addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
who.collisionFilter.category = cat.map;
who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
Matter.Body.setStatic(who, true); //make static
Composite.add(engine.world, who); //add to world
}
//map elements go here
spawn.mapRect(x + 150, y + -1400, 750, 50);
spawn.mapRect(x + 1100, y + -1400, 750, 50);
spawn.mapRect(x + 1825, y + -1050, 200, 50);
spawn.mapRect(x + -25, y + -1050, 200, 50);
spawn.mapRect(x + 1825, y + -325, 200, 50);
spawn.mapRect(x + -25, y + -325, 200, 50);
spawn.mapRect(x + 275, y + -700, 525, 50);
spawn.mapRect(x + 1200, y + -700, 525, 50);
spawn.mapRect(x + -25, y + -1400, 125, 1125); //side walls
spawn.mapRect(x + 1900, y + -1400, 150, 1125);
spawn.mapRect(x + 1900, y + -2700, 125, 1000);
spawn.mapRect(x + -50, y + -2725, 150, 1025);
spawn.mapRect(x + -25, y + -1750, 450, 50);
spawn.mapRect(x + 1575, y + -1750, 450, 50);
spawn.mapRect(x + 525, y + -1750, 950, 50);
for (let i = 0, numberOfMapElementsAdded = map.length - mapStartingLength; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
simulation.draw.setPaths() //update map graphics
//mobs go here
powerUps.directSpawn(x + 50, y - 1525, "ammo");
powerUps.directSpawn(x + 1950, y - 1525, "ammo");
spawn.hopMomBoss(x + 800, y + -2200)
for (let i = 0; i < 10; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
for (let i = 0; i < 10; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
spawn.hopper(x + 1500, y + -775);
spawn.hopper(x + 525, y + -775);
}
}
}
)
},
(x = offset.x, y = offset.y) => { (x = offset.x, y = offset.y) => {
// const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) { // const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) {
// toggle.isAddedElements = false // toggle.isAddedElements = false
const button = level.button(x + 950, y + 0) const button = level.button(x + 935, y + 0)
button.isUp = true button.isUp = true
@@ -2310,7 +2414,7 @@ const level = {
(x = offset.x, y = offset.y) => { (x = offset.x, y = offset.y) => {
// const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) { // const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) {
// toggle.isAddedElements = false // toggle.isAddedElements = false
const button = level.button(x + 950, y + 0) const button = level.button(x + 935, y + 0)
button.isUp = true button.isUp = true
//left ledges //left ledges
spawn.mapVertex(x + 5, y + -1868, "0 0 0 -250 125 -250"); spawn.mapVertex(x + 5, y + -1868, "0 0 0 -250 125 -250");
@@ -2412,7 +2516,7 @@ const level = {
empty = emptyOptions[Math.floor(Math.random() * emptyOptions.length)]; empty = emptyOptions[Math.floor(Math.random() * emptyOptions.length)];
loot = lootOptions[Math.floor(Math.random() * lootOptions.length)]; loot = lootOptions[Math.floor(Math.random() * lootOptions.length)];
upDown = upDownOptions[Math.floor(Math.random() * upDownOptions.length)]; upDown = upDownOptions[Math.floor(Math.random() * upDownOptions.length)];
// upDown = upDownOptions[1] //controls what level spawns for map designing building //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION *************************************** // upDown = upDownOptions[0] //controls what level spawns for map designing building //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION ***************************************
//3x2: 4 short rooms (3000x1500), 1 double tall room (3000x3000) //3x2: 4 short rooms (3000x1500), 1 double tall room (3000x3000)
//rooms //rooms
let rooms = ["exit", "loot", "enter", "empty"] let rooms = ["exit", "loot", "enter", "empty"]
@@ -2661,7 +2765,7 @@ const level = {
document.body.style.backgroundColor = "#ddd"; document.body.style.backgroundColor = "#ddd";
spawn.mapRect(-950, 0, 8200, 800); //ground spawn.mapRect(-950, 0, 8200, 800); //ground
spawn.mapRect(-950, -1200, 800, 1400); //left wall spawn.mapRect(-950, -1200, 800, 1400); //left wall
spawn.mapRect(-950, -1800, 8200, 800); //roof // spawn.mapRect(-950, -1800, 8200, 800); //roof
spawn.mapRect(-250, -400, 1000, 600); // shelf spawn.mapRect(-250, -400, 1000, 600); // shelf
spawn.mapRect(-250, -1200, 1000, 550); // shelf roof spawn.mapRect(-250, -1200, 1000, 550); // shelf roof
// for (let i = 0; i < 10; ++i) powerUps.spawn(550, -800, "ammo", false); // for (let i = 0; i < 10; ++i) powerUps.spawn(550, -800, "ammo", false);
@@ -2968,10 +3072,10 @@ const level = {
}; };
level.setPosToSpawn(0, -250); //normal spawn level.setPosToSpawn(0, -250); //normal spawn
spawn.mapRect(5500, -330 + 20, 100, 20); //spawn this because the real exit is in the wrong spot
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 550000; spawn.mapRect(5500, -330 + 20, 100, 20); //spawn this because the real exit is in the wrong spot
level.exit.y = -330; level.exit.x = 0;
level.exit.y = -8000;
level.defaultZoom = 2500 level.defaultZoom = 2500
simulation.zoomTransition(level.defaultZoom) simulation.zoomTransition(level.defaultZoom)
@@ -7892,6 +7996,7 @@ const level = {
spawn.bodyRect(-2100, 2050, 290, 30) //Portal platform spawn.bodyRect(-2100, 2050, 290, 30) //Portal platform
let b = body[body.length - 1]; let b = body[body.length - 1];
b.isNotHoldable = true
cons[cons.length] = Constraint.create({ cons[cons.length] = Constraint.create({
pointA: { pointA: {
x: -1820, x: -1820,

View File

@@ -1658,6 +1658,9 @@ const m = {
// description: "<strong>attract</strong> power ups from <strong>far away</strong><br><strong>deflecting</strong> doesn't drain <strong class='color-f'>energy</strong><br>thrown <strong class='color-block'>blocks</strong> have", // description: "<strong>attract</strong> power ups from <strong>far away</strong><br><strong>deflecting</strong> doesn't drain <strong class='color-f'>energy</strong><br>thrown <strong class='color-block'>blocks</strong> have",
// description: "gain <strong class='color-f'>energy</strong> when <strong>blocking</strong><br>no <strong>recoil</strong> when <strong>blocking</strong>", // description: "gain <strong class='color-f'>energy</strong> when <strong>blocking</strong><br>no <strong>recoil</strong> when <strong>blocking</strong>",
effect: () => { effect: () => {
m.fieldMeterColor = "#48f" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
m.fieldShieldingScale = 0; m.fieldShieldingScale = 0;
m.fieldBlockCD = 3; m.fieldBlockCD = 3;
m.grabPowerUpRange2 = 10000000 m.grabPowerUpRange2 = 10000000
@@ -1724,9 +1727,8 @@ const m = {
ctx.strokeStyle = "#f0f"; ctx.strokeStyle = "#f0f";
ctx.stroke(); ctx.stroke();
} else if (isFree) { } else if (isFree) {
//when blocking draw this graphic ctx.lineWidth = 2; //when blocking draw this graphic
ctx.fillStyle = "rgba(110,170,200," + (0.2 + 0.4 * Math.random()) + ")"; ctx.fillStyle = `rgba(110,150,220, ${0.2 + 0.4 * Math.random()})`
ctx.lineWidth = 2;
ctx.strokeStyle = "#000"; ctx.strokeStyle = "#000";
const len = mob[i].vertices.length - 1; const len = mob[i].vertices.length - 1;
const mag = mob[i].radius const mag = mob[i].radius
@@ -1739,11 +1741,11 @@ const m = {
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
} else { } else {
//when blocking draw this graphic
const eye = 15; const eye = 15; //when blocking draw this graphic
const len = mob[i].vertices.length - 1; const len = mob[i].vertices.length - 1;
ctx.fillStyle = "rgba(110,170,200," + (0.2 + 0.4 * Math.random()) + ")";
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.fillStyle = `rgba(110,150,220, ${0.2 + 0.4 * Math.random()})`
ctx.strokeStyle = "#000"; ctx.strokeStyle = "#000";
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(m.fieldPosition.x + eye * Math.cos(m.fieldAngle), m.fieldPosition.y + eye * Math.sin(m.fieldAngle)); ctx.moveTo(m.fieldPosition.x + eye * Math.cos(m.fieldAngle), m.fieldPosition.y + eye * Math.sin(m.fieldAngle));
@@ -1800,11 +1802,11 @@ const m = {
m.fieldAngle = m.angle m.fieldAngle = m.angle
//draw field attached to player //draw field attached to player
if (m.holdingTarget) { if (m.holdingTarget) {
ctx.fillStyle = "rgba(110,170,200," + (0.06 + 0.03 * Math.random()) + ")"; ctx.fillStyle = `rgba(110,150,220, ${0.06 + 0.03 * Math.random()})`
ctx.strokeStyle = "rgba(110, 200, 235, " + (0.35 + 0.05 * Math.random()) + ")" ctx.strokeStyle = `rgba(110,150,220, ${0.35 + 0.05 * Math.random()})`
} else { } else {
ctx.fillStyle = "rgba(110,170,200," + (0.27 + 0.2 * Math.random() - 0.1 * wave) + ")"; ctx.fillStyle = `rgba(110,150,220, ${0.27 + 0.2 * Math.random() - 0.1 * wave})`
ctx.strokeStyle = "rgba(110, 200, 235, " + (0.4 + 0.5 * Math.random()) + ")" ctx.strokeStyle = `rgba(110,150,220, ${0.4 + 0.5 * Math.random()})`
} }
ctx.beginPath(); ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, m.fieldRange, m.angle - Math.PI * m.fieldArc, m.angle + Math.PI * m.fieldArc, false); ctx.arc(m.pos.x, m.pos.y, m.fieldRange, m.angle - Math.PI * m.fieldArc, m.angle + Math.PI * m.fieldArc, false);
@@ -1828,8 +1830,8 @@ const m = {
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) 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 (!input.field) { //&& tech.isFieldFree if (!input.field) { //&& tech.isFieldFree
//draw field free of player //draw field free of player
ctx.fillStyle = "rgba(110,170,200," + (0.27 + 0.2 * Math.random() - 0.1 * wave) + ")"; ctx.fillStyle = `rgba(110,150,220, ${0.27 + 0.2 * Math.random() - 0.1 * wave})`
ctx.strokeStyle = "rgba(110, 200, 235, " + (0.4 + 0.5 * Math.random()) + ")" ctx.strokeStyle = `rgba(110,180,255, ${0.4 + 0.5 * Math.random()})`
ctx.beginPath(); ctx.beginPath();
ctx.arc(m.fieldPosition.x, m.fieldPosition.y, m.fieldRange, m.fieldAngle - Math.PI * m.fieldArc, m.fieldAngle + Math.PI * m.fieldArc, false); ctx.arc(m.fieldPosition.x, m.fieldPosition.y, m.fieldRange, m.fieldAngle - Math.PI * m.fieldArc, m.fieldAngle + Math.PI * m.fieldArc, false);
ctx.lineWidth = 2.5 - 1.5 * wave; ctx.lineWidth = 2.5 - 1.5 * wave;
@@ -1842,7 +1844,8 @@ const m = {
m.perfectPush(true); m.perfectPush(true);
} }
} }
m.drawFieldMeter() // m.drawFieldMeter()
m.drawFieldMeter("rgba(0,0,0,0.2)")
if (tech.isPerfectBrake) { //cap mob speed around player if (tech.isPerfectBrake) { //cap mob speed around player
const range = 200 + 140 * wave + 150 * m.energy const range = 200 + 140 * wave + 150 * m.energy
for (let i = 0; i < mob.length; i++) { for (let i = 0; i < mob.length; i++) {
@@ -2018,17 +2021,19 @@ const m = {
description: "excess <strong class='color-f'>energy</strong> used to build <strong>drones</strong><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br>generate <strong>12</strong> <strong class='color-f'>energy</strong> per second", description: "excess <strong class='color-f'>energy</strong> used to build <strong>drones</strong><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br>generate <strong>12</strong> <strong class='color-f'>energy</strong> per second",
//<strong>double</strong> your default <strong class='color-f'>energy</strong> regeneration //<strong>double</strong> your default <strong class='color-f'>energy</strong> regeneration
effect: () => { effect: () => {
// m.fieldMeterColor = "#0c5" m.fieldMeterColor = "#ff0"
// m.eyeFillColor = m.fieldMeterColor m.eyeFillColor = m.fieldMeterColor
m.hold = function() { m.hold = function() {
if (m.energy > m.maxEnergy - 0.02 && m.fieldCDcycle < m.cycle && !input.field && bullet.length < 300 && (m.cycle % 2)) { if (m.energy > m.maxEnergy - 0.02 && m.fieldCDcycle < m.cycle && !input.field && bullet.length < 300 && (m.cycle % 2)) {
// if (tech.isBotField) {
// b.randomBot(this.position, false)
// bullet[bullet.length - 1].endCycle = simulation.cycle + 840 //14 seconds
// m.energy -= 0.35
// } else
if (tech.isSporeField) { if (tech.isSporeField) {
if (tech.isSporeWorm) { if (tech.isSporeFlea) {
const drain = 0.16 + (Math.max(bullet.length, 130) - 130) * 0.02
if (m.energy > drain) {
m.energy -= drain
const speed = m.crouch ? 20 + 8 * Math.random() : 10 + 3 * Math.random()
b.flea({ x: m.pos.x + 35 * Math.cos(m.angle), y: m.pos.y + 35 * Math.sin(m.angle) }, { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) })
}
} else if (tech.isSporeWorm) {
const drain = 0.16 + (Math.max(bullet.length, 130) - 130) * 0.02 const drain = 0.16 + (Math.max(bullet.length, 130) - 130) * 0.02
if (m.energy > drain) { if (m.energy > drain) {
m.energy -= drain m.energy -= drain
@@ -2260,7 +2265,7 @@ const m = {
const damageRadius = circleRadiusScale * this.circleRadius const damageRadius = circleRadiusScale * this.circleRadius
const dischargeRange = 150 + 1600 * tech.plasmaDischarge + 1.3 * damageRadius const dischargeRange = 150 + 1600 * tech.plasmaDischarge + 1.3 * damageRadius
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].alive && (!mob[i].isBadTarget || mob[i].isMobBullet)) { if (mob[i].alive && (!mob[i].isBadTarget || mob[i].isMobBullet) && !mob[i].isInvulnerable) {
const sub = Vector.magnitude(Vector.sub(this.position, mob[i].position)) const sub = Vector.magnitude(Vector.sub(this.position, mob[i].position))
if (sub < damageRadius + mob[i].radius) { if (sub < damageRadius + mob[i].radius) {
// if (!this.isAttached && !mob[i].isMobBullet) this.isPopping = true // if (!this.isAttached && !mob[i].isMobBullet) this.isPopping = true
@@ -2530,11 +2535,43 @@ const m = {
// description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 1px;'>stop time</strong><br>while time is stopped you can <strong>move</strong> and <strong>fire</strong><br>and <strong>collisions</strong> do <strong>50%</strong> less <strong class='color-defense'>harm</strong>", // description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 1px;'>stop time</strong><br>while time is stopped you can <strong>move</strong> and <strong>fire</strong><br>and <strong>collisions</strong> do <strong>50%</strong> less <strong class='color-defense'>harm</strong>",
description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 2px;'>stop time</strong><br><strong>+25%</strong> movement, jumping, and <strong><em>fire rate</em></strong><br>generate <strong>18</strong> <strong class='color-f'>energy</strong> per second", description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 2px;'>stop time</strong><br><strong>+25%</strong> movement, jumping, and <strong><em>fire rate</em></strong><br>generate <strong>18</strong> <strong class='color-f'>energy</strong> per second",
set() { set() {
// m.fieldMeterColor = "#0fc"
// m.fieldMeterColor = "#ff0"
m.fieldMeterColor = "#3fe"
m.eyeFillColor = m.fieldMeterColor
m.fieldFireRate = 0.75 m.fieldFireRate = 0.75
b.setFireCD(); b.setFireCD();
m.fieldFx = 1.2 m.fieldFx = 1.2
m.fieldJump = 1.09 m.fieldJump = 1.09
m.setMovement(); m.setMovement();
const timeStop = () => {
m.immuneCycle = m.cycle + 10; //immune to harm while time is stopped, this also disables regen
//draw field everywhere
ctx.globalCompositeOperation = "saturation"
ctx.fillStyle = "#ccc";
ctx.fillRect(-100000, -100000, 200000, 200000)
ctx.globalCompositeOperation = "source-over"
//stop time
m.isBodiesAsleep = true;
function sleep(who) {
for (let i = 0, len = who.length; i < len; ++i) {
if (!who[i].isSleeping) {
who[i].storeVelocity = who[i].velocity
who[i].storeAngularVelocity = who[i].angularVelocity
}
Matter.Sleeping.set(who[i], true)
}
}
sleep(mob);
sleep(body);
sleep(bullet);
simulation.cycle--; //pause all functions that depend on game cycle increasing
}
if (tech.isRewindField) { if (tech.isRewindField) {
this.rewindCount = 0 this.rewindCount = 0
m.grabPowerUpRange2 = 300000 m.grabPowerUpRange2 = 300000
@@ -2562,6 +2599,7 @@ const m = {
m.drawHold(m.holdingTarget); m.drawHold(m.holdingTarget);
m.holding(); m.holding();
m.throwBlock(); m.throwBlock();
m.wakeCheck();
} else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
m.grabPowerUp(); m.grabPowerUp();
if (this.rewindCount === 0) m.lookForPickUp(); if (this.rewindCount === 0) m.lookForPickUp();
@@ -2612,12 +2650,18 @@ const m = {
} }
} }
} }
m.wakeCheck();
} else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
m.pickUp(); m.pickUp();
this.rewindCount = 0; this.rewindCount = 0;
m.wakeCheck();
} else if (tech.isTimeStop && player.speed < 1 && m.onGround && !input.fire) {
timeStop();
this.rewindCount = 0;
} else { } 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) 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)
this.rewindCount = 0; this.rewindCount = 0;
m.wakeCheck();
} }
if (m.energy < m.maxEnergy) m.regenEnergy(); //extra energy regen if (m.energy < m.maxEnergy) m.regenEnergy(); //extra energy regen
m.drawFieldMeter() // this calls m.regenEnergy(); also m.drawFieldMeter() // this calls m.regenEnergy(); also
@@ -2637,37 +2681,30 @@ const m = {
m.lookForPickUp(); m.lookForPickUp();
if (m.energy > m.drain) { if (m.energy > m.drain) {
m.energy -= m.drain; m.energy -= m.drain;
if (m.energy < m.drain) { if (m.energy < m.drain) { //out of energy
m.fieldCDcycle = m.cycle + 120; m.fieldCDcycle = m.cycle + 120;
m.energy = 0; m.energy = 0;
m.wakeCheck(); m.wakeCheck();
} }
m.immuneCycle = m.cycle + 10; //immune to harm while time is stopped, this also disables regen timeStop();
//draw field everywhere
ctx.globalCompositeOperation = "saturation"
ctx.fillStyle = "#ccc";
ctx.fillRect(-100000, -100000, 200000, 200000)
ctx.globalCompositeOperation = "source-over"
//stop time
m.isBodiesAsleep = true;
function sleep(who) {
for (let i = 0, len = who.length; i < len; ++i) {
if (!who[i].isSleeping) {
who[i].storeVelocity = who[i].velocity
who[i].storeAngularVelocity = who[i].angularVelocity
}
Matter.Sleeping.set(who[i], true)
}
}
sleep(mob);
sleep(body);
sleep(bullet);
simulation.cycle--; //pause all functions that depend on game cycle increasing
} else { //holding, but field button is released } else { //holding, but field button is released
m.wakeCheck(); m.wakeCheck();
} }
} else if (tech.isTimeStop && player.speed < 1 && m.onGround && m.fireCDcycle < m.cycle && !input.fire) {
timeStop();
//makes things move at 1/5 time rate, but has an annoying flicker for mob graphics, and other minor bugs
// if (!(m.cycle % 4)) {
// // requestAnimationFrame(() => {
// m.wakeCheck();
// // simulation.timePlayerSkip(1)
// // }); //wrapping in animation frame prevents errors, probably
// ctx.globalCompositeOperation = "saturation"
// ctx.fillStyle = "#ccc";
// ctx.fillRect(-100000, -100000, 200000, 200000)
// ctx.globalCompositeOperation = "source-over"
// } else {
// timeStop();
// }
} else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
m.wakeCheck(); m.wakeCheck();
m.pickUp(); m.pickUp();
@@ -2682,6 +2719,11 @@ const m = {
} }
}, },
effect() { effect() {
if (tech.isTimeStop) {
m.fieldHarmReduction = 0.66; //33% reduction
} else {
m.fieldHarmReduction = 1;
}
this.set(); this.set();
} }
}, },
@@ -2750,7 +2792,6 @@ const m = {
} else { } 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) 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)
} }
//not shooting (or using field) enable cloak //not shooting (or using field) enable cloak
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing
@@ -2992,6 +3033,9 @@ const m = {
//field <strong>radius</strong> decreases out of <strong>line of sight</strong> //field <strong>radius</strong> decreases out of <strong>line of sight</strong>
description: "use <strong class='color-f'>energy</strong> to guide <strong class='color-block'>blocks</strong><br><strong>unlock</strong> <strong class='color-m'>tech</strong> from other <strong class='color-f'>fields</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", description: "use <strong class='color-f'>energy</strong> to guide <strong class='color-block'>blocks</strong><br><strong>unlock</strong> <strong class='color-m'>tech</strong> from other <strong class='color-f'>fields</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second",
effect: () => { effect: () => {
m.fieldMeterColor = "#333"
m.eyeFillColor = m.fieldMeterColor
m.fieldPhase = 0; m.fieldPhase = 0;
m.fieldPosition = { m.fieldPosition = {
x: simulation.mouseInGame.x, x: simulation.mouseInGame.x,
@@ -3179,7 +3223,7 @@ const m = {
m.fieldOn = false m.fieldOn = false
m.fieldRadius = 0 m.fieldRadius = 0
} }
m.drawFieldMeter() m.drawFieldMeter("rgba(0,0,0,0.2)")
} }
} }
}, },
@@ -3189,6 +3233,9 @@ const m = {
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+4%</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>+4%</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, drain: 0,
effect: function() { effect: function() {
m.fieldMeterColor = "#bbf" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
m.duplicateChance = 0.04 m.duplicateChance = 0.04
m.fieldRange = 0 m.fieldRange = 0
powerUps.setDupChance(); //needed after adjusting duplication chance powerUps.setDupChance(); //needed after adjusting duplication chance

View File

@@ -303,7 +303,7 @@ const powerUps = {
}, },
endDraft(type, isCanceled = false) { //type should be a gun, tech, or field endDraft(type, isCanceled = false) { //type should be a gun, tech, or field
if (isCanceled) { if (isCanceled) {
if (tech.isCancelTech && Math.random() < 0.96) { if (tech.isCancelTech && Math.random() < 0.94) {
// powerUps.research.use('tech') // powerUps.research.use('tech')
powerUps[type].effect(); powerUps[type].effect();
return return
@@ -396,9 +396,6 @@ const powerUps = {
} }
}, delay); }, delay);
} }
// for (let i = 0, len = tech.tech.length; i < len; i++) {
// if (tech.tech[i].name === "bot fabrication") tech.tech[i].description = `if you collect ${powerUps.orb.research(2 + Math.floor(0.2 * b.totalBots()))}use them to build a<br>random <strong class='color-bot'>bot</strong> <em>(+1 cost every 5 bots)</em>`
// }
} }
if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) { if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) {
document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}` document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}`

View File

@@ -120,6 +120,44 @@ const simulation = {
} }
simulation.isTimeSkipping = false; simulation.isTimeSkipping = false;
}, },
// timeMobSkip() {
// simulation.gravity();
// Engine.update(engine, simulation.delta);
// simulation.wipe();
// simulation.textLog();
// if (m.onGround) {
// m.groundControl()
// } else {
// m.airControl()
// }
// m.move();
// m.look();
// simulation.camera();
// level.custom();
// powerUps.do();
// mobs.draw();
// simulation.draw.cons();
// simulation.draw.body();
// if (!m.isBodiesAsleep) {
// simulation.checks();
// // mobs.loop();
// }
// mobs.healthBar();
// m.draw();
// m.hold();
// // v.draw(); //working on visibility work in progress
// level.customTopLayer();
// simulation.draw.drawMapPath();
// b.fire();
// b.bulletRemove();
// b.bulletDraw();
// if (!m.isBodiesAsleep) b.bulletDo();
// simulation.drawCircle();
// // simulation.clip();
// ctx.restore();
// simulation.drawCursor();
// // simulation.pixelGraphics();
// },
mouse: { mouse: {
x: canvas.width / 2, x: canvas.width / 2,
y: canvas.height / 2 y: canvas.height / 2
@@ -857,6 +895,7 @@ const simulation = {
let droneCount = 0 let droneCount = 0
let sporeCount = 0 let sporeCount = 0
let wormCount = 0 let wormCount = 0
let fleaCount = 0
let deliveryCount = 0 let deliveryCount = 0
for (let i = 0; i < bullet.length; ++i) { for (let i = 0; i < bullet.length; ++i) {
if (bullet[i].isDrone) { if (bullet[i].isDrone) {
@@ -866,6 +905,8 @@ const simulation = {
sporeCount++ sporeCount++
} else if (bullet[i].wormSize) { } else if (bullet[i].wormSize) {
wormCount++ wormCount++
} else if (bullet[i].isFlea) {
fleaCount++
} }
} }
@@ -920,6 +961,21 @@ const simulation = {
} }
} }
requestAnimationFrame(respawnWorms); requestAnimationFrame(respawnWorms);
//respawn fleas in animation frame
let respawnFleas = () => {
if (fleaCount > 0) {
requestAnimationFrame(respawnFleas);
if (!simulation.paused && !simulation.isChoosing) {
fleaCount--
const where = { x: level.enter.x + 50, y: level.enter.y - 60 }
const speed = 6 + 3 * Math.random()
const angle = 2 * Math.PI * Math.random()
b.flea({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 120 * (Math.random() - 0.5) }, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) })
}
}
}
requestAnimationFrame(respawnFleas);
} }
if (tech.isQuantumEraser) { if (tech.isQuantumEraser) {

View File

@@ -1,7 +1,7 @@
//main object for spawning things in a level //main object for spawning things in a level
const spawn = { const spawn = {
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"], nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"],
// other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss //these need a particular level to work so they are not included in the random pool // other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss, hopMomBoss //these need a particular level to work so they are not included in the random pool
randomBossList: [ randomBossList: [
"orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
"powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", "powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
@@ -51,13 +51,13 @@ const spawn = {
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss
if (mob[i].isFinalBoss) { if (mob[i].isFinalBoss) {
mob[i].health = 0.66 tech.quantumEraserCount = 0;
return
} else { } else {
tech.isQuantumEraserDuplication = true tech.isQuantumEraserDuplication = true
mob[i].death() mob[i].death()
tech.isQuantumEraserDuplication = false tech.isQuantumEraserDuplication = false
} }
//graphics //graphics
const color = 'rgba(255,255,255, 0.8)' const color = 'rgba(255,255,255, 0.8)'
simulation.drawList.push({ simulation.drawList.push({
@@ -81,7 +81,6 @@ const spawn = {
color: color, //"rgb(0,0,0)", color: color, //"rgb(0,0,0)",
time: 120 time: 120
}); });
tech.quantumEraserCount-- tech.quantumEraserCount--
simulation.makeTextLog(`<span class='color-var'>tech</span>.quantumEraserCount <span class='color-symbol'>=</span> ${tech.quantumEraserCount}`) simulation.makeTextLog(`<span class='color-var'>tech</span>.quantumEraserCount <span class='color-symbol'>=</span> ${tech.quantumEraserCount}`)
if (tech.quantumEraserCount < 1) break if (tech.quantumEraserCount < 1) break
@@ -1580,99 +1579,166 @@ const spawn = {
} }
}; };
}, },
hopBoss(x, y, radius = 90) { hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8)) {
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)"); mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.stroke = "transparent";
me.leaveBody = false;
me.isDropPowerUp = false;
// me.isBadTarget = true;
me.isMobBullet = true;
me.showHealthBar = false;
me.timeLeft = 1500 + Math.floor(600 * Math.random());
me.g = 0.005; //required if using this.gravity me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
me.accelMag = 0.01; //jump height
me.g = 0.0015; //required if using this.gravity
me.frictionAir = 0.01; me.frictionAir = 0.01;
me.friction = 1 me.friction = 1
me.frictionStatic = 1 me.frictionStatic = 1
me.restitution = 0; me.restitution = 0;
me.accelMag = 0.07; me.delay = 130 + 60 * simulation.CDScale;
me.delay = 120 * simulation.CDScale; // Matter.Body.rotate(me, Math.random() * Math.PI);
me.randomHopFrequency = 200 me.collisionFilter.category = cat.mobBullet;
me.randomHopCD = simulation.cycle + me.randomHopFrequency; me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
// me.memory = 420; me.onHit = function() {
me.isInAir = false this.explode(this.mass * 2);
Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger };
me.do = function() {
this.gravity();
this.checkStatus();
if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
this.cd = simulation.cycle + this.delay;
if (this.isRandomMove || Math.random() < 0.2) {
this.force.x += (0.01 + 0.03 * Math.random()) * this.mass * (Math.random() < 0.5 ? 1 : -1); //random move
} else {
this.force.x += (0.01 + 0.03 * Math.random()) * this.mass * (player.position.x > this.position.x ? 1 : -1); //chase player
}
this.force.y -= (0.04 + 0.04 * Math.random()) * this.mass
}
this.timeLimit();
};
},
hopMomBoss(x, y, radius = 120) {
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
let me = mob[mob.length - 1];
me.isBoss = true;
me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.accelMag = 0.05; //jump height
me.g = 0.003; //required if using this.gravity
me.frictionAir = 0.01;
me.friction = 1
me.frictionStatic = 1
me.restitution = 0;
me.delay = 100 + 40 * simulation.CDScale;
Matter.Body.rotate(me, Math.random() * Math.PI);
spawn.shield(me, x, y, 1); spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 60, 1)
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// for (let i = 0, len = 3 + 0.1 * simulation.difficulty; i < len; ++i) spawn.hopBullet(this.position.x + 100 * (Math.random() - 0.5), this.position.y + 100 * (Math.random() - 0.5))
}; };
me.lastSpeed = me.speed
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.do = function() { me.do = function() {
// this.armor();
this.gravity(); this.gravity();
this.seePlayerCheck(); this.seePlayerCheck();
this.checkStatus(); this.checkStatus();
if (this.seePlayer.recall) { if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
const deltaSpeed = this.lastSpeed - this.speed this.cd = simulation.cycle + this.delay;
this.lastSpeed = this.speed //spawn hopBullets after each jump
if (deltaSpeed > 13 && this.speed < 5) { //if the player slows down greatly in one cycle for (let i = 0, len = 1 + 0.05 * simulation.difficulty; i < len; ++i) spawn.hopBullet(this.position.x + 100 * (Math.random() - 0.5), this.position.y + 100 * (Math.random() - 0.5))
//damage and push player away, push away blocks
const range = 800 //Math.min(800, 50 * deltaSpeed)
for (let i = body.length - 1; i > -1; i--) {
if (!body[i].isNotHoldable) {
sub = Vector.sub(body[i].position, this.position);
dist = Vector.magnitude(sub);
if (dist < range) {
knock = Vector.mult(Vector.normalise(sub), Math.min(20, 50 * body[i].mass / dist));
body[i].force.x += knock.x;
body[i].force.y += knock.y;
}
}
}
simulation.drawList.push({ //draw radius this.force.x += (0.02 + 0.06 * Math.random()) * this.mass * (player.position.x > this.position.x ? 1 : -1);
x: this.position.x, this.force.y -= (0.08 + 0.08 * Math.random()) * this.mass
y: this.position.y,
radius: range,
color: "rgba(0,200,180,0.6)",
time: 4
});
}
if (this.isInAir) {
if (this.velocity.y > -0.01 && Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { //not moving up, and has hit the map or a body
this.isInAir = false //landing
this.cd = simulation.cycle + this.delay
}
} else { //on ground
if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { //jump
this.isInAir = true
const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
}
}
// if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
// this.cd = simulation.cycle + this.delay;
// const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
// const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
// this.force.x += forceMag * Math.cos(angle);
// this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
// }
} else {
//randomly hob if not aware of player
if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
this.randomHopCD = simulation.cycle + this.randomHopFrequency;
//slowly change randomHopFrequency after each hop
this.randomHopFrequency = Math.max(100, this.randomHopFrequency + 200 * (0.5 - Math.random()));
const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.5 + Math.random() * 0.2);
const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle) - (0.1 + 0.08 * Math.random()) * this.mass; //antigravity
}
} }
}; };
}, },
// hopBoss(x, y, radius = 90) {
// mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
// let me = mob[mob.length - 1];
// me.isBoss = true;
// me.g = 0.005; //required if using this.gravity
// me.frictionAir = 0.01;
// me.friction = 1
// me.frictionStatic = 1
// me.restitution = 0;
// me.accelMag = 0.07;
// me.delay = 120 * simulation.CDScale;
// me.randomHopFrequency = 200
// me.randomHopCD = simulation.cycle + me.randomHopFrequency;
// // me.memory = 420;
// me.isInAir = false
// Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
// spawn.shield(me, x, y, 1);
// spawn.spawnOrbitals(me, radius + 60, 1)
// me.onDeath = function() {
// powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// };
// me.lastSpeed = me.speed
// me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
// me.do = function() {
// // this.armor();
// this.gravity();
// this.seePlayerCheck();
// this.checkStatus();
// if (this.seePlayer.recall) {
// const deltaSpeed = this.lastSpeed - this.speed
// this.lastSpeed = this.speed
// if (deltaSpeed > 13 && this.speed < 5) { //if the player slows down greatly in one cycle
// //damage and push player away, push away blocks
// const range = 800 //Math.min(800, 50 * deltaSpeed)
// for (let i = body.length - 1; i > -1; i--) {
// if (!body[i].isNotHoldable) {
// sub = Vector.sub(body[i].position, this.position);
// dist = Vector.magnitude(sub);
// if (dist < range) {
// knock = Vector.mult(Vector.normalise(sub), Math.min(20, 50 * body[i].mass / dist));
// body[i].force.x += knock.x;
// body[i].force.y += knock.y;
// }
// }
// }
// simulation.drawList.push({ //draw radius
// x: this.position.x,
// y: this.position.y,
// radius: range,
// color: "rgba(0,200,180,0.6)",
// time: 4
// });
// }
// if (this.isInAir) {
// if (this.velocity.y > -0.01 && Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { //not moving up, and has hit the map or a body
// this.isInAir = false //landing
// this.cd = simulation.cycle + this.delay
// }
// } else { //on ground
// if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { //jump
// this.isInAir = true
// const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
// const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
// this.force.x += forceMag * Math.cos(angle);
// this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
// }
// }
// // if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
// // this.cd = simulation.cycle + this.delay;
// // const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
// // const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
// // this.force.x += forceMag * Math.cos(angle);
// // this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
// // }
// } else {
// //randomly hob if not aware of player
// if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
// this.randomHopCD = simulation.cycle + this.randomHopFrequency;
// //slowly change randomHopFrequency after each hop
// this.randomHopFrequency = Math.max(100, this.randomHopFrequency + 200 * (0.5 - Math.random()));
// const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.5 + Math.random() * 0.2);
// const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
// this.force.x += forceMag * Math.cos(angle);
// this.force.y += forceMag * Math.sin(angle) - (0.1 + 0.08 * Math.random()) * this.mass; //antigravity
// }
// }
// };
// },
spinner(x, y, radius = 30 + Math.ceil(Math.random() * 35)) { spinner(x, y, radius = 30 + Math.ceil(Math.random() * 35)) {
mobs.spawn(x, y, 5, radius, "#000000"); mobs.spawn(x, y, 5, radius, "#000000");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
@@ -5118,7 +5184,7 @@ const spawn = {
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.stroke = "transparent"; me.stroke = "transparent";
me.onHit = function() { me.onHit = function() {
this.explode(this.mass * 20); this.explode(this.mass);
}; };
Matter.Body.setDensity(me, 0.00004); //normal is 0.001 Matter.Body.setDensity(me, 0.00004); //normal is 0.001
@@ -5135,7 +5201,7 @@ const spawn = {
//damage player if in range //damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.position)) < pulseRadius && m.immuneCycle < m.cycle) { if (Vector.magnitude(Vector.sub(player.position, this.position)) < pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
m.damage(0.02 * simulation.dmgScale); m.damage(0.015 * simulation.dmgScale);
} }
simulation.drawList.push({ //add dmg to draw queue simulation.drawList.push({ //add dmg to draw queue
x: this.position.x, x: this.position.x,

View File

@@ -256,7 +256,7 @@ const tech = {
return dmg * tech.slowFire * tech.aimDamage return dmg * tech.slowFire * tech.aimDamage
}, },
duplicationChance() { duplicationChance() {
return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) + tech.isQuantumEraserDuplication * (1 - 0.01 * (simulation.difficultyMode ** 2))) return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) + tech.isQuantumEraserDuplication * (1 - 0.016 * (simulation.difficultyMode ** 2)))
}, },
isScaleMobsWithDuplication: false, isScaleMobsWithDuplication: false,
maxDuplicationEvent() { maxDuplicationEvent() {
@@ -2977,7 +2977,7 @@ const tech = {
effect() { effect() {
tech.isBrainstorm = true tech.isBrainstorm = true
tech.isBrainstormActive = false tech.isBrainstormActive = false
tech.brainStormDelay = 145 - simulation.difficultyMode * 10 tech.brainStormDelay = 150 - simulation.difficultyMode * 7
}, },
remove() { remove() {
tech.isBrainstorm = false tech.isBrainstorm = false
@@ -3319,7 +3319,7 @@ const tech = {
{ {
name: "options exchange", name: "options exchange",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Option_(finance)' class="link">options exchange</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Option_(finance)' class="link">options exchange</a>`,
description: `clicking <strong style = 'font-size:150%;'>×</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong> has a <strong>96%</strong><br>chance to randomize <strong>choices</strong> and not <strong>cancel</strong>`, description: `clicking <strong style = 'font-size:150%;'>×</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong> has a <strong>94%</strong><br>chance to randomize <strong>choices</strong> and not <strong>cancel</strong>`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -5205,7 +5205,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isSporeWorm return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isSporeWorm || tech.isSporeFlea
}, },
requires: "spores", requires: "spores",
effect() { effect() {
@@ -5225,7 +5225,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isSporeWorm return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isSporeWorm || tech.isSporeFlea
}, },
requires: "spores", requires: "spores",
effect() { effect() {
@@ -5263,7 +5263,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField) && !tech.isEnergyHealth || tech.isSporeWorm return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField) && !tech.isEnergyHealth || tech.isSporeWorm || tech.isSporeFlea
}, },
requires: "spores, not mass-energy", requires: "spores, not mass-energy",
effect() { effect() {
@@ -5273,26 +5273,55 @@ const tech = {
tech.isMutualism = false tech.isMutualism = false
} }
}, },
// { {
// name: "worm-shot", name: "fleas",
// link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Worm' class="link">worm-shot</a>`, description: "<strong class='color-p' style='letter-spacing: 2px;'>sporangium</strong> hatch <strong class='color-p' style='letter-spacing: -0.8px;'>fleas</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spore</strong> <strong class='color-m'>tech</strong> applies to <strong class='color-p' style='letter-spacing: -0.8px;'>fleas</strong>",
// description: "<strong>shotgun</strong> hatches <strong>3-4</strong> mob seeking <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br><em>worms benefit from spore technology</em>", //<br><strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> seek out nearby mobs isGunTech: true,
// isGunTech: true, maxCount: 1,
// maxCount: 1, count: 0,
// count: 0, frequency: 3,
// frequency: 2, frequencyDefault: 3,
// frequencyDefault: 2, allowed() {
// allowed() { return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField) && !tech.isSporeWorm
// return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles },
// }, requires: "spores, not worms",
// requires: "shotgun, not incendiary, nail-shot, rivets, foam-shot, ice-shot, needles", effect() {
// effect() { tech.isSporeFlea = true
// tech.isWormShot = true; },
// }, remove() {
// remove() { tech.isSporeFlea = false
// tech.isWormShot = false;
}
},
// ammoBonus: 8,
// effect() {
// tech.isRailGun = true;
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
// if (b.guns[i].name === "harpoon") {
// b.guns[i].chooseFireMethod()
// b.guns[i].ammoPack = this.ammoBonus;
// b.guns[i].ammo = b.guns[i].ammo * this.ammoBonus;
// simulation.updateGunHUD();
// break
// }
// } // }
// }, // },
// remove() {
// if (tech.isRailGun) {
// tech.isRailGun = false;
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
// if (b.guns[i].name === "harpoon") {
// b.guns[i].chooseFireMethod()
// b.guns[i].ammoPack = 0.6;
// b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoBonus);
// simulation.updateGunHUD();
// break
// }
// }
// }
// }
{ {
name: "nematodes", name: "nematodes",
description: "<strong>shotgun</strong> and <strong class='color-p' style='letter-spacing: 2px;'>sporangium</strong> hatch <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spore</strong> <strong class='color-m'>tech</strong> applies to <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong>", description: "<strong>shotgun</strong> and <strong class='color-p' style='letter-spacing: 2px;'>sporangium</strong> hatch <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spore</strong> <strong class='color-m'>tech</strong> applies to <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong>",
@@ -5302,9 +5331,9 @@ const tech = {
frequency: 3, frequency: 3,
frequencyDefault: 3, frequencyDefault: 3,
allowed() { allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot) return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeFlea
}, },
requires: "spores", requires: "spores, not fleas",
effect() { effect() {
tech.isSporeWorm = true tech.isSporeWorm = true
}, },
@@ -5333,7 +5362,7 @@ const tech = {
}, },
{ {
name: "path integration", name: "path integration",
description: "<strong>drones</strong>, <strong class='color-p' style='letter-spacing: 2px;'>spores</strong>, and <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br>travel with you through <strong>levels</strong>", description: "<strong>drones</strong>, <strong class='color-p' style='letter-spacing: 2px;'>spores</strong>, <strong class='color-p' style='letter-spacing: -0.8px;'>fleas</strong>, and <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br>travel with you through <strong>levels</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -5342,7 +5371,7 @@ const tech = {
allowed() { allowed() {
return (tech.isSporeFollow && (tech.haveGunCheck("spores") || (tech.haveGunCheck("shotgun") && tech.isSporeWorm))) || tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField)) return (tech.isSporeFollow && (tech.haveGunCheck("spores") || (tech.haveGunCheck("shotgun") && tech.isSporeWorm))) || tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField))
}, },
requires: "spores, worms, diplochory, drones", requires: "spores, worms, flagella, drones",
effect() { effect() {
tech.isDronesTravel = true tech.isDronesTravel = true
}, },
@@ -5353,7 +5382,7 @@ const tech = {
{ {
name: "anti-shear topology", name: "anti-shear topology",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Topology' class="link">anti-shear topology</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Topology' class="link">anti-shear topology</a>`,
description: "<strong>+30%</strong> projectile <strong>duration</strong><br><em style = 'font-size: 83%'>drone, spore, worm, missile, foam, wave, neutron, ice</em>", description: "<strong>+30%</strong> projectile <strong>duration</strong><br><em style = 'font-size: 83%'>drone spore worm flea missile foam wave neutron ice</em>",
isGunTech: true, isGunTech: true,
maxCount: 3, maxCount: 3,
count: 0, count: 0,
@@ -5362,7 +5391,7 @@ const tech = {
allowed() { allowed() {
return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("matter wave") || tech.isNeutronBomb || tech.isIceField || tech.isIceShot || tech.relayIce || tech.isNeedleIce || tech.blockingIce > 1 || tech.isSporeWorm || tech.isFoamBotUpgrade || tech.isFoamBall return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("matter wave") || tech.isNeutronBomb || tech.isIceField || tech.isIceShot || tech.relayIce || tech.isNeedleIce || tech.blockingIce > 1 || tech.isSporeWorm || tech.isFoamBotUpgrade || tech.isFoamBall
}, },
requires: "drones, spores, missiles, foam, matter wave, neutron bomb, ice IX", requires: "drones, spores, missiles, foam, matter wave, neutron bomb, ice IX, flea",
effect() { effect() {
tech.isBulletsLastLonger += 0.3 tech.isBulletsLastLonger += 0.3
}, },
@@ -5662,14 +5691,14 @@ const tech = {
}, },
{ {
name: "necrophage", name: "necrophage",
description: "if <strong>foam</strong> or <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> <strong>kill</strong> their target<br>grow 3 <strong>copies</strong>", description: "if <strong>foam</strong>, <strong class='color-p' style='letter-spacing: -0.8px;'>fleas</strong>, or <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> <strong>kill</strong> their target<br>grow 3 <strong>copies</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea
}, },
requires: "foam, worms", requires: "foam, worms",
effect() { effect() {
@@ -5818,7 +5847,7 @@ const tech = {
}, },
{ {
name: "railgun", name: "railgun",
description: `<strong>+50%</strong> <strong>harpoon</strong> density, but they don't <strong>retract</strong><br><strong>+800%</strong> harpoon <strong class='color-ammo'>ammo</strong> per ${powerUps.orb.ammo(1)}`, description: `<strong>+50%</strong> <strong>harpoon</strong> density, but they don't <strong>retract</strong><br><strong>+900%</strong> harpoon <strong class='color-ammo'>ammo</strong> per ${powerUps.orb.ammo(1)}`,
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -5828,7 +5857,7 @@ const tech = {
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple
}, },
requires: "harpoon, not UHMWPE, induction furnace, grappling hook", requires: "harpoon, not UHMWPE, induction furnace, grappling hook",
ammoBonus: 8, ammoBonus: 9,
effect() { effect() {
tech.isRailGun = true; tech.isRailGun = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -6109,7 +6138,7 @@ const tech = {
}, },
{ {
name: "laser diode", name: "laser diode",
description: "<strong>+30%</strong> <strong class='color-laser'>laser</strong> <strong class='color-f'>energy</strong> efficiency<br><em>affects laser-gun, laser-bot, laser-mines, pulse</em>", description: "<strong>+33%</strong> <strong class='color-laser'>laser</strong> <strong class='color-f'>energy</strong> efficiency",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -6120,7 +6149,7 @@ const tech = {
}, },
requires: "laser, not free-electron", requires: "laser, not free-electron",
effect() { effect() {
tech.isLaserDiode = 0.70; //100%-37% tech.isLaserDiode = 0.66; //100%-37%
tech.laserColor = "rgb(0, 11, 255)" tech.laserColor = "rgb(0, 11, 255)"
tech.laserColorAlpha = "rgba(0, 11, 255,0.5)" tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
}, },
@@ -6177,7 +6206,7 @@ const tech = {
{ {
name: "iridescence", name: "iridescence",
// description: "if a <strong class='color-laser'>laser</strong> hits a mob at a low angle of illumination<br><strong>+66%</strong> <strong class='color-laser'>laser</strong> <strong class='color-d'>damage</strong>", // description: "if a <strong class='color-laser'>laser</strong> hits a mob at a low angle of illumination<br><strong>+66%</strong> <strong class='color-laser'>laser</strong> <strong class='color-d'>damage</strong>",
description: "if mobs are struck near their <strong>center</strong><br><strong>+88%</strong> <strong class='color-laser'>laser</strong> <strong class='color-d'>damage</strong>", description: "if <strong class='color-laser'>laser</strong> beams hit mobs near their <strong>center</strong><br><strong>+88%</strong> <strong class='color-laser'>laser</strong> <strong class='color-d'>damage</strong>",
isGunTech: true, isGunTech: true,
maxCount: 3, maxCount: 3,
count: 0, count: 0,
@@ -6196,7 +6225,7 @@ const tech = {
}, },
{ {
name: "lens", name: "lens",
description: "if directed through a revolving <strong>+<span style='font-size: 125%;'>π</span> / 4</strong> circular arc<br><strong>+150%</strong> <strong class='color-laser'>laser</strong> gun <strong class='color-d'>damage</strong>", description: "<strong>+150%</strong> <strong class='color-laser'>laser</strong> gun <strong class='color-d'>damage</strong> if it passes<br>through a revolving <strong>+90°</strong> arc circular lens", //<span style='font-size: 125%;'>π</span> / 2</strong>
isGunTech: true, isGunTech: true,
maxCount: 3, maxCount: 3,
count: 0, count: 0,
@@ -6255,7 +6284,7 @@ const tech = {
}, },
{ {
name: "diffraction grating", name: "diffraction grating",
description: `<strong>+1</strong> <strong class='color-laser'>laser</strong> gun beam`, description: `<strong>+1</strong> diverging <strong class='color-laser'>laser</strong> gun beam`,
isGunTech: true, isGunTech: true,
maxCount: 9, maxCount: 9,
count: 0, count: 0,
@@ -6384,7 +6413,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.isPulseLaser && !tech.beamSplitter return tech.haveGunCheck("laser") && tech.isPulseLaser && !tech.beamSplitter
}, },
requires: "laser gun, pulse, not diffraction grating", requires: "laser gun, pulse, not diffraction grating",
effect() { effect() {
@@ -7090,7 +7119,7 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.isExtruder return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isExtruder
}, },
requires: "extruder", requires: "extruder",
effect() { effect() {
@@ -7146,8 +7175,8 @@ const tech = {
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 1,
frequencyDefault: 2, frequencyDefault: 1,
allowed() { allowed() {
return m.fieldUpgrades[m.fieldMode].name === "time dilation" && !m.isShipMode && !tech.isRewindAvoidDeath && !tech.isEnergyHealth && !tech.isTimeSkip return m.fieldUpgrades[m.fieldMode].name === "time dilation" && !m.isShipMode && !tech.isRewindAvoidDeath && !tech.isEnergyHealth && !tech.isTimeSkip
}, },
@@ -7162,6 +7191,27 @@ const tech = {
if (this.count) m.fieldUpgrades[m.fieldMode].set() if (this.count) m.fieldUpgrades[m.fieldMode].set()
} }
}, },
{
name: "frame-dragging", //"non-inertial frame",
description: "when not <strong>moving</strong> time dilation <strong style='letter-spacing: 2px;'>stops time</strong><br><strong>+33%</strong> <strong class='color-defense'>defense</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "time dilation"
},
requires: "time dilation",
effect() {
tech.isTimeStop = true;
m.fieldHarmReduction = 0.66; //33% reduction
},
remove() {
tech.isTimeStop = false;
if (m.fieldUpgrades[m.fieldMode].name === "time dilation") m.fieldHarmReduction = 1;
}
},
{ {
name: "Lorentz transformation", name: "Lorentz transformation",
description: `use ${powerUps.orb.research(3)}<br><strong>+50%</strong> <strong>movement</strong>, <strong>jumping</strong>, and <strong><em>fire rate</em></strong>`, description: `use ${powerUps.orb.research(3)}<br><strong>+50%</strong> <strong>movement</strong>, <strong>jumping</strong>, and <strong><em>fire rate</em></strong>`,
@@ -7235,7 +7285,7 @@ const tech = {
}, },
{ {
name: "quantum eraser", name: "quantum eraser",
descriptionFunction() { return `<span style = 'font-size:90%;'>for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br><strong>kill</strong> a mob as they spawn at <strong>${100-simulation.difficultyMode**2}%</strong> <strong class='color-dup'>duplication</strong></span>` }, descriptionFunction() { return `<span style = 'font-size:90%;'>for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br><strong>kill</strong> a mob as they spawn at <strong>+${100-1.6*simulation.difficultyMode**2}%</strong> <strong class='color-dup'>duplication</strong></span>` },
description: `<span style = 'font-size:90%;'>for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br><strong>kill</strong> a mob as they spawn at <strong>100%</strong> <strong class='color-dup'>duplication</strong></span>`, description: `<span style = 'font-size:90%;'>for each mob left <strong>alive</strong> after you exit a <strong>level</strong><br><strong>kill</strong> a mob as they spawn at <strong>100%</strong> <strong class='color-dup'>duplication</strong></span>`,
isFieldTech: true, isFieldTech: true,
@@ -10403,6 +10453,7 @@ const tech = {
isFastTime: null, isFastTime: null,
isAnthropicTech: null, isAnthropicTech: null,
isSporeWorm: null, isSporeWorm: null,
isSporeFlea: null,
isFoamShot: null, isFoamShot: null,
isIceShot: null, isIceShot: null,
isBlockRestitution: null, isBlockRestitution: null,

View File

@@ -1,32 +1,46 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
tech: iridescence - laser does 100% damage to mobs hit near their center tech: fleas - replace spores with little hoppers
tech: lens - laser does extra damage if you fire through a lens that revolves around you
tech: arc length - increase the size of the lens
virtual particles costs 4->6 research for 11% duplication frame-dragging - time dilation field stops time when you aren't moving or firing, +33% defense
quantum eraser has less duplication chance at higher difficulty modes the odds of finding this tech is low because I find it kinda annoying, but maybe you will like it
community map temple updates
molecular assembler field energy meter is yellow
wormhole is lavender
perfect diamagnetism is blue
time dilation is green blue
pilot wave is black
new room in labs: hopBossMom
harpoon now auto targets by default, but disabled when crouched
pulse + neocognitron auto targeting also disabled when crouched
bug fixes bug fixes
*********************************************************** TODO ***************************************************** *********************************************************** TODO *****************************************************
give laser gun _____ if you fire in an angle range fleas
draw angle range as a slowly rotation circle arc around player add very short (2 cycle) delay after each landing -> hop
effect: zero velocity while on short delay? try it?
bonus damage flea tech:
extra beams add a delay to flea jumping also +dmg
extra reflections reduce lifespan after hitting mob, like drones
but add in a long cooldown after a hit
mid flight attraction towards nearby mobs?
if close to mob and line of sight: set isAttached flag = true
draw a line to mob, attraction
reset isAttached to false after: 1-2s or distance gets too big
tech for shotgun?
laser tech: critical hits do _______ damage? anti-shear topology apply to grenades too? and other less useful bullets
name? polarized light, iridescence then open up tech requirements
hopBossMom menagerie: sporangium release a variety of things
spawns lots of small hopBullets spores, worms, hoppers, drones, iceIX?, foam?, missiles?
drops eggs, that hatch into hopBullets benefit: they release more stuff than normal
like sporangium
normally runs away from player, but goes closer to drop eggs swim through slime
hold up to float while in slime?
level element: exploding barrels level element: exploding barrels
@@ -34,22 +48,12 @@ improve mob invincible graphic
opacity oscillates from 100% to 0%? opacity oscillates from 100% to 0%?
make different from stun make different from stun
junk tech give strange CSS to a keyword
@keyframes bounce-munch {
0% {vertical-align: -40px;}
100% {vertical-align: 40px;}
}
make plasma ball power up and block pick up still work when you have no no energy make plasma ball power up and block pick up still work when you have no no energy
make a unique CD var for plasma ball? make a unique CD var for plasma ball?
wormhole tech: entropic gravity - gain defense for each research wormhole tech: entropic gravity - gain defense for each research
requires wormhole or negative mass field or pilot wave requires wormhole or negative mass field or pilot wave
shrapnel: a new bullet type: a very small bullet with no targeting that has a high gravity arc
maybe 1 bounce or no bounce before it ends on map or mob collision
often spawns in groups
testChamber2 testChamber2
mechanics mechanics
companion cube companion cube
@@ -184,6 +188,7 @@ tech expansion: should also make other fields do things
perfect diamagnetism moves forward when you hold down the shield perfect diamagnetism moves forward when you hold down the shield
it's great, but maybe annoying? it's great, but maybe annoying?
maybe only with crouch? maybe only with crouch?
perfect diamagnetism just replace Messier effect
time dilation drains 1/2 as much energy when paused time dilation drains 1/2 as much energy when paused
grow plasma torch as you hold it down grow plasma torch as you hold it down
negative mass effects much more space negative mass effects much more space