fleas
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:
200
js/bullet.js
200
js/bullet.js
@@ -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)
|
||||
|
||||
@@ -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> ${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;
|
||||
|
||||
169
js/level.js
169
js/level.js
@@ -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,
|
||||
|
||||
143
js/player.js
143
js/player.js
@@ -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
|
||||
|
||||
@@ -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}`
|
||||
|
||||
@@ -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) {
|
||||
|
||||
220
js/spawn.js
220
js/spawn.js
@@ -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
|
||||
});
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
},
|
||||
// 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
|
||||
// }
|
||||
} 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
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
// }
|
||||
// // 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,
|
||||
|
||||
137
js/tech.js
137
js/tech.js
@@ -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",
|
||||
{
|
||||
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.isWormShot = true;
|
||||
// },
|
||||
// remove() {
|
||||
// tech.isWormShot = false;
|
||||
// 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,
|
||||
|
||||
63
todo.txt
63
todo.txt
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user