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,
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
for (let i = 0, len = mob.length; i < len; i++) {
const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position))
@@ -2386,9 +2386,9 @@ const b = {
if (best.who.alive) {
best.who.locatePlayer();
if (best.who.damageReduction) {
if ( //crit
if ( //iridescence
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
simulation.drawList.push({ //add dmg to draw queue
@@ -2663,8 +2663,7 @@ const b = {
!mob[i].isBadTarget &&
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(body, this.position, mob[i].position).length === 0 &&
!mob[i].isInvulnerable
Matter.Query.ray(body, this.position, mob[i].position).length === 0
) {
if (tech.isStun) b.AoEStunEffect(this.position, 700 + mob[i].radius + random); //AoEStunEffect(where, range, cycles = 90 + 60 * Math.random()) {
if (tech.isMineSentry) {
@@ -2961,7 +2960,7 @@ const b = {
friction: 0,
frictionAir: 0.023,
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()),
endCycle: simulation.cycle + 100 * tech.isBulletsLastLonger + Math.floor(25 * Math.random()),
classType: "bullet",
@@ -3022,6 +3021,128 @@ const b = {
// 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) {
const me = bullet.length;
const THRUST = 0.0015
@@ -3774,7 +3895,13 @@ const b = {
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) {
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)
const slow = 0.9
Matter.Body.setVelocity(this, {
@@ -3800,7 +3927,7 @@ const b = {
targetedBlock(who, speed = 50 - Math.min(20, who.mass * 2), range = 1600) {
let closestMob, dist
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));
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]
@@ -4331,7 +4458,7 @@ const b = {
minDmgSpeed: 2,
// lookFrequency: 56 + Math.floor(17 * Math.random()) - isUpgraded * 20,
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()),
range: 60 * (1 + 0.3 * Math.random()) + 3 * b.totalBots(),
endCycle: Infinity,
@@ -4492,7 +4619,7 @@ const b = {
let target
for (let i = 0, len = mob.length; i < len; i++) {
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;
target = Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist2) / 60))
const radius = 6 + 7 * Math.random()
@@ -4523,10 +4650,7 @@ const b = {
restitution: 0.5 * (1 + 0.5 * Math.random()),
acceleration: 0.0015 * (1 + 0.3 * Math.random()),
playerRange: 140 + Math.floor(30 * Math.random()) + 2 * b.totalBots(),
offPlayer: {
x: 0,
y: 0,
},
offPlayer: { x: 0, y: 0, },
dmg: 0, //damage done in addition to the damage from momentum
minDmgSpeed: 2,
lookFrequency: 40 + Math.floor(7 * Math.random()) - 10 * tech.isLaserBotUpgrade,
@@ -4562,11 +4686,14 @@ const b = {
let closeDist = this.range;
for (let i = 0, len = mob.length; i < len; ++i) {
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].isBadTarget || mob[i].isMobBullet) &&
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;
this.lockedOn = mob[i]
}
@@ -4686,10 +4813,13 @@ const b = {
let closeDist = this.range;
for (let i = 0, len = mob.length; i < len; ++i) {
const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius;
if (DIST < closeDist &&
if (
DIST < closeDist &&
!mob[i].isBadTarget &&
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;
this.lockedOn = mob[i]
}
@@ -4842,7 +4972,7 @@ const b = {
y: best.y
};
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.locatePlayer();
//push mobs away
@@ -4948,7 +5078,7 @@ const b = {
})
for (let i = 0; i < q.length; i++) {
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)
q[i].damage(dmg);
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
let scale = 1.01
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)
} else {
b.spore(this.position)
}
// this.totalSpores--
scale = 0.96
if (this.stuckTo && this.stuckTo.alive) scale = 0.9
Matter.Body.scale(this, scale, scale);
@@ -6289,18 +6424,21 @@ const b = {
this.radius *= scale
if (this.radius > this.maxRadius) this.endCycle = 0;
}
// this.force.y += this.mass * 0.00045;
//draw green glow
ctx.fillStyle = "rgba(0,200,125,0.16)";
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI);
ctx.fill();
};
//spawn bullets on end
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)
} else {
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 (this.ammo > -1) {
// 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
targetCount++
if (targetCount > tech.extraHarpoons) break
@@ -6574,7 +6712,7 @@ const b = {
//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
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 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
@@ -7066,7 +7204,11 @@ const b = {
fire() {},
chooseFireMethod() {
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) {
this.fire = () => {
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>`
}
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
//right side
text = "";
if (tech.isPauseSwitchField && !simulation.isChoosing) {
@@ -304,7 +303,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
}
}
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
document.getElementById("tech").style.display = "none"
@@ -933,7 +932,7 @@ window.addEventListener("keydown", function(event) {
if (m.alive && localSettings.loreCount > 0) {
if (simulation.difficultyMode > 4) {
simulation.makeTextLog("<em>testing mode disabled for this difficulty</em>");
break
// break
}
if (simulation.testing) {
simulation.testing = false;

View File

@@ -15,40 +15,31 @@ const level = {
levels: [],
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// simulation.isHorizontalFlipped = true
// m.addHealth(Infinity)
// m.setField("time dilation")
// b.giveGuns("laser")
// m.setField("molecular assembler")
// b.giveGuns("spores")
// tech.giveTech("fleas")
// tech.giveTech("flagella")
// b.guns[0].ammo = 10000
// // b.giveGuns("mine")
// tech.giveTech("lens")
// 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 < 1; ++i) tech.giveTech("mycelium manufacturing")
// for (let i = 0; i < 9; ++i) tech.giveTech("WIMPs")
// for (let i = 0; i < 100; ++i) tech.giveTech("nail-bot")
// for (let i = 0; i < 9; ++i) tech.giveTech("emergence")
// tech.giveTech("laser-bot")
// 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 < 1; ++i) tech.giveTech("necrophage")
// for (let i = 0; i < 1; i++) tech.giveTech("cryodesiccation")
// 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 < 15; i++) tech.giveTech()
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
// m.maxHealth = m.health = 100
// powerUps.research.changeRerolls(100000)
// tech.tech[297].frequency = 100
// 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)
// spawn.starter(1900, -500, 40)
// spawn.starter(1900, -500, 20)
// spawn.starter(1900, -500, 100)
// for (let i = 0; i < 20; ++i) spawn.exploder(1900, -500)
// spawn.timeSkipBoss(1900, -500)
// level.difficultyIncrease(50) //30 is near max on hard //60 is near max on why
// tech.tech[297].frequency = 100
// spawn.starter(1900, -500, 200)
// for (let i = 0; i < 10; ++i) spawn.hopBullet(1900, -500)
// spawn.hopMomBoss(1900, -500)
// spawn.grenadier(1900, -1450, 10)
// level.difficultyIncrease(8 * 4) //30 is near max on hard //60 is near max on why
// 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 < 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);
// },
// (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) => {
// const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) {
// toggle.isAddedElements = false
const button = level.button(x + 950, y + 0)
const button = level.button(x + 935, y + 0)
button.isUp = true
@@ -2310,7 +2414,7 @@ const level = {
(x = offset.x, y = offset.y) => {
// const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) {
// toggle.isAddedElements = false
const button = level.button(x + 950, y + 0)
const button = level.button(x + 935, y + 0)
button.isUp = true
//left ledges
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)];
loot = lootOptions[Math.floor(Math.random() * lootOptions.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)
//rooms
let rooms = ["exit", "loot", "enter", "empty"]
@@ -2661,7 +2765,7 @@ const level = {
document.body.style.backgroundColor = "#ddd";
spawn.mapRect(-950, 0, 8200, 800); //ground
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, -1200, 1000, 550); // shelf roof
// 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
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);
level.exit.x = 550000;
level.exit.y = -330;
spawn.mapRect(5500, -330 + 20, 100, 20); //spawn this because the real exit is in the wrong spot
level.exit.x = 0;
level.exit.y = -8000;
level.defaultZoom = 2500
simulation.zoomTransition(level.defaultZoom)
@@ -7892,6 +7996,7 @@ const level = {
spawn.bodyRect(-2100, 2050, 290, 30) //Portal platform
let b = body[body.length - 1];
b.isNotHoldable = true
cons[cons.length] = Constraint.create({
pointA: {
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: "gain <strong class='color-f'>energy</strong> when <strong>blocking</strong><br>no <strong>recoil</strong> when <strong>blocking</strong>",
effect: () => {
m.fieldMeterColor = "#48f" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
m.fieldShieldingScale = 0;
m.fieldBlockCD = 3;
m.grabPowerUpRange2 = 10000000
@@ -1724,9 +1727,8 @@ const m = {
ctx.strokeStyle = "#f0f";
ctx.stroke();
} else if (isFree) {
//when blocking draw this graphic
ctx.fillStyle = "rgba(110,170,200," + (0.2 + 0.4 * Math.random()) + ")";
ctx.lineWidth = 2;
ctx.lineWidth = 2; //when blocking draw this graphic
ctx.fillStyle = `rgba(110,150,220, ${0.2 + 0.4 * Math.random()})`
ctx.strokeStyle = "#000";
const len = mob[i].vertices.length - 1;
const mag = mob[i].radius
@@ -1739,11 +1741,11 @@ const m = {
ctx.fill();
ctx.stroke();
} else {
//when blocking draw this graphic
const eye = 15;
const eye = 15; //when blocking draw this graphic
const len = mob[i].vertices.length - 1;
ctx.fillStyle = "rgba(110,170,200," + (0.2 + 0.4 * Math.random()) + ")";
ctx.lineWidth = 1;
ctx.fillStyle = `rgba(110,150,220, ${0.2 + 0.4 * Math.random()})`
ctx.strokeStyle = "#000";
ctx.beginPath();
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
//draw field attached to player
if (m.holdingTarget) {
ctx.fillStyle = "rgba(110,170,200," + (0.06 + 0.03 * Math.random()) + ")";
ctx.strokeStyle = "rgba(110, 200, 235, " + (0.35 + 0.05 * Math.random()) + ")"
ctx.fillStyle = `rgba(110,150,220, ${0.06 + 0.03 * Math.random()})`
ctx.strokeStyle = `rgba(110,150,220, ${0.35 + 0.05 * Math.random()})`
} else {
ctx.fillStyle = "rgba(110,170,200," + (0.27 + 0.2 * Math.random() - 0.1 * wave) + ")";
ctx.strokeStyle = "rgba(110, 200, 235, " + (0.4 + 0.5 * Math.random()) + ")"
ctx.fillStyle = `rgba(110,150,220, ${0.27 + 0.2 * Math.random() - 0.1 * wave})`
ctx.strokeStyle = `rgba(110,150,220, ${0.4 + 0.5 * Math.random()})`
}
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);
@@ -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)
if (!input.field) { //&& tech.isFieldFree
//draw field free of player
ctx.fillStyle = "rgba(110,170,200," + (0.27 + 0.2 * Math.random() - 0.1 * wave) + ")";
ctx.strokeStyle = "rgba(110, 200, 235, " + (0.4 + 0.5 * Math.random()) + ")"
ctx.fillStyle = `rgba(110,150,220, ${0.27 + 0.2 * Math.random() - 0.1 * wave})`
ctx.strokeStyle = `rgba(110,180,255, ${0.4 + 0.5 * Math.random()})`
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.lineWidth = 2.5 - 1.5 * wave;
@@ -1842,7 +1844,8 @@ const m = {
m.perfectPush(true);
}
}
m.drawFieldMeter()
// m.drawFieldMeter()
m.drawFieldMeter("rgba(0,0,0,0.2)")
if (tech.isPerfectBrake) { //cap mob speed around player
const range = 200 + 140 * wave + 150 * m.energy
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",
//<strong>double</strong> your default <strong class='color-f'>energy</strong> regeneration
effect: () => {
// m.fieldMeterColor = "#0c5"
// m.eyeFillColor = m.fieldMeterColor
m.fieldMeterColor = "#ff0"
m.eyeFillColor = m.fieldMeterColor
m.hold = function() {
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.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
if (m.energy > drain) {
m.energy -= drain
@@ -2260,7 +2265,7 @@ const m = {
const damageRadius = circleRadiusScale * this.circleRadius
const dischargeRange = 150 + 1600 * tech.plasmaDischarge + 1.3 * damageRadius
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))
if (sub < damageRadius + mob[i].radius) {
// 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: 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() {
// m.fieldMeterColor = "#0fc"
// m.fieldMeterColor = "#ff0"
m.fieldMeterColor = "#3fe"
m.eyeFillColor = m.fieldMeterColor
m.fieldFireRate = 0.75
b.setFireCD();
m.fieldFx = 1.2
m.fieldJump = 1.09
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) {
this.rewindCount = 0
m.grabPowerUpRange2 = 300000
@@ -2562,6 +2599,7 @@ const m = {
m.drawHold(m.holdingTarget);
m.holding();
m.throwBlock();
m.wakeCheck();
} else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
m.grabPowerUp();
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
m.pickUp();
this.rewindCount = 0;
m.wakeCheck();
} else if (tech.isTimeStop && player.speed < 1 && m.onGround && !input.fire) {
timeStop();
this.rewindCount = 0;
} 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)
this.rewindCount = 0;
m.wakeCheck();
}
if (m.energy < m.maxEnergy) m.regenEnergy(); //extra energy regen
m.drawFieldMeter() // this calls m.regenEnergy(); also
@@ -2637,37 +2681,30 @@ const m = {
m.lookForPickUp();
if (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.energy = 0;
m.wakeCheck();
}
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
timeStop();
} else { //holding, but field button is released
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
m.wakeCheck();
m.pickUp();
@@ -2682,6 +2719,11 @@ const m = {
}
},
effect() {
if (tech.isTimeStop) {
m.fieldHarmReduction = 0.66; //33% reduction
} else {
m.fieldHarmReduction = 1;
}
this.set();
}
},
@@ -2750,7 +2792,6 @@ const m = {
} 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)
}
//not shooting (or using field) enable cloak
if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
if (m.fireCDcycle + 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>
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: () => {
m.fieldMeterColor = "#333"
m.eyeFillColor = m.fieldMeterColor
m.fieldPhase = 0;
m.fieldPosition = {
x: simulation.mouseInGame.x,
@@ -3179,7 +3223,7 @@ const m = {
m.fieldOn = false
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>
drain: 0,
effect: function() {
m.fieldMeterColor = "#bbf" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
m.duplicateChance = 0.04
m.fieldRange = 0
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
if (isCanceled) {
if (tech.isCancelTech && Math.random() < 0.96) {
if (tech.isCancelTech && Math.random() < 0.94) {
// powerUps.research.use('tech')
powerUps[type].effect();
return
@@ -396,9 +396,6 @@ const powerUps = {
}
}, 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")) {
document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}`

View File

@@ -120,6 +120,44 @@ const simulation = {
}
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: {
x: canvas.width / 2,
y: canvas.height / 2
@@ -857,6 +895,7 @@ const simulation = {
let droneCount = 0
let sporeCount = 0
let wormCount = 0
let fleaCount = 0
let deliveryCount = 0
for (let i = 0; i < bullet.length; ++i) {
if (bullet[i].isDrone) {
@@ -866,6 +905,8 @@ const simulation = {
sporeCount++
} else if (bullet[i].wormSize) {
wormCount++
} else if (bullet[i].isFlea) {
fleaCount++
}
}
@@ -920,6 +961,21 @@ const simulation = {
}
}
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) {

View File

@@ -1,7 +1,7 @@
//main object for spawning things in a level
const spawn = {
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: [
"orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
"powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
@@ -51,13 +51,13 @@ const spawn = {
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isDropPowerUp && mob[i].alive) { //&& !mob[i].isBoss
if (mob[i].isFinalBoss) {
mob[i].health = 0.66
tech.quantumEraserCount = 0;
return
} else {
tech.isQuantumEraserDuplication = true
mob[i].death()
tech.isQuantumEraserDuplication = false
}
//graphics
const color = 'rgba(255,255,255, 0.8)'
simulation.drawList.push({
@@ -81,7 +81,6 @@ const spawn = {
color: color, //"rgb(0,0,0)",
time: 120
});
tech.quantumEraserCount--
simulation.makeTextLog(`<span class='color-var'>tech</span>.quantumEraserCount <span class='color-symbol'>=</span> ${tech.quantumEraserCount}`)
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)");
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.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
me.delay = 130 + 60 * simulation.CDScale;
// Matter.Body.rotate(me, Math.random() * Math.PI);
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.onHit = function() {
this.explode(this.mass * 2);
};
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.spawnOrbitals(me, radius + 60, 1)
me.onDeath = function() {
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() {
// 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;
}
}
}
if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
this.cd = simulation.cycle + this.delay;
//spawn hopBullets after each jump
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))
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
}
this.force.x += (0.02 + 0.06 * Math.random()) * this.mass * (player.position.x > this.position.x ? 1 : -1);
this.force.y -= (0.08 + 0.08 * Math.random()) * this.mass
}
};
},
// 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)) {
mobs.spawn(x, y, 5, radius, "#000000");
let me = mob[mob.length - 1];
@@ -5118,7 +5184,7 @@ const spawn = {
let me = mob[mob.length - 1];
me.stroke = "transparent";
me.onHit = function() {
this.explode(this.mass * 20);
this.explode(this.mass);
};
Matter.Body.setDensity(me, 0.00004); //normal is 0.001
@@ -5135,7 +5201,7 @@ const spawn = {
//damage player if in range
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.damage(0.02 * simulation.dmgScale);
m.damage(0.015 * simulation.dmgScale);
}
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,

View File

@@ -256,7 +256,7 @@ const tech = {
return dmg * tech.slowFire * tech.aimDamage
},
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,
maxDuplicationEvent() {
@@ -2977,7 +2977,7 @@ const tech = {
effect() {
tech.isBrainstorm = true
tech.isBrainstormActive = false
tech.brainStormDelay = 145 - simulation.difficultyMode * 10
tech.brainStormDelay = 150 - simulation.difficultyMode * 7
},
remove() {
tech.isBrainstorm = false
@@ -3319,7 +3319,7 @@ const tech = {
{
name: "options exchange",
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,
count: 0,
frequency: 1,
@@ -5205,7 +5205,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
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",
effect() {
@@ -5225,7 +5225,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
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",
effect() {
@@ -5263,7 +5263,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
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",
effect() {
@@ -5273,26 +5273,55 @@ const tech = {
tech.isMutualism = false
}
},
// {
// name: "worm-shot",
// link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Worm' class="link">worm-shot</a>`,
// 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,
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles
// },
// requires: "shotgun, not incendiary, nail-shot, rivets, foam-shot, ice-shot, needles",
// effect() {
// tech.isWormShot = true;
// },
// remove() {
// tech.isWormShot = false;
{
name: "fleas",
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>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || tech.isSporeField) && !tech.isSporeWorm
},
requires: "spores, not worms",
effect() {
tech.isSporeFlea = true
},
remove() {
tech.isSporeFlea = 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",
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,
frequencyDefault: 3,
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() {
tech.isSporeWorm = true
},
@@ -5333,7 +5362,7 @@ const tech = {
},
{
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,
maxCount: 1,
count: 0,
@@ -5342,7 +5371,7 @@ const tech = {
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))
},
requires: "spores, worms, diplochory, drones",
requires: "spores, worms, flagella, drones",
effect() {
tech.isDronesTravel = true
},
@@ -5353,7 +5382,7 @@ const tech = {
{
name: "anti-shear topology",
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,
maxCount: 3,
count: 0,
@@ -5362,7 +5391,7 @@ const tech = {
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
},
requires: "drones, spores, missiles, foam, matter wave, neutron bomb, ice IX",
requires: "drones, spores, missiles, foam, matter wave, neutron bomb, ice IX, flea",
effect() {
tech.isBulletsLastLonger += 0.3
},
@@ -5662,14 +5691,14 @@ const tech = {
},
{
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,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
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",
effect() {
@@ -5818,7 +5847,7 @@ const tech = {
},
{
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,
maxCount: 1,
count: 0,
@@ -5828,7 +5857,7 @@ const tech = {
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple
},
requires: "harpoon, not UHMWPE, induction furnace, grappling hook",
ammoBonus: 8,
ammoBonus: 9,
effect() {
tech.isRailGun = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -6109,7 +6138,7 @@ const tech = {
},
{
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,
maxCount: 1,
count: 0,
@@ -6120,7 +6149,7 @@ const tech = {
},
requires: "laser, not free-electron",
effect() {
tech.isLaserDiode = 0.70; //100%-37%
tech.isLaserDiode = 0.66; //100%-37%
tech.laserColor = "rgb(0, 11, 255)"
tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
},
@@ -6177,7 +6206,7 @@ const tech = {
{
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 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,
maxCount: 3,
count: 0,
@@ -6196,7 +6225,7 @@ const tech = {
},
{
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,
maxCount: 3,
count: 0,
@@ -6255,7 +6284,7 @@ const tech = {
},
{
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,
maxCount: 9,
count: 0,
@@ -6384,7 +6413,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isPulseLaser && !tech.beamSplitter
return tech.haveGunCheck("laser") && tech.isPulseLaser && !tech.beamSplitter
},
requires: "laser gun, pulse, not diffraction grating",
effect() {
@@ -7090,7 +7119,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.isExtruder
return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isExtruder
},
requires: "extruder",
effect() {
@@ -7146,8 +7175,8 @@ const tech = {
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 1,
frequencyDefault: 1,
allowed() {
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()
}
},
{
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",
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",
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>`,
isFieldTech: true,
@@ -10403,6 +10453,7 @@ const tech = {
isFastTime: null,
isAnthropicTech: null,
isSporeWorm: null,
isSporeFlea: null,
isFoamShot: null,
isIceShot: null,
isBlockRestitution: null,

View File

@@ -1,32 +1,46 @@
******************************************************** NEXT PATCH **************************************************
tech: iridescence - laser does 100% damage to mobs hit near their center
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
tech: fleas - replace spores with little hoppers
virtual particles costs 4->6 research for 11% duplication
quantum eraser has less duplication chance at higher difficulty modes
community map temple updates
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
*********************************************************** TODO *****************************************************
give laser gun _____ if you fire in an angle range
draw angle range as a slowly rotation circle arc around player
effect:
bonus damage
extra beams
extra reflections
fleas
add very short (2 cycle) delay after each landing -> hop
zero velocity while on short delay? try it?
flea tech:
add a delay to flea jumping also +dmg
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?
name? polarized light, iridescence
anti-shear topology apply to grenades too? and other less useful bullets
then open up tech requirements
hopBossMom
spawns lots of small hopBullets
drops eggs, that hatch into hopBullets
like sporangium
normally runs away from player, but goes closer to drop eggs
menagerie: sporangium release a variety of things
spores, worms, hoppers, drones, iceIX?, foam?, missiles?
benefit: they release more stuff than normal
swim through slime
hold up to float while in slime?
level element: exploding barrels
@@ -34,22 +48,12 @@ improve mob invincible graphic
opacity oscillates from 100% to 0%?
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 a unique CD var for plasma ball?
wormhole tech: entropic gravity - gain defense for each research
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
mechanics
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
it's great, but maybe annoying?
maybe only with crouch?
perfect diamagnetism just replace Messier effect
time dilation drains 1/2 as much energy when paused
grow plasma torch as you hold it down
negative mass effects much more space