planned obsolescence

bug fixes
  strong anthropic principle does 0.03599% more damage
  spores can stick to rotating blocks now
  probably fixed the new wormhole field while targeting a block -> crouch lock bug
  ceramic needles now correctly bypass shields

needles fire 3 at a time with a short delay and no spread

tech: planned obsolescence - 3x drone ammo, 1/3 drone nano-scale energy cost, but 53% reduced drone life span
This commit is contained in:
landgreen
2021-03-16 05:03:50 -07:00
parent 862a0ae9d0
commit 05fcb823b2
8 changed files with 554 additions and 507 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -35,7 +35,7 @@ const b = {
if (m.health > 0.05) {
m.damage(0.05 / m.harmReduction()); // /m.harmReduction() undoes damage increase from difficulty
if (!(tech.isRewindAvoidDeath && m.energy > 0.66)) { //don't give ammo if CPT triggered
for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "ammo");
for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x, m.pos.y, "ammo");
}
}
} else {
@@ -66,7 +66,7 @@ const b = {
if (m.health > 0.05) {
m.damage(0.05 / m.harmReduction()); // /m.harmReduction() undoes damage increase from difficulty
if (!(tech.isRewindAvoidDeath && m.energy > 0.66)) { //don't give ammo if CPT triggered
for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "ammo");
for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x, m.pos.y, "ammo");
}
}
} else {
@@ -98,7 +98,7 @@ const b = {
if (m.health > 0.05) {
m.damage(0.05 / m.harmReduction()); // /m.harmReduction() undoes damage increase from difficulty
if (!(tech.isRewindAvoidDeath && m.energy > 0.66)) { //don't give ammo if CPT triggered
for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "ammo");
for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x, m.pos.y, "ammo");
}
}
} else {
@@ -2037,7 +2037,7 @@ const b = {
restitution: 1,
dmg: 0.24, //damage done in addition to the damage from momentum
lookFrequency: 80 + Math.floor(23 * Math.random()),
endCycle: simulation.cycle + Math.floor((1100 + 420 * Math.random()) * tech.isBulletsLastLonger),
endCycle: simulation.cycle + Math.floor((1100 + 420 * Math.random()) * tech.isBulletsLastLonger * tech.droneCycleReduction),
classType: "bullet",
collisionFilter: {
category: cat.bullet,
@@ -2109,7 +2109,7 @@ const b = {
powerUp.splice(i, 1);
if (tech.isDroneGrab) {
this.isImproved = true;
const SCALE = 3
const SCALE = 2.5
Matter.Body.scale(this, SCALE, SCALE);
this.lookFrequency = 30;
this.endCycle += 2500
@@ -3214,8 +3214,6 @@ const b = {
this.baseFire(m.angle + (Math.random() - 0.5) * (Math.random() - 0.5) * (m.crouch ? 1.35 : 3.2) / CD)
},
fireNeedles() {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 33 : 16) * b.fireCD); // cool down
function makeNeedle(angle = m.angle) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(m.pos.x + 40 * Math.cos(m.angle), m.pos.y + 40 * Math.sin(m.angle), 50, 1, b.fireAttributes(angle));
@@ -3226,34 +3224,36 @@ const b = {
bullet[me].do = function() {
const whom = Matter.Query.collides(this, mob)
if (whom.length && this.speed > 20) { //if touching a mob
who = whom[whom.length - 1].bodyA
if (who && who.mob) {
let immune = false
for (let i = 0; i < this.immuneList.length; i++) {
if (this.immuneList[i] === who.id) {
immune = true
break
for (let i = 0, len = whom.length; i < len; i++) {
who = whom[i].bodyA
if (who && who.mob) {
let immune = false
for (let i = 0; i < this.immuneList.length; i++) { //check if this needle has hit this mob already
if (this.immuneList[i] === who.id) {
immune = true
break
}
}
}
if (!immune) {
if (tech.isNailCrit && !who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.975) {
b.explosion(this.position, 220 + 30 * Math.random()); //makes bullet do explosive damage at end
}
this.immuneList.push(who.id)
who.foundPlayer();
if (tech.isNailRadiation) {
mobs.statusDoT(who, tech.isFastRadiation ? 8 : 2, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles
} else {
let dmg = b.dmgScale * 3.25
if (tech.isCrit && who.isStunned) dmg *= 4
who.damage(dmg, tech.isNeedleShieldPierce);
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
radius: Math.log(2 * dmg + 1.1) * 40,
color: simulation.playerDmgColor,
time: simulation.drawTime
});
if (!immune) {
if (tech.isNailCrit && !who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.975) {
b.explosion(this.position, 220 + 30 * Math.random()); //makes bullet do explosive damage at end
}
this.immuneList.push(who.id) //remember that this needle has hit this mob once already
who.foundPlayer();
if (tech.isNailRadiation) {
mobs.statusDoT(who, tech.isFastRadiation ? 9 : 2.25, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles
} else {
let dmg = b.dmgScale * 3.5
if (tech.isCrit && who.isStunned) dmg *= 4
who.damage(dmg, tech.isNeedleShieldPierce);
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
radius: Math.log(2 * dmg + 1.1) * 40,
color: simulation.playerDmgColor,
time: simulation.drawTime
});
}
}
}
}
@@ -3277,10 +3277,26 @@ const b = {
Matter.Body.setDensity(bullet[me], 0.00001);
World.add(engine.world, bullet[me]); //add bullet to world
}
const spread = (m.crouch ? 0.013 : 0.06)
makeNeedle(m.angle + spread)
makeNeedle()
makeNeedle(m.angle - spread)
if (m.crouch) {
m.fireCDcycle = m.cycle + 50 * b.fireCD; // cool down
makeNeedle()
for (let i = 1; i < 4; i++) { //4 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 40 * i);
}
} else {
m.fireCDcycle = m.cycle + 30 * b.fireCD; // cool down
makeNeedle()
for (let i = 1; i < 3; i++) { //3 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 40 * i);
}
}
// const spread = (m.crouch ? 0.013 : 0.06)
// makeNeedle(m.angle + spread)
// makeNeedle()
// makeNeedle(m.angle - spread)
},
fireRivets() {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 30 : 25) * b.fireCD); // cool down
@@ -3553,8 +3569,7 @@ const b = {
}
}
}
},
{
}, {
name: "super balls",
description: "fire <strong>four</strong> balls in a wide arc<br>balls <strong>bounce</strong> with no momentum loss",
ammo: 0,
@@ -3618,8 +3633,7 @@ const b = {
}
}
}
},
{
}, {
name: "wave beam",
description: "emit a <strong>sine wave</strong> of oscillating particles<br>propagates through <strong>walls</strong>",
ammo: 0,
@@ -3729,8 +3743,7 @@ const b = {
const transverse = Vector.normalise(Vector.perp(bullet[me].velocity))
}
}
},
{
}, {
name: "missiles",
description: "launch <strong>homing</strong> missiles that <strong class='color-e'>explode</strong><br>crouch to <strong>rapidly</strong> launch smaller missiles",
ammo: 0,
@@ -3846,8 +3859,7 @@ const b = {
// }
}
},
{
}, {
name: "grenades",
description: "lob a single <strong>bouncy</strong> projectile<br><strong class='color-e'>explodes</strong> on <strong>contact</strong> or after one second",
ammo: 0,
@@ -3857,8 +3869,7 @@ const b = {
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 40 : 30) * b.fireCD); // cool down
b.grenade()
},
},
{
}, {
name: "mine",
description: "toss a <strong>proximity</strong> mine that <strong>sticks</strong> to walls<br>fires <strong>nails</strong> at mobs within range",
ammo: 0,
@@ -3885,8 +3896,7 @@ const b = {
}
m.fireCDcycle = m.cycle + Math.floor((m.crouch ? 50 : 25) * b.fireCD); // cool down
}
},
{
}, {
name: "spores",
description: "fire a <strong class='color-p' style='letter-spacing: 2px;'>sporangium</strong> that discharges <strong class='color-p' style='letter-spacing: 2px;'>spores</strong><br><strong class='color-p' style='letter-spacing: 2px;'>spores</strong> seek out nearby mobs",
ammo: 0,
@@ -3947,7 +3957,7 @@ const b = {
} else {
const bodyCollisions = Matter.Query.collides(this, body)
if (bodyCollisions.length) {
if (!bodyCollisions[0].bodyA.isNotHoldable) {
if (!bodyCollisions[0].bodyA.isComposite) {
onCollide(this)
this.stuckTo = bodyCollisions[0].bodyA
//find the relative position for when the mob is at angle zero by undoing the mobs rotation
@@ -4015,12 +4025,12 @@ const b = {
}
}
}
},
{
}, {
name: "drones",
description: "deploy drones that <strong>crash</strong> into mobs<br>crashes reduce their <strong>lifespan</strong> by 1 second",
ammo: 0,
ammoPack: 14,
defaultAmmoPack: 14,
have: false,
fire() {
if (m.crouch) {
@@ -4086,8 +4096,7 @@ const b = {
b.foam(position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius)
}
}
},
{
}, {
name: "rail gun",
description: "use <strong class='color-f'>energy</strong> to launch a high-speed <strong>dense</strong> rod<br><strong>hold</strong> left mouse to charge, <strong>release</strong> to fire",
ammo: 0,
@@ -4431,8 +4440,7 @@ const b = {
}
}
}
},
{
}, {
name: "laser",
description: "emit a <strong>beam</strong> of collimated coherent <strong class='color-laser'>light</strong><br>drains <strong class='color-f'>energy</strong> instead of ammunition",
ammo: 0,

View File

@@ -16,11 +16,11 @@ const level = {
// simulation.zoomScale = 1000;
// simulation.setZoom();
// m.setField("nano-scale manufacturing")
// b.giveGuns("foam")
// b.giveGuns("spores")
// tech.isExplodeRadio = true
// for (let i = 0; i < 1; i++) tech.giveTech("dynamo-bot")
// tech.giveTech("supercritical fission")
// tech.giveTech("micro-extruder")
// tech.giveTech("needle gun")
// tech.giveTech("ceramic needles")
// tech.giveTech("causality bombs")
// tech.giveTech("cardinality")
// tech.giveTech("Bayesian statistics")
@@ -424,12 +424,14 @@ const level = {
rotor(x, y, rotate = 0, radius = 800, width = 40, density = 0.0005) {
const rotor1 = Matter.Bodies.rectangle(x, y, width, radius, {
density: density,
isNotHoldable: true
isNotHoldable: true,
isComposite: true
});
const rotor2 = Matter.Bodies.rectangle(x, y, width, radius, {
angle: Math.PI / 2,
density: density,
isNotHoldable: true
isNotHoldable: true,
isComposite: true
});
rotor = Body.create({ //combine rotor1 and rotor2
parts: [rotor1, rotor2],
@@ -1100,8 +1102,8 @@ const level = {
// simulation.difficulty = 30
// spawn.starter(1900, -500, 200) //big boy
spawn.pulsar(1900, -500)
spawn.pulsarBoss(1900, -500)
// spawn.pulsar(1900, -500)
// spawn.pulsarBoss(1900, -500)
// spawn.historyBoss(1900, -500)
// spawn.ghoster(2900, -500)
// spawn.launcherBoss(1200, -500)
@@ -1113,7 +1115,7 @@ const level = {
// spawn.streamBoss(1600, -500)
// spawn.orbitalBoss(1600, -500)
// spawn.cellBossCulture(1600, -500)
// spawn.shieldingBoss(1600, -500)
spawn.shieldingBoss(1600, -500)
// spawn.beamer(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1);
@@ -4956,13 +4958,13 @@ const level = {
document.body.style.backgroundColor = "#dcdcde";
//Level
level.setPosToSpawn(200, 50);
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 8950;
level.exit.y = 200;
level.exit.y = 170;
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
//Map
spawn.mapRect(150, 90, 100, 100);
spawn.mapRect(8950, 190, 100, 100);
spawn.mapRect(-100, -400, 100, 600);
spawn.mapRect(-100, 100, 700, 100);
spawn.mapRect(500, 100, 100, 1700);
@@ -5006,7 +5008,7 @@ const level = {
spawn.mapRect(8000, 1500, 300, 100);
spawn.mapRect(7120, -100, 300, 100);
spawn.mapRect(7000, 1500, 300, 100);
spawn.mapRect(6500, 1000, 300, 2100);
spawn.mapRect(6500, 1000, 300, 1200);
spawn.mapRect(5800, 1100, 300, 100);
spawn.mapRect(5900, 1700, 300, 100);
spawn.mapRect(5300, 1400, 300, 100);
@@ -5063,11 +5065,11 @@ const level = {
spawn.randomMob(8650, -200, 0.9); //end guards
//Boss Spawning
spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]);
spawn.shieldingBoss(7200, 500);
if (simulation.difficulty > 20) {
spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]);
//Boss Spawning
if (simulation.difficulty > 3) {
spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]);
if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500);
if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]);
}
//Blocks

View File

@@ -392,7 +392,7 @@ const m = {
simulation.makeGunHUD(); //update gun HUD
simulation.updateTechHUD();
simulation.isTextLogOpen = true;
if (m.holdingTarget) m.drop();
m.drop();
if (simulation.paused) build.pauseGrid() //update the build when paused
},
death() {
@@ -498,7 +498,7 @@ const m = {
harmReduction() {
let dmg = 1
dmg *= m.fieldHarmReduction
if (tech.isImmortal) dmg *= 0.84
if (tech.isImmortal) dmg *= 0.79
if (tech.isHarmReduceAfterKill) dmg *= (m.lastKillCycle + 300 > m.cycle) ? 0.25 : 1.25
if (tech.healthDrain) dmg *= 1 + 2.667 * tech.healthDrain //tech.healthDrain = 0.03 at one stack //cause more damage
if (tech.squirrelFx !== 1) dmg *= 1 + (tech.squirrelFx - 1) / 5 //cause more damage
@@ -631,7 +631,7 @@ const m = {
}
m.lastHarmCycle = m.cycle
if (tech.isDroneOnDamage) { //chance to build a drone on damage from tech
const len = Math.min((dmg - 0.06 * Math.random()) * 40, 40)
const len = Math.min((dmg - 0.06 * Math.random()) * 40, 40) / tech.droneEnergyReduction
for (let i = 0; i < len; i++) {
if (Math.random() < 0.5) b.drone() //spawn drone
}
@@ -1002,11 +1002,11 @@ const m = {
m.isHolding = false;
m.throwCharge = 0;
m.definePlayerMass()
if (m.holdingTarget) {
m.holdingTarget.collisionFilter.category = cat.body;
m.holdingTarget.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
m.holdingTarget = null;
}
}
if (m.holdingTarget) {
m.holdingTarget.collisionFilter.category = cat.body;
m.holdingTarget.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
m.holdingTarget = null;
}
},
definePlayerMass(mass = m.defaultMass) {
@@ -1376,7 +1376,7 @@ const m = {
if (tech.isFreezeMobs) {
for (let i = 0, len = mob.length; i < len; ++i) {
Matter.Sleeping.set(mob[i], false)
mobs.statusSlow(mob[i], 90)
mobs.statusSlow(mob[i], 60)
}
} else {
wake(mob);
@@ -1566,7 +1566,7 @@ const m = {
m.energy -= 0.057;
b.iceIX(1)
} else {
m.energy -= 0.45;
m.energy -= 0.45 * tech.droneEnergyReduction;
b.drone(1)
}
}
@@ -2297,15 +2297,246 @@ const m = {
name: "wormhole",
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong class='color-worm'>wormholes</strong> attract blocks and power ups<br><strong>7%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong>", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
effect: function() {
m.drop();
m.duplicateChance = 0.07
simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw
// if (tech.isRewindGun) {
// m.hold = this.rewind
// } else {
m.hold = this.teleport
// }
m.hold = function() {
// m.hole = { //this is reset with each new field, but I'm leaving it here for reference
// isOn: false,
// isReady: true,
// pos1: {x: 0,y: 0},
// pos2: {x: 0,y: 0},
// angle: 0,
// unit:{x:0,y:0},
// }
if (m.hole.isOn) {
// draw holes
m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025))
const semiMajorAxis = m.fieldRange + 30
const edge1a = Vector.add(Vector.mult(m.hole.unit, semiMajorAxis), m.hole.pos1)
const edge1b = Vector.add(Vector.mult(m.hole.unit, -semiMajorAxis), m.hole.pos1)
const edge2a = Vector.add(Vector.mult(m.hole.unit, semiMajorAxis), m.hole.pos2)
const edge2b = Vector.add(Vector.mult(m.hole.unit, -semiMajorAxis), m.hole.pos2)
ctx.beginPath();
ctx.moveTo(edge1a.x, edge1a.y)
ctx.bezierCurveTo(m.hole.pos1.x, m.hole.pos1.y, m.hole.pos2.x, m.hole.pos2.y, edge2a.x, edge2a.y);
ctx.lineTo(edge2b.x, edge2b.y)
ctx.bezierCurveTo(m.hole.pos2.x, m.hole.pos2.y, m.hole.pos1.x, m.hole.pos1.y, edge1b.x, edge1b.y);
ctx.fillStyle = `rgba(255,255,255,${200 / m.fieldRange / m.fieldRange})` //"rgba(0,0,0,0.1)"
ctx.fill();
ctx.beginPath();
ctx.ellipse(m.hole.pos1.x, m.hole.pos1.y, m.fieldRange, semiMajorAxis, m.hole.angle, 0, 2 * Math.PI)
ctx.ellipse(m.hole.pos2.x, m.hole.pos2.y, m.fieldRange, semiMajorAxis, m.hole.angle, 0, 2 * Math.PI)
ctx.fillStyle = `rgba(255,255,255,${32 / m.fieldRange})`
ctx.fill();
//suck power ups
for (let i = 0, len = powerUp.length; i < len; ++i) {
//which hole is closer
const dxP1 = m.hole.pos1.x - powerUp[i].position.x;
const dyP1 = m.hole.pos1.y - powerUp[i].position.y;
const dxP2 = m.hole.pos2.x - powerUp[i].position.x;
const dyP2 = m.hole.pos2.y - powerUp[i].position.y;
let dxP, dyP, dist2
if (dxP1 * dxP1 + dyP1 * dyP1 < dxP2 * dxP2 + dyP2 * dyP2) {
dxP = dxP1
dyP = dyP1
} else {
dxP = dxP2
dyP = dyP2
}
dist2 = dxP * dxP + dyP * dyP;
if (dist2 < 600000 && !(m.health === m.maxHealth && powerUp[i].name === "heal")) {
powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
Matter.Body.setVelocity(powerUp[i], { //extra friction
x: powerUp[i].velocity.x * 0.05,
y: powerUp[i].velocity.y * 0.05
});
if (dist2 < 1000 && !simulation.isChoosing) { //use power up if it is close enough
m.fieldRange *= 0.8
powerUps.onPickUp(powerUp[i]);
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break; //because the array order is messed up after splice
}
}
}
//suck and shrink blocks
const suckRange = 500
const shrinkRange = 100
const shrinkScale = 0.97;
const slowScale = 0.9
for (let i = 0, len = body.length; i < len; i++) {
if (!body[i].isNotHoldable) {
const dist1 = Vector.magnitude(Vector.sub(m.hole.pos1, body[i].position))
const dist2 = Vector.magnitude(Vector.sub(m.hole.pos2, body[i].position))
if (dist1 < dist2) {
if (dist1 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos1, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(m.hole.pos1, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
m.fieldRange *= 0.8
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(m.hole.pos2, Vector.rotate({
x: m.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -15));
}
}
break
}
}
}
} else if (dist2 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos2, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(m.hole.pos2, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
m.fieldRange *= 0.8
// if (tech.isWormholeEnergy && m.energy < m.maxEnergy * 2) m.energy = m.maxEnergy * 2
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(m.hole.pos1, Vector.rotate({
x: m.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 15));
}
}
break
}
}
}
}
}
if (tech.isWormBullets) {
//teleport bullets
for (let i = 0, len = bullet.length; i < len; ++i) { //teleport bullets from hole1 to hole2
if (!bullet[i].botType && !bullet[i].isInHole) { //don't teleport bots
if (Vector.magnitude(Vector.sub(m.hole.pos1, bullet[i].position)) < m.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(m.hole.pos2, Vector.sub(m.hole.pos1, bullet[i].position)));
m.fieldRange += 5
bullet[i].isInHole = true
} else if (Vector.magnitude(Vector.sub(m.hole.pos2, bullet[i].position)) < m.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(m.hole.pos1, Vector.sub(m.hole.pos2, bullet[i].position)));
m.fieldRange += 5
bullet[i].isInHole = true
}
}
}
// mobs get pushed away
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(m.hole.pos1, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos1, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
if (Vector.magnitude(Vector.sub(m.hole.pos2, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos2, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
}
}
}
if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
const justPastMouse = Vector.add(Vector.mult(Vector.normalise(Vector.sub(simulation.mouseInGame, m.pos)), 50), simulation.mouseInGame)
const scale = 60
// console.log(Matter.Query.region(map, bounds))
if (m.hole.isReady &&
(
Matter.Query.region(map, {
min: {
x: simulation.mouseInGame.x - scale,
y: simulation.mouseInGame.y - scale
},
max: {
x: simulation.mouseInGame.x + scale,
y: simulation.mouseInGame.y + scale
}
}).length === 0 &&
Matter.Query.ray(map, m.pos, justPastMouse).length === 0
// Matter.Query.ray(map, m.pos, simulation.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, simulation.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, justPastMouse).length === 0
)
) {
const sub = Vector.sub(simulation.mouseInGame, m.pos)
const mag = Vector.magnitude(sub)
const drain = 0.03 + 0.005 * Math.sqrt(mag)
if (m.energy > drain && mag > 300) {
m.energy -= drain
m.hole.isReady = false;
m.fieldRange = 0
Matter.Body.setPosition(player, simulation.mouseInGame);
m.buttonCD_jump = 0 //this might fix a bug with jumping
const velocity = Vector.mult(Vector.normalise(sub), 18)
Matter.Body.setVelocity(player, {
x: velocity.x,
y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
});
if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
// move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
}
//set holes
m.hole.isOn = true;
m.hole.pos1.x = m.pos.x
m.hole.pos1.y = m.pos.y
m.hole.pos2.x = player.position.x
m.hole.pos2.y = player.position.y
m.hole.angle = Math.atan2(sub.y, sub.x)
m.hole.unit = Vector.perp(Vector.normalise(sub))
if (tech.isWormholeDamage) {
who = Matter.Query.ray(mob, m.pos, simulation.mouseInGame, 100)
for (let i = 0; i < who.length; i++) {
if (who[i].body.alive) {
mobs.statusDoT(who[i].body, 1, 420)
mobs.statusStun(who[i].body, 360)
}
}
}
} else {
m.grabPowerUp();
}
} else {
m.grabPowerUp();
}
// } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
// m.pickUp();
} else {
m.hole.isReady = true;
}
m.drawFieldMeter()
}
},
rewindCount: 0,
// rewind: function() {
@@ -2392,244 +2623,6 @@ const m = {
// }
// m.drawFieldMeter()
// },
teleport: function() {
// m.hole = { //this is reset with each new field, but I'm leaving it here for reference
// isOn: false,
// isReady: true,
// pos1: {x: 0,y: 0},
// pos2: {x: 0,y: 0},
// angle: 0,
// unit:{x:0,y:0},
// }
if (m.hole.isOn) {
// draw holes
m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025))
const semiMajorAxis = m.fieldRange + 30
const edge1a = Vector.add(Vector.mult(m.hole.unit, semiMajorAxis), m.hole.pos1)
const edge1b = Vector.add(Vector.mult(m.hole.unit, -semiMajorAxis), m.hole.pos1)
const edge2a = Vector.add(Vector.mult(m.hole.unit, semiMajorAxis), m.hole.pos2)
const edge2b = Vector.add(Vector.mult(m.hole.unit, -semiMajorAxis), m.hole.pos2)
ctx.beginPath();
ctx.moveTo(edge1a.x, edge1a.y)
ctx.bezierCurveTo(m.hole.pos1.x, m.hole.pos1.y, m.hole.pos2.x, m.hole.pos2.y, edge2a.x, edge2a.y);
ctx.lineTo(edge2b.x, edge2b.y)
ctx.bezierCurveTo(m.hole.pos2.x, m.hole.pos2.y, m.hole.pos1.x, m.hole.pos1.y, edge1b.x, edge1b.y);
ctx.fillStyle = `rgba(255,255,255,${200 / m.fieldRange / m.fieldRange})` //"rgba(0,0,0,0.1)"
ctx.fill();
ctx.beginPath();
ctx.ellipse(m.hole.pos1.x, m.hole.pos1.y, m.fieldRange, semiMajorAxis, m.hole.angle, 0, 2 * Math.PI)
ctx.ellipse(m.hole.pos2.x, m.hole.pos2.y, m.fieldRange, semiMajorAxis, m.hole.angle, 0, 2 * Math.PI)
ctx.fillStyle = `rgba(255,255,255,${32 / m.fieldRange})`
ctx.fill();
//suck power ups
for (let i = 0, len = powerUp.length; i < len; ++i) {
//which hole is closer
const dxP1 = m.hole.pos1.x - powerUp[i].position.x;
const dyP1 = m.hole.pos1.y - powerUp[i].position.y;
const dxP2 = m.hole.pos2.x - powerUp[i].position.x;
const dyP2 = m.hole.pos2.y - powerUp[i].position.y;
let dxP, dyP, dist2
if (dxP1 * dxP1 + dyP1 * dyP1 < dxP2 * dxP2 + dyP2 * dyP2) {
dxP = dxP1
dyP = dyP1
} else {
dxP = dxP2
dyP = dyP2
}
dist2 = dxP * dxP + dyP * dyP;
if (dist2 < 600000 && !(m.health === m.maxHealth && powerUp[i].name === "heal")) {
powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
Matter.Body.setVelocity(powerUp[i], { //extra friction
x: powerUp[i].velocity.x * 0.05,
y: powerUp[i].velocity.y * 0.05
});
if (dist2 < 1000 && !simulation.isChoosing) { //use power up if it is close enough
m.fieldRange *= 0.8
powerUps.onPickUp(powerUp[i]);
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break; //because the array order is messed up after splice
}
}
}
//suck and shrink blocks
const suckRange = 500
const shrinkRange = 100
const shrinkScale = 0.97;
const slowScale = 0.9
for (let i = 0, len = body.length; i < len; i++) {
if (!body[i].isNotHoldable) {
const dist1 = Vector.magnitude(Vector.sub(m.hole.pos1, body[i].position))
const dist2 = Vector.magnitude(Vector.sub(m.hole.pos2, body[i].position))
if (dist1 < dist2) {
if (dist1 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos1, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(m.hole.pos1, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
m.fieldRange *= 0.8
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(m.hole.pos2, Vector.rotate({
x: m.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -15));
}
}
break
}
}
}
} else if (dist2 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos2, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(m.hole.pos2, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
m.fieldRange *= 0.8
// if (tech.isWormholeEnergy && m.energy < m.maxEnergy * 2) m.energy = m.maxEnergy * 2
if (tech.isWormholeEnergy) m.energy += 0.63
if (tech.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(m.hole.pos1, Vector.rotate({
x: m.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 15));
}
}
break
}
}
}
}
}
if (tech.isWormBullets) {
//teleport bullets
for (let i = 0, len = bullet.length; i < len; ++i) { //teleport bullets from hole1 to hole2
if (!bullet[i].botType && !bullet[i].isInHole) { //don't teleport bots
if (Vector.magnitude(Vector.sub(m.hole.pos1, bullet[i].position)) < m.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(m.hole.pos2, Vector.sub(m.hole.pos1, bullet[i].position)));
m.fieldRange += 5
bullet[i].isInHole = true
} else if (Vector.magnitude(Vector.sub(m.hole.pos2, bullet[i].position)) < m.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(m.hole.pos1, Vector.sub(m.hole.pos2, bullet[i].position)));
m.fieldRange += 5
bullet[i].isInHole = true
}
}
}
// mobs get pushed away
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(m.hole.pos1, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos1, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
if (Vector.magnitude(Vector.sub(m.hole.pos2, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos2, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
}
}
}
if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
const justPastMouse = Vector.add(Vector.mult(Vector.normalise(Vector.sub(simulation.mouseInGame, m.pos)), 50), simulation.mouseInGame)
const scale = 60
// console.log(Matter.Query.region(map, bounds))
if (m.hole.isReady &&
(
Matter.Query.region(map, {
min: {
x: simulation.mouseInGame.x - scale,
y: simulation.mouseInGame.y - scale
},
max: {
x: simulation.mouseInGame.x + scale,
y: simulation.mouseInGame.y + scale
}
}).length === 0 &&
Matter.Query.ray(map, m.pos, justPastMouse).length === 0
// Matter.Query.ray(map, m.pos, simulation.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, simulation.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, justPastMouse).length === 0
)
) {
const sub = Vector.sub(simulation.mouseInGame, m.pos)
const mag = Vector.magnitude(sub)
const drain = 0.03 + 0.005 * Math.sqrt(mag)
if (m.energy > drain && mag > 300) {
m.energy -= drain
m.hole.isReady = false;
m.fieldRange = 0
Matter.Body.setPosition(player, simulation.mouseInGame);
m.buttonCD_jump = 0 //this might fix a bug with jumping
const velocity = Vector.mult(Vector.normalise(sub), 18)
Matter.Body.setVelocity(player, {
x: velocity.x,
y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
});
if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
// move bots to player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
}
//set holes
m.hole.isOn = true;
m.hole.pos1.x = m.pos.x
m.hole.pos1.y = m.pos.y
m.hole.pos2.x = player.position.x
m.hole.pos2.y = player.position.y
m.hole.angle = Math.atan2(sub.y, sub.x)
m.hole.unit = Vector.perp(Vector.normalise(sub))
if (tech.isWormholeDamage) {
who = Matter.Query.ray(mob, m.pos, simulation.mouseInGame, 100)
for (let i = 0; i < who.length; i++) {
if (who[i].body.alive) {
mobs.statusDoT(who[i].body, 1, 420)
mobs.statusStun(who[i].body, 360)
}
}
}
} else {
m.grabPowerUp();
}
} else {
m.grabPowerUp();
}
} else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
m.pickUp();
} else {
m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
m.hole.isReady = true;
}
m.drawFieldMeter()
},
},
],
isShipMode: false,

View File

@@ -2566,7 +2566,7 @@ const spawn = {
this.cycle = 0
ctx.beginPath();
for (let i = 0; i < mob.length; i++) {
if (!mob[i].isShielded && !mob[i].shield && mob[i].dropPowerUp) {
if (!mob[i].isShielded && !mob[i].shield && mob[i].dropPowerUp && mob[i].alive) {
ctx.moveTo(this.position.x, this.position.y)
ctx.lineTo(mob[i].position.x, mob[i].position.y)

View File

@@ -124,7 +124,7 @@
damageFromTech() {
let dmg = m.fieldDamage
if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555
if (tech.isAnthropicDamage && tech.isDeathAvoidedThisLevel) dmg *= 2.37
if (tech.isAnthropicDamage && tech.isDeathAvoidedThisLevel) dmg *= 2.3703599
if (tech.isDamageAfterKill) dmg *= (m.lastKillCycle + 300 > m.cycle) ? 1.5 : 0.5
if (tech.isTechDamage) dmg *= 2
if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
@@ -270,8 +270,8 @@
}
},
{
name: "gun technology",
description: "</strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-g'>gun</strong> <strong class='color-m'>tech</strong><br>spawn a <strong class='color-g'>gun</strong>",
name: "gun sciences",
description: "spawn a <strong class='color-g'>gun</strong> and </strong>double</strong> the <strong class='flicker'>frequency</strong><br>of finding <strong class='color-m'>tech</strong> for a specific <strong class='color-g'>gun</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -358,14 +358,14 @@
},
{
name: "catabolism",
description: "when you <strong>fire</strong> while <strong>out</strong> of <strong class='color-g'>ammo</strong><br>gain <strong>3</strong> <strong class='color-g'>ammo</strong>, but lose <strong>5</strong> <strong class='color-h'>health</strong>",
description: "when you <strong>fire</strong> while <strong>out</strong> of <strong class='color-g'>ammo</strong><br>gain <strong>4</strong> <strong class='color-g'>ammo</strong>, but lose <strong>5</strong> <strong class='color-h'>health</strong>",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return !tech.isEnergyHealth && !tech.isEnergyNoAmmo
return m.harmReduction() < 1 && !tech.isEnergyHealth && !tech.isEnergyNoAmmo
},
requires: "not mass-energy equivalence<br>not exciton-lattice",
requires: "some harm reduction, not mass-energy equivalence, exciton-lattice",
effect: () => {
tech.isAmmoFromHealth = true;
},
@@ -613,6 +613,58 @@
b.setFireCD();
}
},
{
name: "microstates",
description: "increase <strong class='color-d'>damage</strong> by <strong>4%</strong><br>for every <strong>10</strong> active <strong>bullets</strong>",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.isBulletsLastLonger > 1
},
requires: "anti-shear topology",
effect() {
tech.isDamageFromBulletCount = true
},
remove() {
tech.isDamageFromBulletCount = false
}
},
{
name: "anti-shear topology",
description: "some <strong>bullets</strong> last <strong>30% longer</strong><br><em style = 'font-size: 83%'>drones, spores, missiles, foam, wave, neutron</em>",
// isGunTech: true,
maxCount: 3,
count: 0,
frequency: 1,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("wave beam") || tech.isNeutronBomb
},
requires: "drones, spores, missiles, foam<br>wave beam, neutron bomb",
effect() {
tech.isBulletsLastLonger += 0.3
},
remove() {
tech.isBulletsLastLonger = 1;
}
},
{
name: "radioactive contamination",
description: "after a mob or shield <strong>dies</strong>,<br> leftover <strong class='color-p'>radiation</strong> <strong>spreads</strong> to a nearby mob",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio
},
requires: "radiation damage source",
effect() {
tech.isRadioactive = true
},
remove() {
tech.isRadioactive = false
}
},
{
name: "iridium-192",
description: "<strong class='color-e'>explosions</strong> release <strong class='color-p'>gamma radiation</strong><br><strong>100%</strong> more <strong class='color-d'>damage</strong>, but over 4 seconds",
@@ -699,6 +751,40 @@
tech.isImmuneExplosion = false;
}
},
{
name: "incendiary ammunition",
description: "<strong>shotgun</strong>, <strong>super balls</strong>, and <strong>drones</strong><br>are loaded with <strong class='color-e'>explosives</strong>",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)) || tech.haveGunCheck("drones") || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot
},
requires: "drones, super balls, shotgun",
effect() {
tech.isIncendiary = true
},
remove() {
tech.isIncendiary = false;
}
},
{
name: "fragmentation",
description: "some <strong class='color-e'>detonations</strong> and collisions eject <strong>nails</strong><br><em style = 'font-size: 90%'>blocks, rail gun, grenades, missiles, shotgun slugs</em>",
maxCount: 9,
count: 0,
frequency: 1,
allowed() {
return (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || tech.haveGunCheck("rail gun") || (tech.haveGunCheck("shotgun") && tech.isSlugShot) || tech.throwChargeRate > 1
},
requires: "grenades, missiles, rail gun, shotgun slugs, or mass driver",
effect() {
tech.fragments++
},
remove() {
tech.fragments = 0
}
},
{
name: "thermal runaway",
description: "mobs <strong class='color-e'>explode</strong> when they <strong>die</strong><br><em>be careful</em>",
@@ -716,6 +802,23 @@
tech.isExplodeMob = false;
}
},
{
name: "impact shear",
description: "mobs release a <strong>nail</strong> when they <strong>die</strong><br><em>nails target nearby mobs</em>",
maxCount: 9,
count: 0,
frequency: 1,
allowed() {
return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.isBotSpawner
},
requires: "no other mob death tech",
effect: () => {
tech.nailsDeathMob++
},
remove() {
tech.nailsDeathMob = 0;
}
},
{
name: "zoospore vector",
description: "mobs produce <strong class='color-p' style='letter-spacing: 2px;'>spores</strong> when they <strong>die</strong><br><strong>9%</strong> chance",
@@ -736,23 +839,6 @@
tech.sporesOnDeath = 0;
}
},
{
name: "impact shear",
description: "mobs release a <strong>nail</strong> when they <strong>die</strong><br><em>nails target nearby mobs</em>",
maxCount: 9,
count: 0,
frequency: 1,
allowed() {
return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.isBotSpawner
},
requires: "no other mob death tech",
effect: () => {
tech.nailsDeathMob++
},
remove() {
tech.nailsDeathMob = 0;
}
},
{
name: "reaction inhibitor",
description: "mobs spawn with <strong>11%</strong> less <strong>health</strong>",
@@ -1492,7 +1578,25 @@
remove() {
tech.isFreezeHarmImmune = false;
}
}, {
},
{
name: "superfluidity",
description: "<strong class='color-s'>freeze</strong> effects are applied to a small area",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField
},
requires: "a localized freeze effect",
effect() {
tech.isAoESlow = true
},
remove() {
tech.isAoESlow = false
}
},
{
name: "ablative drones",
description: "rebuild your broken parts as <strong>drones</strong><br>chance to occur after receiving <strong class='color-harm'>harm</strong>",
maxCount: 1,
@@ -2025,7 +2129,7 @@
frequency: 1,
isHealTech: true,
allowed() {
return (m.health < 0.75 || build.isExperimentSelection) && !tech.isEnergyHealth
return ((m.health / m.maxHealth) < 0.7 || build.isExperimentSelection) && !tech.isEnergyHealth
},
requires: "not mass-energy equivalence",
effect() {
@@ -2036,14 +2140,14 @@
}
},
{
name: "healing technology",
name: "maintenance",
description: "</strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-h'>healing</strong> <strong class='color-m'>tech</strong><br>spawn <strong>12</strong> <strong class='color-h'>heals</strong>",
maxCount: 1,
count: 0,
frequency: 1,
isNonRefundable: true,
allowed() {
return true
return ((m.health / m.maxHealth) < 0.7 || build.isExperimentSelection)
},
requires: "",
effect() {
@@ -2118,14 +2222,14 @@
}
}, {
name: "quantum immortality",
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>16%</strong>", //spawn <strong>4</strong> <strong class='color-r'>research</strong>
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>23%</strong>", //spawn <strong>4</strong> <strong class='color-r'>research</strong>
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return !tech.isSwitchReality && !tech.isResearchReality
return !tech.isSwitchReality && !tech.isResearchReality && tech.isDeathAvoid
},
requires: "not many-worlds, perturbation theory",
requires: "anthropic principle, not many-worlds, perturbation theory",
effect() {
tech.isImmortal = true;
// for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + Math.random() * 10, m.pos.y + Math.random() * 10, "research", false);
@@ -2156,9 +2260,9 @@
count: 0,
frequency: 1,
allowed() {
return !tech.isImmortal && !tech.isSwitchReality && (powerUps.research.count > 2 || build.isExperimentSelection)
return !tech.isImmortal && !tech.isSwitchReality
},
requires: "at least 2 research, not quantum immortality, many-worlds",
requires: "not quantum immortality, many-worlds",
effect() {
tech.isResearchReality = true;
for (let i = 0; i < 11; i++) powerUps.spawn(m.pos.x + Math.random() * 10, m.pos.y + Math.random() * 10, "research", false);
@@ -2166,22 +2270,6 @@
remove() {
tech.isResearchReality = false;
}
}, {
name: "renormalization",
description: "using a <strong class='color-r'>research</strong> for <strong>any</strong> purpose<br>has a <strong>37%</strong> chance to spawn a <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return (powerUps.research.count > 2 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste
},
requires: "not superdeterminism or Ψ(t) collapse<br>at least 3 research",
effect() {
tech.renormalization = true;
},
remove() {
tech.renormalization = false;
}
}, {
name: "decoherence",
description: "<strong class='color-r'>researched</strong> or <strong>canceled</strong> <strong class='color-m'>tech</strong> won't <strong>reoccur</strong> <br>spawn <strong>5</strong> <strong class='color-r'>research</strong>",
@@ -2200,6 +2288,22 @@
tech.isBanish = false
powerUps.tech.banishLog = [] //reset banish log
}
}, {
name: "renormalization",
description: "using a <strong class='color-r'>research</strong> for <strong>any</strong> purpose<br>has a <strong>37%</strong> chance to spawn a <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return (powerUps.research.count > 3 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste
},
requires: "not superdeterminism or Ψ(t) collapse<br>at least 4 research",
effect() {
tech.renormalization = true;
},
remove() {
tech.renormalization = false;
}
}, {
name: "perturbation theory",
description: "<strong>66%</strong> decreased <strong><em>delay</em></strong> after firing<br>when you have no <strong class='color-r'>research</strong> in your inventory",
@@ -2319,7 +2423,7 @@
},
{
name: "meta-analysis",
description: "if you choose a <strong>junk</strong> <strong class='color-m'>tech</strong> you instead get a <br>random non-junk <strong class='color-m'>tech</strong> and spawn <strong>2</strong> <strong class='color-r'>research</strong>",
description: "if you choose a <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> you instead get a <br>random normal <strong class='color-m'>tech</strong> and <strong>2</strong> <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2336,7 +2440,7 @@
},
{
name: "replication",
description: "<strong>7%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>add <strong>12</strong> junk <strong class='color-m'>tech</strong> to the potential pool",
description: "<strong>7%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>add <strong>12</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
maxCount: 9,
count: 0,
frequency: 1,
@@ -2378,14 +2482,14 @@
},
{
name: "futures exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>4.5%</strong> power up <strong class='color-dup'>duplication</strong> chance",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to <strong>cancel</strong> a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>4.5%</strong> power up <strong class='color-dup'>duplication</strong> chance",
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.duplicationChance() < 1 && !tech.isDeterminism && (level.levelsCleared < 5 || Math.random() < 0.5)
return tech.duplicationChance() < 1 && !tech.isDeterminism && level.levelsCleared < 5
},
requires: "below 100% duplication chance, not determinism",
requires: "below 100% duplication chance, below level 5, not determinism",
effect() {
tech.isCancelDuplication = true
tech.cancelCount = 0
@@ -2546,7 +2650,7 @@
}
}, {
name: "dark patterns",
description: "reduce combat <strong>difficulty</strong> by <strong>1 level</strong><br>add <strong>18</strong> junk <strong class='color-m'>tech</strong> to the potential pool",
description: "reduce combat <strong>difficulty</strong> by <strong>1 level</strong><br>add <strong>18</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2584,7 +2688,7 @@
}
},
{
name: "field technology",
name: "vector fields",
description: "</strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-f'>field</strong> <strong class='color-m'>tech</strong><br>spawn a <strong class='color-f'>field</strong>",
maxCount: 1,
count: 0,
@@ -2646,7 +2750,7 @@
}
}, {
name: "determinism",
description: "spawn <strong>5</strong> <strong class='color-m'>tech</strong><br><strong class='color-m'>tech</strong>, <strong class='color-f'>fields</strong>, and <strong class='color-g'>guns</strong> have only <strong>1 choice</strong>",
description: "spawn <strong>5</strong> <strong class='color-m'>tech</strong>, but you have <strong>no cancel</strong><br>and <strong>1 choice</strong> for <strong class='color-m'>tech</strong>, <strong class='color-f'>fields</strong>, and <strong class='color-g'>guns</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2666,7 +2770,7 @@
}
}, {
name: "superdeterminism",
description: "spawn <strong>7</strong> <strong class='color-m'>tech</strong><br><strong class='color-r'>research</strong>, <strong class='color-g'>guns</strong>, and <strong class='color-f'>fields</strong> no longer <strong>spawn</strong>",
description: "spawn <strong>5</strong> <strong class='color-m'>tech</strong><br><strong class='color-r'>research</strong>, <strong class='color-g'>guns</strong>, and <strong class='color-f'>fields</strong> no longer <strong>spawn</strong>",
maxCount: 1,
count: 0,
frequency: 3,
@@ -2732,108 +2836,6 @@
tech.isRewindGun = false
}
}
}, {
name: "incendiary ammunition",
description: "<strong>shotgun</strong>, <strong>super balls</strong>, and <strong>drones</strong><br>are loaded with <strong class='color-e'>explosives</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)) || tech.haveGunCheck("drones") || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot
},
requires: "drones, super balls, shotgun",
effect() {
tech.isIncendiary = true
},
remove() {
tech.isIncendiary = false;
}
}, {
name: "fragmentation",
description: "some <strong class='color-e'>detonations</strong> and collisions eject <strong>nails</strong><br><em style = 'font-size: 90%'>blocks, rail gun, grenades, missiles, shotgun slugs</em>",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 1,
allowed() {
return (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || tech.haveGunCheck("rail gun") || (tech.haveGunCheck("shotgun") && tech.isSlugShot) || tech.throwChargeRate > 1
},
requires: "grenades, missiles, rail gun, shotgun slugs, or mass driver",
effect() {
tech.fragments++
},
remove() {
tech.fragments = 0
}
}, {
name: "superfluidity",
description: "<strong class='color-s'>freeze</strong> effects are applied to a small area",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.isIceCrystals || tech.isSporeFreeze || tech.isIceField
},
requires: "a freeze effect",
effect() {
tech.isAoESlow = true
},
remove() {
tech.isAoESlow = false
}
}, {
name: "radioactive contamination",
description: "after a mob or shield <strong>dies</strong>,<br> leftover <strong class='color-p'>radiation</strong> <strong>spreads</strong> to a nearby mob",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio
},
requires: "radiation damage source",
effect() {
tech.isRadioactive = true
},
remove() {
tech.isRadioactive = false
}
}, {
name: "anti-shear topology",
description: "some <strong>bullets</strong> last <strong>30% longer</strong><br><em style = 'font-size: 83%'>drones, spores, missiles, foam, wave, neutron</em>",
isGunTech: true,
maxCount: 3,
count: 0,
frequency: 1,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" || tech.haveGunCheck("spores") || tech.haveGunCheck("drones") || tech.haveGunCheck("missiles") || tech.haveGunCheck("foam") || tech.haveGunCheck("wave beam") || tech.isNeutronBomb
},
requires: "drones, spores, missiles, foam<br>wave beam, neutron bomb",
effect() {
tech.isBulletsLastLonger += 0.3
},
remove() {
tech.isBulletsLastLonger = 1;
}
}, {
name: "microstates",
description: "increase <strong class='color-d'>damage</strong> by <strong>4%</strong><br>for every <strong>10</strong> active <strong>bullets</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
allowed() {
return tech.isBulletsLastLonger > 1
},
requires: "anti-shear topology",
effect() {
tech.isDamageFromBulletCount = true
},
remove() {
tech.isDamageFromBulletCount = false
}
}, {
name: "needle gun",
description: "<strong>nail gun</strong> fires <strong>3</strong> mob piercing <strong>needles</strong><br>requires <strong>3</strong> times more <strong class='color-g'>ammo</strong>",
@@ -2872,7 +2874,7 @@
}
}
}, {
name: "ceramic needle",
name: "ceramic needles",
description: `your <strong>needles</strong> pierce <strong>shields</strong><br>directly <strong class='color-d'>damaging</strong> shielded mobs`,
isGunTech: true,
maxCount: 1,
@@ -3600,6 +3602,31 @@
remove() {
tech.isDroneGrab = false
}
}, {
name: "planned obsolescence",
description: "reduce all <strong>drone</strong> production costs by <strong>300%</strong><br>reduce the average <strong>drone</strong> lifetime by <strong>53%</strong>",
isGunTech: true,
maxCount: 3,
count: 0,
frequency: 1,
allowed() {
return tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField))
},
requires: "drones",
effect() {
tech.droneCycleReduction = Math.pow(0.47, this.count)
tech.droneEnergyReduction = Math.pow(0.33, this.count)
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * Math.pow(3, this.count)
}
},
remove() {
tech.droneCycleReduction = 1
tech.droneEnergyReduction = 1
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
}
}
}, {
name: "necrophoresis",
description: "<strong>foam</strong> bubbles grow and split into 3 <strong>copies</strong><br> when the mob they are stuck to <strong>dies</strong>",
@@ -4845,7 +4872,7 @@
remove() {}
}, {
name: "defragment",
description: "set the <strong class='flicker'>frequency</strong> of finding junk <strong class='color-m'>tech</strong> to zero",
description: "set the <strong class='flicker'>frequency</strong> of finding <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to zero",
maxCount: 1,
count: 0,
frequency: 0,
@@ -5021,7 +5048,7 @@
remove() {}
}, {
name: "expert system",
description: "spawn a <strong class='color-m'>tech</strong> power up<br>add <strong>64</strong> junk <strong class='color-m'>tech</strong> to the potential pool",
description: "spawn a <strong class='color-m'>tech</strong> power up<br>add <strong>64</strong> <strong class='color-j'>JUNK</strong> <strong class='color-m'>tech</strong> to the potential pool",
maxCount: 9,
count: 0,
frequency: 0,
@@ -5795,5 +5822,7 @@
isFlipFlopDamage: null,
isFlipFlopEnergy: null,
isMetaAnalysis: null,
isFoamAttract: null
isFoamAttract: null,
droneCycleReduction: null,
droneEnergyReduction: null
}

View File

@@ -604,6 +604,13 @@ summary {
font-weight: 100;
}
.color-j {
letter-spacing: 1px;
/* font-weight: 100; */
font-family: Lucida Console, Courier, monospace;
/* transform: rotate(-90deg); */
}
/* .color-rewind {
background-image: linear-gradient(to left, #fff, #bbb);
border-radius: 5px;

View File

@@ -1,16 +1,19 @@
******************************************************** NEXT PATCH ********************************************************
tech: electrostatic induction - foam bullets are attracted to nearby mobs
bug fixes
strong anthropic principle does 0.03599% more damage
spores can stick to rotating blocks now
probably fixed the new wormhole field while targeting a block -> crouch lock bug
ceramic needles now correctly bypass shields
portals on perplex map, now remove blocks that fall in
new community map! coliseum by iNoobBoi
needles fire 3 at a time with a short delay and no spread
a few more tech can be refunded properly
nonRefundable tech don't show up in the list of tech you have
tech: planned obsolescence - 3x drone ammo, 1/3 drone nano-scale energy cost, but 53% reduced drone life span
******************************************************** BUGS ********************************************************
fix issue where you have to press z once to get copy to work for simulation.enableConstructMode()
you have to press z once to get copy to work for simulation.enableConstructMode() sometimes
not sure how to reproduce, but it happens often on the first draw
mouse event e.which is deprecated
@@ -22,9 +25,6 @@ fix door.isOpen actually meaning isClosed?
wasn't able to understand bug after extensive testing
had tech: complex spin statistics
(a few times) wormhole teleportation can leave the player in a stuck jump state
seems to be easily fixed, by porting, firing or something
(always) make it so that when you are immune to harm you can either jump on mobs or you pass through them
(always) is there a way to check if the player is stuck inside the map or block
@@ -41,6 +41,20 @@ fix door.isOpen actually meaning isClosed?
******************************************************** TODO ********************************************************
mob vision: look at player history
build a new type of attraction for mobs
if mobs can't see player, they check to see if they can see where the player was in the history
if mobs can't see player, they could check to see if they can find player in the past
https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
tech: chitin - take 50% less damage, reduce harm reduction by 5% after each collision
Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
maybe it could be immune to damage? but it is spawned by an actual mob
wormhole, or CPT tech: after taking damage teleport in direction of mouse
after collision
mob sniper: draw aim graphics before fire
tech laser: photon - laser, but it can only move 100 pixels a cycle
@@ -153,12 +167,6 @@ tech pilot wave: antigravity - blocks have no gravity for a few seconds after ex
maybe they bounce too?
maybe they explode?
mob vision: look at player history
build a new type of attraction for mobs
if mobs can't see player, they check to see if they can see where the player was in the history
if mobs can't see player, they could check to see if they can find player in the past
https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
wormhole - make it clear when the wormhole can and can't teleport to a location before the player clicks
flavor - your bullets destroy blocks