worm-shot, ice-shot, needle-shot, foam-shot

shotgun techs:
  (I haven't done enough testing so let me know if these different shotgun modes aren't balanced)
  worm shot
  ice-IX shot
  foam shot
  needle shot

foam lasts much longer on shielded mobs
  overall foam damage is reduced about 8%

attacks that drain energy don't work when the player is immune to harm
  slime, radiation fields, black holes
energy regen that consumes something (ammo, blocks, power ups) now works when immune to harm
  but passive energy regen is still stopped while you are immune to harm

pilot wave field can no longer hit intangible mobs with blocks
  it was too annoying that you can't use blocks to move around so I reverted it back
This commit is contained in:
landgreen
2021-07-25 05:53:27 -07:00
parent a57639987a
commit 271791703f
10 changed files with 394 additions and 262 deletions

View File

@@ -329,7 +329,7 @@ const b = {
if (Vector.magnitude(Vector.sub(where, player.position)) < radius) {
const DRAIN = (tech.isExplosionHarm ? 0.5 : 0.25) * (tech.isRadioactiveResistance ? 0.25 : 1)
// * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1)
m.energy -= DRAIN
if (m.immuneCycle < m.cycle) m.energy -= DRAIN
if (m.energy < 0) {
m.energy = 0
m.damage(0.03 * (tech.isRadioactiveResistance ? 0.25 : 1));
@@ -1036,7 +1036,7 @@ const b = {
if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) {
const DRAIN = tech.isRadioactiveResistance ? 0.0025 * 0.25 : 0.0025
if (m.energy > DRAIN) {
m.energy -= DRAIN
if (m.immuneCycle < m.cycle) m.energy -= DRAIN
} else {
m.energy = 0;
m.damage(tech.isRadioactiveResistance ? 0.00016 * 0.25 : 0.00016) //0.00015
@@ -1861,7 +1861,7 @@ const b = {
},
onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
m.health += 0.005
m.health += 0.005 + 0.005 * tech.isSporeWorm
if (m.health > m.maxHealth) m.health = m.maxHealth;
m.displayHealth();
}
@@ -1919,7 +1919,7 @@ const b = {
});
World.add(engine.world, bullet[bIndex]); //add bullet to world
if (tech.isMutualism && m.health > 0.02) {
m.health -= 0.005
m.health -= 0.005 - 0.005 * tech.isSporeWorm
m.displayHealth();
bullet[bIndex].isMutualismActive = true
}
@@ -1957,7 +1957,7 @@ const b = {
},
onEnd() {
if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) {
m.health += 0.005
m.health += 0.005 + 0.005 * tech.isSporeWorm
if (m.health > m.maxHealth) m.health = m.maxHealth;
m.displayHealth();
}
@@ -2040,7 +2040,7 @@ const b = {
World.add(engine.world, bullet[bIndex]); //add bullet to world
if (tech.isMutualism && m.health > 0.02) {
m.health -= 0.005
m.health -= 0.005 - 0.005 * tech.isSporeWorm
m.displayHealth();
bullet[bIndex].isMutualismActive = true
}
@@ -2048,17 +2048,18 @@ const b = {
},
iceIX(speed = 0, dir = m.angle + Math.PI * 2 * Math.random(), where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }) {
const me = bullet.length;
const THRUST = 0.004
const THRUST = 0.0006
const RADIUS = 18
const SCALE = 1 - 0.08 / tech.isBulletsLastLonger
bullet[me] = Bodies.polygon(where.x, where.y, 3, RADIUS, {
angle: dir - Math.PI,
inertia: Infinity,
friction: 0,
frictionAir: 0.10,
restitution: 0.3,
dmg: 0.42, //damage done in addition to the damage from momentum
frictionAir: 0.023,
restitution: 0.9,
dmg: 0.5, //damage done in addition to the damage from momentum
lookFrequency: 14 + Math.floor(8 * Math.random()),
endCycle: simulation.cycle + 140 * tech.isBulletsLastLonger,
endCycle: simulation.cycle + 150 * tech.isBulletsLastLonger + Math.floor(25 * Math.random()),
classType: "bullet",
collisionFilter: {
category: cat.bullet,
@@ -2071,13 +2072,8 @@ const b = {
mobs.statusSlow(who, 180)
this.endCycle = simulation.cycle
// if (tech.isHeavyWater) mobs.statusDoT(who, 0.15, 300)
if (m.immuneCycle < m.cycle && tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
setTimeout(function() {
if (!who.alive) {
m.energy += tech.iceEnergy * 0.8
// m.addHealth(tech.iceEnergy * 0.04)
}
}, 10);
if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) {
setTimeout(() => { if (!who.alive) m.energy += tech.iceEnergy * 0.8 }, 10);
}
},
onEnd() {},
@@ -2085,8 +2081,7 @@ const b = {
// this.force.y += this.mass * 0.0002;
//find mob targets
if (!(simulation.cycle % this.lookFrequency)) {
const scale = 1 - 0.08 / tech.isBulletsLastLonger //0.9 * tech.isBulletsLastLonger;
Matter.Body.scale(this, scale, scale);
Matter.Body.scale(this, SCALE, SCALE);
this.lockedOn = null;
let closeDist = Infinity;
for (let i = 0, len = mob.length; i < len; ++i) {
@@ -2380,7 +2375,7 @@ const b = {
if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.radioRadius) {
const DRAIN = tech.isRadioactiveResistance ? 0.0023 * 0.25 : 0.0023
if (m.energy > DRAIN) {
m.energy -= DRAIN
if (m.immuneCycle < m.cycle) m.energy -= DRAIN
} else {
m.energy = 0;
m.damage(tech.isRadioactiveResistance ? 0.00015 * 0.25 : 0.00015) //0.00015
@@ -2543,14 +2538,11 @@ const b = {
// radius *= Math.sqrt(tech.bulletSize)
const me = bullet.length;
bullet[me] = Bodies.polygon(position.x, position.y, 20, radius, {
// angle: 0,
density: 0.000001, // 0.001 is normal density
inertia: Infinity,
frictionAir: 0.003,
// friction: 0.2,
// restitution: 0.2,
dmg: 0, //damage on impact
damage: (tech.isFastFoam ? 0.048 : 0.012) * (tech.isFoamTeleport ? 1.66 : 1), //damage done over time
damage: (tech.isFastFoam ? 0.044 : 0.011) * (tech.isFoamTeleport ? 1.66 : 1), //damage done over time
scale: 1 - 0.006 / tech.isBulletsLastLonger * (tech.isFastFoam ? 1.6 : 1),
classType: "bullet",
collisionFilter: {
@@ -2610,9 +2602,6 @@ const b = {
this.radius *= this.scale;
if (this.radius < 8) this.endCycle = 0;
}
if (this.target && this.target.alive) { //if stuck to a target
const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector
if (this.target.isVerticesChange) {
@@ -2622,12 +2611,10 @@ const b = {
}
Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.9))
Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9);
// Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9)
if (this.target.isShielded) {
this.target.damage(b.dmgScale * this.damage, true); //shield damage bypass
//shrink if mob is shielded
const SCALE = 1 - 0.01 / tech.isBulletsLastLonger
const SCALE = 1 - 0.004 / tech.isBulletsLastLonger //shrink if mob is shielded
Matter.Body.scale(this, SCALE, SCALE);
this.radius *= SCALE;
} else {
@@ -2641,9 +2628,7 @@ const b = {
let targets = []
for (let i = 0, len = mob.length; i < len; i++) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist < 1000000) {
targets.push(mob[i])
}
if (dist < 1000000) targets.push(mob[i])
}
const radius = Math.min(this.radius * 0.5, 10)
const len = bullet.length < 100 ? 2 : 1
@@ -2682,7 +2667,6 @@ const b = {
this.radius *= SCALE;
} else {
this.force.y += this.mass * tech.foamGravity; //gravity
if (tech.isFoamAttract) {
for (let i = 0, len = mob.length; i < len; i++) {
if (!mob[i].isBadTarget && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
@@ -2768,6 +2752,71 @@ const b = {
};
bullet[me].do = function() {};
},
needle(angle = m.angle) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(m.pos.x + 40 * Math.cos(m.angle), m.pos.y + 40 * Math.sin(m.angle), 75, 0.75, b.fireAttributes(angle));
bullet[me].collisionFilter.mask = tech.isNeedleShieldPierce ? cat.body : cat.body | cat.mobShield
Matter.Body.setDensity(bullet[me], 0.00001); //0.001 is normal
bullet[me].endCycle = simulation.cycle + 180;
bullet[me].immuneList = []
bullet[me].do = function() {
const whom = Matter.Query.collides(this, mob)
if (whom.length && this.speed > 20) { //if touching a mob
for (let i = 0, len = whom.length; i < len; i++) {
who = whom[i].bodyA
if (who && who.mob) {
let immune = false
for (let i = 0; i < this.immuneList.length; i++) { //check if this needle has hit this mob already
if (this.immuneList[i] === who.id) {
immune = true
break
}
}
if (!immune) {
if (tech.isNailCrit && !who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.975) {
b.explosion(this.position, 220 + 50 * Math.random()); //makes bullet do explosive damage at end
}
this.immuneList.push(who.id) //remember that this needle has hit this mob once already
who.foundPlayer();
if (tech.isNailRadiation) {
mobs.statusDoT(who, tech.isFastRadiation ? 12 : 3, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles
} else {
let dmg = b.dmgScale * 5.5
if (tech.isCrit && who.isStunned) dmg *= 4
who.damage(dmg, tech.isNeedleShieldPierce);
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
radius: Math.log(2 * dmg + 1.1) * 40,
color: simulation.playerDmgColor,
time: simulation.drawTime
});
}
}
}
}
} else if (Matter.Query.collides(this, map).length) { //stick in walls
this.collisionFilter.mask = 0;
Matter.Body.setAngularVelocity(this, 0)
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
this.do = function() {
if (!Matter.Query.collides(this, map).length) this.force.y += this.mass * 0.001;
}
} else if (this.speed < 30) {
this.force.y += this.mass * 0.001; //no gravity until it slows down to improve aiming
}
};
const SPEED = 90
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + SPEED * Math.cos(angle),
y: m.Vy / 2 + SPEED * Math.sin(angle)
});
// Matter.Body.setDensity(bullet[me], 0.00001);
World.add(engine.world, bullet[me]); //add bullet to world
},
// **************************************************************************************************
// **************************************************************************************************
// ******************************** Bots *********************************************
@@ -3629,91 +3678,19 @@ const b = {
this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / CD)
},
fireNeedles() {
function makeNeedle(angle = m.angle) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(m.pos.x + 40 * Math.cos(m.angle), m.pos.y + 40 * Math.sin(m.angle), 75, 0.75, b.fireAttributes(angle));
bullet[me].collisionFilter.mask = tech.isNeedleShieldPierce ? cat.body : cat.body | cat.mobShield
Matter.Body.setDensity(bullet[me], 0.00001); //0.001 is normal
bullet[me].endCycle = simulation.cycle + 180;
bullet[me].immuneList = []
bullet[me].do = function() {
const whom = Matter.Query.collides(this, mob)
if (whom.length && this.speed > 20) { //if touching a mob
for (let i = 0, len = whom.length; i < len; i++) {
who = whom[i].bodyA
if (who && who.mob) {
let immune = false
for (let i = 0; i < this.immuneList.length; i++) { //check if this needle has hit this mob already
if (this.immuneList[i] === who.id) {
immune = true
break
}
}
if (!immune) {
if (tech.isNailCrit && !who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.975) {
b.explosion(this.position, 220 + 50 * Math.random()); //makes bullet do explosive damage at end
}
this.immuneList.push(who.id) //remember that this needle has hit this mob once already
who.foundPlayer();
if (tech.isNailRadiation) {
mobs.statusDoT(who, tech.isFastRadiation ? 12 : 3, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles
} else {
let dmg = b.dmgScale * 5.5
if (tech.isCrit && who.isStunned) dmg *= 4
who.damage(dmg, tech.isNeedleShieldPierce);
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
radius: Math.log(2 * dmg + 1.1) * 40,
color: simulation.playerDmgColor,
time: simulation.drawTime
});
}
}
}
}
} else if (Matter.Query.collides(this, map).length) { //stick in walls
this.collisionFilter.mask = 0;
Matter.Body.setAngularVelocity(this, 0)
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
this.do = function() {
if (!Matter.Query.collides(this, map).length) this.force.y += this.mass * 0.001;
}
} else if (this.speed < 30) {
this.force.y += this.mass * 0.001; //no gravity until it slows down to improve aiming
}
};
const SPEED = 90
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + SPEED * Math.cos(angle),
y: m.Vy / 2 + SPEED * Math.sin(angle)
});
// Matter.Body.setDensity(bullet[me], 0.00001);
World.add(engine.world, bullet[me]); //add bullet to world
}
if (m.crouch) {
m.fireCDcycle = m.cycle + 45 * b.fireCDscale; // cool down
makeNeedle()
b.needle()
for (let i = 1; i < 4; i++) { //4 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i);
setTimeout(() => { if (!simulation.paused) b.needle() }, 60 * i);
}
} else {
m.fireCDcycle = m.cycle + 25 * b.fireCDscale; // cool down
makeNeedle()
b.needle()
for (let i = 1; i < 3; i++) { //3 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i);
setTimeout(() => { if (!simulation.paused) b.needle() }, 60 * i);
}
}
// const spread = (m.crouch ? 0.013 : 0.06)
// makeNeedle(m.angle + spread)
// makeNeedle()
// makeNeedle(m.angle - spread)
},
fireRivets() {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 25 : 17) * b.fireCDscale); // cool down
@@ -3806,11 +3783,11 @@ const b = {
let knock, spread
if (m.crouch) {
spread = 0.65
m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCDscale); // cool down
m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCDscale) // cool down
if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(58 * b.fireCDscale)) m.immuneCycle = m.cycle + Math.floor(58 * b.fireCDscale); //player is immune to damage for 30 cycles
knock = 0.01
} else {
m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale); // cool down
m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale) // cool down
if (tech.isShotgunImmune && m.immuneCycle < m.cycle + Math.floor(47 * b.fireCDscale)) m.immuneCycle = m.cycle + Math.floor(47 * b.fireCDscale); //player is immune to damage for 30 cycles
spread = 1.3
knock = 0.1
@@ -3900,7 +3877,7 @@ const b = {
y: speed * Math.sin(dirOff)
});
bullet[me].onEnd = function() {
b.explosion(this.position, 150 * (tech.isShotgunReversed ? 1.6 : 1) + (Math.random() - 0.5) * 40); //makes bullet do explosive damage at end
b.explosion(this.position, 160 * (tech.isShotgunReversed ? 1.6 : 1) + (Math.random() - 0.5) * 40); //makes bullet do explosive damage at end
}
bullet[me].beforeDmg = function() {
this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion
@@ -3910,7 +3887,7 @@ const b = {
}
} else if (tech.isNailShot) {
spread *= 0.65
const dmg = 1.4 * (tech.isShotgunReversed ? 1.6 : 1)
const dmg = 2 * (tech.isShotgunReversed ? 1.6 : 1)
if (m.crouch) {
for (let i = 0; i < 17; i++) {
speed = 38 + 15 * Math.random()
@@ -3938,6 +3915,49 @@ const b = {
}, dmg)
}
}
} else if (tech.isWormShot) {
const unit = {
x: Math.cos(m.angle),
y: Math.sin(m.angle)
}
const where = {
x: m.pos.x + 35 * unit.x,
y: m.pos.y + 35 * unit.y
}
for (let i = 0, len = 3 * (tech.isShotgunReversed ? 1.6 : 1) + Math.random(); i < len; i++) {
b.worm(where)
const SPEED = 14 + 6 * Math.random() + 20 * m.crouch;
Matter.Body.setVelocity(bullet[bullet.length - 1], {
x: SPEED * unit.x,
y: SPEED * unit.y
});
}
} else if (tech.isIceShot) {
const spread = (m.crouch ? 0.6 : 1.6)
for (let i = 0, len = 16 * (tech.isShotgunReversed ? 1.6 : 1); i < len; i++) {
// iceIX(speed = 0, dir = m.angle + Math.PI * 2 * Math.random(), where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }) {
b.iceIX(14 + 30 * Math.random(), m.angle + spread * (Math.random() - 0.5))
}
} else if (tech.isFoamShot) {
const spread = (m.crouch ? 0.35 : 0.7)
const where = {
x: m.pos.x + 25 * Math.cos(m.angle),
y: m.pos.y + 25 * Math.sin(m.angle)
}
const number = 14 * (tech.isShotgunReversed ? 1.6 : 1)
for (let i = 0; i < number; i++) {
const SPEED = 25 + 12 * Math.random();
const angle = m.angle + spread * (Math.random() - 0.5)
b.foam(where, { x: SPEED * Math.cos(angle), y: SPEED * Math.sin(angle) }, 5 + 8 * Math.random())
}
} else if (tech.isNeedleShot) {
const number = 12 * (tech.isShotgunReversed ? 1.6 : 1)
const spread = (m.crouch ? 0.04 : 0.08)
let angle = m.angle - (number - 1) * spread * 0.5
for (let i = 0; i < number; i++) {
b.needle(angle)
angle += spread
}
} else {
const side = 22
for (let i = 0; i < 17; i++) {
@@ -4843,7 +4863,7 @@ const b = {
if (tech.isCapacitor) {
if ((m.energy > 0.16 || tech.isRailEnergyGain)) { //&& m.immuneCycle < m.cycle
if (m.immuneCycle < m.cycle) m.energy += 0.16 * (tech.isRailEnergyGain ? 6 : -1)
m.energy += 0.16 * (tech.isRailEnergyGain ? 4.5 : -1)
m.fireCDcycle = m.cycle + Math.floor(30 * b.fireCDscale);
const me = bullet.length;
bullet[me] = Bodies.rectangle(m.pos.x + 50 * Math.cos(m.angle), m.pos.y + 50 * Math.sin(m.angle), 60, 14, {
@@ -4970,7 +4990,7 @@ const b = {
bullet[me].charge = 0;
bullet[me].do = function() {
if (m.energy < 0.005 && !tech.isRailEnergyGain) {
if (m.immuneCycle < m.cycle) m.energy += 0.05 + this.charge * 0.3
m.energy += 0.05 + this.charge * 0.2
m.fireCDcycle = m.cycle + 120; // cool down if out of energy
this.endCycle = 0;
return
@@ -5019,7 +5039,7 @@ const b = {
let smoothRate = 0.98 * (m.crouch ? 0.99 : 1) * (0.98 + 0.02 * b.fireCDscale) //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
this.charge = this.charge * smoothRate + 1 * (1 - smoothRate)
if (tech.isRailEnergyGain) {
if (m.immuneCycle < m.cycle) m.energy += (this.charge - previousCharge) * 2 //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
m.energy += (this.charge - previousCharge) * 1.5 //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
} else {
m.energy -= (this.charge - previousCharge) * 0.33 //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
}

View File

@@ -12,10 +12,15 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(60) //30 is near max on hard //60 is near max on why
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true
// m.setField("wormhole")
// b.giveGuns("spores")
// b.giveGuns("shotgun")
// b.giveGuns("foam")
// tech.isNeedleShot = true
// tech.isIceShot = true
// tech.isFoamShot = true
// tech.isWormShot = true
// tech.giveTech("CPT reversal")
// tech.giveTech("causality bombs")
// b.giveGuns("wave beam")
@@ -966,12 +971,14 @@ const level = {
ctx.fillRect(this.min.x, this.min.y + offset, this.width, this.height - offset)
if (this.height > 0 && Matter.Query.region([player], this).length) {
const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen
if (m.energy > DRAIN) {
m.energy -= DRAIN
m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1) * 0.03) //still take 2% damage while you have energy
} else {
m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1))
if (m.immuneCycle < m.cycle) {
const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen
if (m.energy > DRAIN) {
m.energy -= DRAIN
m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1) * 0.03) //still take 2% damage while you have energy
} else {
m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1))
}
}
//float
if (player.velocity.y > 5) player.force.y -= 0.95 * player.mass * simulation.g
@@ -1621,8 +1628,10 @@ const level = {
ctx.lineWidth = 2;
if (Vector.magnitudeSquared(Vector.sub(m.pos, powerUp1.position)) < 90000) { //zone radius is 300
//damage player and drain energy
if (m.immuneCycle < m.cycle) m.damage(0.01);
if (m.energy > 0.1) m.energy -= 0.02
if (m.immuneCycle < m.cycle) {
m.damage(0.01);
if (m.energy > 0.1) m.energy -= 0.02
}
//draw electricity going towards player
const unit = Vector.normalise(Vector.sub(m.pos, powerUp1.position))
let xElec = powerUp1.position.x + 40 * unit.x;
@@ -2256,10 +2265,10 @@ const level = {
spawn.mapRect(6700, -1800, 800, 2600); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
// spawn.starter(1900, -500, 200) //big boy
spawn.growBossCulture(1900, -500)
spawn.starter(1900, -500, 200) //big boy
// spawn.growBossCulture(1900, -500)
// spawn.pulsarBoss(1900, -500)
// spawn.snakeBoss(1900, -500)
// spawn.shieldingBoss(1900, -500)
// spawn.grenadierBoss(1900, -500)

View File

@@ -417,8 +417,10 @@ const mobs = {
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
// ctx.lineDashOffset = 6*(simulation.cycle % 215);
if (this.distanceToPlayer() < this.laserRange) {
if (m.immuneCycle < m.cycle) m.damage(0.0003 * simulation.dmgScale);
if (m.energy > 0.1) m.energy -= 0.003
if (m.immuneCycle < m.cycle) {
m.damage(0.0003 * simulation.dmgScale);
if (m.energy > 0.1) m.energy -= 0.003
}
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
ctx.lineTo(m.pos.x, m.pos.y);

View File

@@ -635,7 +635,7 @@ const m = {
}
if (tech.isEnergyHealth) {
m.energy -= dmg * 1.15;
m.energy -= dmg * 1.1;
if (m.energy < 0 || isNaN(m.energy)) { //taking deadly damage
if (tech.isDeathAvoid && powerUps.research.count && !tech.isDeathAvoidedThisLevel) {
tech.isDeathAvoidedThisLevel = true
@@ -2443,7 +2443,9 @@ const m = {
const unit = Vector.mult(Vector.normalise(sub), body[i].mass * tech.pilotForce * Vector.magnitude(sub))
body[i].force.x += unit.x
body[i].force.y += unit.y - body[i].mass * simulation.g //remove gravity effects
if (body[i].collisionFilter.category !== cat.bullet) body[i].collisionFilter.category = cat.bullet;
// if (body[i].collisionFilter.category !== cat.bullet) {
// body[i].collisionFilter.category = cat.bullet;
// }
} else {
m.fieldCDcycle = m.cycle + 120;
m.fieldOn = false
@@ -2602,7 +2604,7 @@ const m = {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
m.fieldRange *= 0.8
if (tech.isWormholeEnergy && m.immuneCycle < m.cycle) m.energy += 0.63
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
if (tech.isSporeWorm) {

View File

@@ -676,7 +676,7 @@ const powerUps = {
onPickUp(who) {
powerUps.research.currentRerollCount = 0
if (tech.isTechDamage && who.name === "tech") m.damage(0.11)
if (tech.isMassEnergy && m.immuneCycle < m.cycle) m.energy += 2;
if (tech.isMassEnergy) m.energy += 2;
if (tech.isMineDrop) {
if (tech.isLaserMine) {
b.laserMine(who.position)

View File

@@ -696,7 +696,7 @@ const simulation = {
if (tech.isMutualism && !tech.isEnergyHealth) {
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].isMutualismActive) {
m.health += 0.005
m.health += 0.005 + 0.005 * tech.isSporeWorm
if (m.health > m.maxHealth) m.health = m.maxHealth;
m.displayHealth();
}

View File

@@ -188,7 +188,7 @@ const spawn = {
if (m.immuneCycle < m.cycle && Vector.magnitude(Vector.sub(player.position, this.position)) < this.radius) {
const DRAIN = tech.isRadioactiveResistance ? 0.07 * 0.25 : 0.07
if (m.energy > DRAIN) {
m.energy -= DRAIN
if (m.immuneCycle < m.cycle) m.energy -= DRAIN
} else {
m.energy = 0;
m.damage((tech.isRadioactiveResistance ? 0.007 * 0.25 : 0.007) * simulation.dmgScale)
@@ -504,9 +504,9 @@ const spawn = {
ctx.fill();
//when player is inside event horizon
if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
if (m.energy > 0) m.energy -= 0.01
if (m.energy < 0.15 && m.immuneCycle < m.cycle) {
m.damage(0.0004 * simulation.dmgScale);
if (m.immuneCycle < m.cycle) {
if (m.energy > 0) m.energy -= 0.01
if (m.energy < 0.15 && m.immuneCycle < m.cycle) m.damage(0.0004 * simulation.dmgScale);
}
const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
@@ -704,7 +704,7 @@ const spawn = {
let me = mob[mob.length - 1];
// console.log(`mass=${me.mass}, radius = ${radius}`)
me.accelMag = 0.0002
me.repulsionRange = 100000; //squared
me.repulsionRange = 100000 + radius * radius; //squared
// me.memory = 120;
me.seeAtDistance2 = 2000000 //1400 vision range
Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback
@@ -1338,9 +1338,9 @@ const spawn = {
//when player is inside event horizon
if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
if (m.energy > 0) m.energy -= 0.004
if (m.energy < 0.1 && m.immuneCycle < m.cycle) {
m.damage(0.00015 * simulation.dmgScale);
if (m.immuneCycle < m.cycle) {
if (m.energy > 0) m.energy -= 0.004
if (m.energy < 0.1) m.damage(0.00015 * simulation.dmgScale);
}
const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
player.force.x -= 0.00125 * player.mass * Math.cos(angle) * (m.onGround ? 1.8 : 1);
@@ -1447,9 +1447,9 @@ const spawn = {
ctx.fill();
//when player is inside event horizon
if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
if (m.energy > 0) m.energy -= 0.006
if (m.energy < 0.1 && m.immuneCycle < m.cycle) {
m.damage(0.0002 * simulation.dmgScale);
if (m.immuneCycle < m.cycle) {
if (m.energy > 0) m.energy -= 0.006
if (m.energy < 0.1) m.damage(0.0002 * simulation.dmgScale);
}
const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
player.force.x -= 0.0013 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
@@ -1703,10 +1703,12 @@ const spawn = {
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); //the dashed effect is not set back to normal, because it looks neat for how the player is drawn
// ctx.lineDashOffset = 6*(simulation.cycle % 215);
if (this.distanceToPlayer() < this.laserRange) {
if (m.energy > 0.002) {
m.energy -= 0.0035
} else if (m.immuneCycle < m.cycle) {
m.damage(0.0003 * simulation.dmgScale)
if (m.immuneCycle < m.cycle) {
if (m.energy > 0.002) {
m.energy -= 0.0035
} else {
m.damage(0.0003 * simulation.dmgScale)
}
}
ctx.beginPath();
ctx.moveTo(eye.x, eye.y);
@@ -3551,7 +3553,8 @@ const spawn = {
};
},
snakeBoss(x, y, radius = 75) { //snake boss with a laser head
mobs.spawn(x, y, 8, radius, "rgb(55,170,170)");
const color1 = "#f27"
mobs.spawn(x, y, 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1];
me.isBoss = true;
me.damageReduction = 0.25;
@@ -3579,6 +3582,14 @@ const spawn = {
//snake tail
const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40)
spawn.lineGroup(x + 105, y, "snakeBody", nodes);
for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors
if (i % 2) {
mob[i].fill = "#333"
} else {
mob[i].fill = color1
}
}
//constraint with first 3 mobs in line
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes],
@@ -3598,7 +3609,7 @@ const spawn = {
stiffness: 0.05
});
World.add(engine.world, consBB[consBB.length - 1]);
spawn.shield(me, x, y, 1);
// spawn.shield(me, x, y, 1);
},
snakeBody(x, y, radius = 10) {
mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
@@ -3610,6 +3621,8 @@ const spawn = {
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body
me.accelMag = 0.0004 * simulation.accelScale;
me.leaveBody = false;
me.showHealthBar = false;
// Matter.Body.setDensity(me, 0.00004); //normal is 0.001
me.frictionAir = 0.02;
me.isSnakeTail = true;
me.stroke = "transparent"

View File

@@ -682,7 +682,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("wave beam") || tech.isNeutronBomb || tech.isIceField || tech.relayIce || tech.blockingIce > 1
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("wave beam") || tech.isNeutronBomb || tech.isIceField || tech.isIceShot || tech.relayIce || tech.blockingIce > 1
},
requires: "drones, spores, missiles, foam, wave beam, neutron bomb, ice IX",
effect() {
@@ -865,9 +865,9 @@
frequency: 1,
frequencyDefault: 1,
allowed() {
return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isDroneRadioactive || tech.isSporeField || tech.isMissileField || tech.isIceField)) || (tech.haveGunCheck("drones") && !tech.isDroneRadioactive) || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot
return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isDroneRadioactive || tech.isSporeField || tech.isMissileField || tech.isIceField)) || (tech.haveGunCheck("drones") && !tech.isDroneRadioactive) || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot
},
requires: "super balls, shotgun, drones, not irradiated drones",
requires: "super balls, basic or slug shotgun, drones, not irradiated drones",
effect() {
tech.isIncendiary = true
},
@@ -1812,7 +1812,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField || tech.relayIce || tech.blockingIce > 1) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob
return (tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField || tech.isIceShot || tech.relayIce || tech.blockingIce > 1) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob
},
requires: "a localized freeze effect, no other mob death tech",
effect() {
@@ -1830,7 +1830,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isIceField || tech.relayIce || tech.blockingIce || tech.iceIXOnDeath
return tech.isIceField || tech.relayIce || tech.blockingIce || tech.iceIXOnDeath || tech.isIceShot
},
requires: "ice IX",
effect() {
@@ -1848,7 +1848,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField || tech.relayIce || tech.blockingIce > 1 || tech.iceIXOnDeath
return tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField || tech.relayIce || tech.blockingIce > 1 || tech.iceIXOnDeath || tech.isIceShot
},
requires: "a localized freeze effect",
effect() {
@@ -1866,7 +1866,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isStunField || tech.isExplosionStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 || tech.iceIXOnDeath
return tech.isStunField || tech.isExplosionStun || tech.oneSuperBall || tech.isHarmFreeze || tech.isIceField || tech.relayIce || tech.isIceCrystals || tech.isSporeFreeze || tech.isAoESlow || tech.isFreezeMobs || tech.isCloakStun || tech.orbitBotCount > 1 || tech.isWormholeDamage || tech.blockingIce > 1 || tech.iceIXOnDeath || tech.isIceShot
},
requires: "a freezing or stunning effect",
effect() {
@@ -3461,9 +3461,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isNeedles && !tech.isNailRadiation
return (tech.isNeedles || tech.isNeedleShot) && !tech.isNailRadiation
},
requires: "needle gun, not irradiated nails",
requires: "needle gun, needle-shot, not irradiated nails",
effect() {
tech.isNeedleShieldPierce = true
},
@@ -3729,44 +3729,6 @@
}
}
},
{
name: "nailshot",
description: "the <strong>shotgun</strong> fires a burst of <strong>nails</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isSlugShot
},
requires: "shotgun, not slug, incendiary",
effect() {
tech.isNailShot = true;
},
remove() {
tech.isNailShot = false;
}
},
{
name: "shotgun slug",
description: "the <strong>shotgun</strong> fires 1 large <strong>bullet</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot
},
requires: "shotgun, not nailshot",
effect() {
tech.isSlugShot = true;
},
remove() {
tech.isSlugShot = false;
}
},
{
name: "Newton's 3rd law",
description: "<strong>shotgun</strong> <strong>recoil</strong> is increased<br>decrease <strong>shotgun</strong> <strong><em>delay</em></strong> after firing by <strong>66%</strong>",
@@ -3805,6 +3767,120 @@
tech.isShotgunReversed = false;
}
},
{
name: "shotgun slug",
description: "the <strong>shotgun</strong> fires a huge dense <strong>bullet</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not nail-shot, foam-shot, worm-shot, ice-shot",
effect() {
tech.isSlugShot = true;
},
remove() {
tech.isSlugShot = false;
}
},
{
name: "nail-shot",
description: "the <strong>shotgun</strong> fires a burst of <strong>nails</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isSlugShot && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, slug, foam-shot, worm-shot, ice-shot",
effect() {
tech.isNailShot = true;
},
remove() {
tech.isNailShot = false;
}
},
{
name: "worm-shot",
description: "the <strong>shotgun</strong> fires <strong>3-4</strong> <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong>", //<br><strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> seek out nearby mobs
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, nail-shot, slug, foam-shot, ice-shot",
effect() {
tech.isWormShot = true;
},
remove() {
tech.isWormShot = false;
}
},
{
name: "foam-shot",
description: "the <strong>shotgun</strong> fires <strong>14</strong> <strong>foam</strong> bubbles",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isIceShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, nail-shot, slug, worm-shot, ice-shot",
effect() {
tech.isFoamShot = true;
},
remove() {
tech.isFoamShot = false;
}
},
{
name: "ice-shot",
description: "the <strong>shotgun</strong> fires <strong>16</strong> <strong class='color-s'>ice IX</strong> crystals",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
},
requires: "shotgun, not incendiary, nail-shot, slug, foam-shot, worm-shot",
effect() {
tech.isIceShot = true;
},
remove() {
tech.isIceShot = false;
}
},
{
name: "needle-shot",
description: "the <strong>shotgun</strong> fires <strong>12</strong> mob piercing <strong>needles</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isSlugShot && !tech.isFoamShot && !tech.isWormShot && !tech.isIceShot
},
requires: "shotgun, not incendiary, nail-shot, slug, foam-shot, worm-shot, ice-shot",
effect() {
tech.isNeedleShot = true;
},
remove() {
tech.isNeedleShot = false;
}
},
{
name: "super duper",
description: "fire <strong>1</strong> additional <strong>super ball</strong>",
@@ -4318,9 +4394,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormShot
},
requires: "spores",
requires: "spores or worms",
effect() {
tech.isSporeFreeze = true
},
@@ -4337,9 +4413,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField
return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField || tech.isWormShot
},
requires: "spores",
requires: "spores or worms",
effect() {
tech.isSporeFollow = true
},
@@ -4347,6 +4423,25 @@
tech.isSporeFollow = false
}
},
{
name: "mutualism",
description: "increase <strong class='color-p' style='letter-spacing: 2px;'>spore</strong> <strong class='color-d'>damage</strong> by <strong>150%</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spores</strong> borrow <strong>0.5</strong> <strong class='color-h'>health</strong> until they <strong>die</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField) && !tech.isEnergyHealth || tech.isWormShot
},
requires: "spores, worms, not mass-energy",
effect() {
tech.isMutualism = true
},
remove() {
tech.isMutualism = false
}
},
{
name: "nematodes",
description: "<strong class='color-p' style='letter-spacing: 2px;'>spores</strong> develop into <strong>1/2</strong> as many <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong><br><strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> do <strong>200%</strong> more <strong class='color-d'>damage</strong>",
@@ -4366,25 +4461,6 @@
tech.isSporeWorm = false
}
},
{
name: "mutualism",
description: "increase <strong class='color-p' style='letter-spacing: 2px;'>spore</strong> <strong class='color-d'>damage</strong> by <strong>150%</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spores</strong> borrow <strong>0.5</strong> <strong class='color-h'>health</strong> until they <strong>die</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField) && !tech.isEnergyHealth
},
requires: "spores, not mass-energy",
effect() {
tech.isMutualism = true
},
remove() {
tech.isMutualism = false
}
},
{
name: "reduced tolerances",
description: "increase <strong>drone</strong> <strong class='color-g'>ammo</strong>/<strong class='color-f'>efficiency</strong> by <strong>66%</strong><br>reduce the average <strong>drone</strong> lifetime by <strong>40%</strong>",
@@ -4543,6 +4619,25 @@
tech.droneRadioDamage = 1
}
},
{
name: "electrostatic induction",
description: "<strong>foam</strong> bubbles are electrically charged<br>causing <strong>attraction</strong> to nearby <strong>mobs</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isFoamTeleport && (tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot)
},
requires: "foam, not uncertainty",
effect() {
tech.isFoamAttract = true
},
remove() {
tech.isFoamAttract = false
}
},
{
name: "uncertainty principle",
description: "<strong>foam</strong> bubbles randomly change <strong>position</strong><br>increase <strong>foam</strong> <strong class='color-d'>damage</strong> per second by <strong>66%</strong>",
@@ -4552,7 +4647,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.foamBotCount > 1)
return !tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot)
},
requires: "foam, not electrostatic induction",
effect() {
@@ -4571,7 +4666,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam") || tech.foamBotCount > 1
return tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot
},
requires: "foam",
effect() {
@@ -4590,7 +4685,7 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("foam") || tech.foamBotCount > 1
return tech.haveGunCheck("foam") || tech.foamBotCount > 1 || tech.isFoamShot
},
requires: "foam",
effect() {
@@ -4640,25 +4735,6 @@
tech.isAmmoFoamSize = false;
}
},
{
name: "electrostatic induction",
description: "<strong>foam</strong> bubbles are electrically charged<br>causing <strong>attraction</strong> to nearby <strong>mobs</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return !tech.isFoamTeleport && (tech.haveGunCheck("foam") || tech.foamBotCount > 1)
},
requires: "foam, not uncertainty",
effect() {
tech.isFoamAttract = true
},
remove() {
tech.isFoamAttract = false
}
},
{
name: "half-wave rectifier",
description: "charging the <strong>rail gun</strong> gives you <strong class='color-f'>energy</strong><br><em>instead of draining it</em>",
@@ -7553,6 +7629,10 @@
isFieldHarmReduction: null,
isFastTime: null,
isDroneTeleport: null,
isAnthropicTech: null,
isSporeWorm: null,
isAnthropicTech: null
isWormShot: null,
isFoamShot: null,
isIceShot: null,
isNeedleShot: null
}