From 05fcb823b260d1bfde8cf9d8c12b9b47b8ec8df2 Mon Sep 17 00:00:00 2001 From: landgreen Date: Tue, 16 Mar 2021 05:03:50 -0700 Subject: [PATCH] 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 --- .DS_Store | Bin 6148 -> 6148 bytes js/bullet.js | 122 +++++++------ js/level.js | 36 ++-- js/player.js | 501 +++++++++++++++++++++++++-------------------------- js/spawn.js | 2 +- js/tech.js | 355 +++++++++++++++++++----------------- style.css | 7 + todo.txt | 38 ++-- 8 files changed, 554 insertions(+), 507 deletions(-) diff --git a/.DS_Store b/.DS_Store index 6ef377dd5002e264fe0c9e0363caa740ce79f00e..7a51ec22395fc98346c0346df2360726bfcdd316 100644 GIT binary patch delta 121 zcmZoMXffEJ!W7S>w0SNA0|N_#9z!}qCPPVXzKcszPJR+ljAKsx0=C9~ha6GmQ}D_c kWEch~=jRpx^)N8aQJCD!w45n(`(zzvKgI)_tC>4R0H&BBIRF3v delta 121 zcmZoMXffEJ!W7S#q-)8*z`(+w$B@pD$xxD;@8Xh_lb-|>4R0GT!+*Z=?k diff --git a/js/bullet.js b/js/bullet.js index b4403ea..68d2462 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -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 four balls in a wide arc
balls bounce with no momentum loss", ammo: 0, @@ -3618,8 +3633,7 @@ const b = { } } } - }, - { + }, { name: "wave beam", description: "emit a sine wave of oscillating particles
propagates through walls", ammo: 0, @@ -3729,8 +3743,7 @@ const b = { const transverse = Vector.normalise(Vector.perp(bullet[me].velocity)) } } - }, - { + }, { name: "missiles", description: "launch homing missiles that explode
crouch to rapidly launch smaller missiles", ammo: 0, @@ -3846,8 +3859,7 @@ const b = { // } } - }, - { + }, { name: "grenades", description: "lob a single bouncy projectile
explodes on contact 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 proximity mine that sticks to walls
fires nails 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 sporangium that discharges spores
spores 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 crash into mobs
crashes reduce their lifespan 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 energy to launch a high-speed dense rod
hold left mouse to charge, release to fire", ammo: 0, @@ -4431,8 +4440,7 @@ const b = { } } } - }, - { + }, { name: "laser", description: "emit a beam of collimated coherent light
drains energy instead of ammunition", ammo: 0, diff --git a/js/level.js b/js/level.js index f88289d..4557df8 100644 --- a/js/level.js +++ b/js/level.js @@ -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 diff --git a/js/player.js b/js/player.js index 0821f09..6a995da 100644 --- a/js/player.js +++ b/js/player.js @@ -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 energy to tunnel through a wormhole
wormholes attract blocks and power ups
7% chance to duplicate spawned power ups", //
bullets may also traverse wormholes 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, diff --git a/js/spawn.js b/js/spawn.js index 3d6f380..a132e80 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -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) diff --git a/js/tech.js b/js/tech.js index 41782a0..50db686 100644 --- a/js/tech.js +++ b/js/tech.js @@ -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: "double the frequency of finding gun tech
spawn a gun", + name: "gun sciences", + description: "spawn a gun and double the frequency
of finding tech for a specific gun", maxCount: 1, count: 0, frequency: 1, @@ -358,14 +358,14 @@ }, { name: "catabolism", - description: "when you fire while out of ammo
gain 3 ammo, but lose 5 health", + description: "when you fire while out of ammo
gain 4 ammo, but lose 5 health", 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
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 damage by 4%
for every 10 active bullets", + 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 bullets last 30% longer
drones, spores, missiles, foam, wave, neutron", + // 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
wave beam, neutron bomb", + effect() { + tech.isBulletsLastLonger += 0.3 + }, + remove() { + tech.isBulletsLastLonger = 1; + } + }, + { + name: "radioactive contamination", + description: "after a mob or shield dies,
leftover radiation spreads 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: "explosions release gamma radiation
100% more damage, but over 4 seconds", @@ -699,6 +751,40 @@ tech.isImmuneExplosion = false; } }, + { + name: "incendiary ammunition", + description: "shotgun, super balls, and drones
are loaded with explosives", + 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 detonations and collisions eject nails
blocks, rail gun, grenades, missiles, shotgun slugs", + 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 explode when they die
be careful", @@ -716,6 +802,23 @@ tech.isExplodeMob = false; } }, + { + name: "impact shear", + description: "mobs release a nail when they die
nails target nearby mobs", + 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 spores when they die
9% chance", @@ -736,23 +839,6 @@ tech.sporesOnDeath = 0; } }, - { - name: "impact shear", - description: "mobs release a nail when they die
nails target nearby mobs", - 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 11% less health", @@ -1492,7 +1578,25 @@ remove() { tech.isFreezeHarmImmune = false; } - }, { + }, + { + name: "superfluidity", + description: "freeze 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 drones
chance to occur after receiving harm", 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: "double the frequency of finding healing tech
spawn 12 heals", 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 dying, continue in an alternate reality
reduce harm by 16%", //spawn 4 research + description: "after dying, continue in an alternate reality
reduce harm by 23%", //spawn 4 research 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 research for any purpose
has a 37% chance to spawn a research", - maxCount: 1, - count: 0, - frequency: 1, - allowed() { - return (powerUps.research.count > 2 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste - }, - requires: "not superdeterminism or Ψ(t) collapse
at least 3 research", - effect() { - tech.renormalization = true; - }, - remove() { - tech.renormalization = false; - } }, { name: "decoherence", description: "researched or canceled tech won't reoccur
spawn 5 research", @@ -2200,6 +2288,22 @@ tech.isBanish = false powerUps.tech.banishLog = [] //reset banish log } + }, { + name: "renormalization", + description: "using a research for any purpose
has a 37% chance to spawn a research", + maxCount: 1, + count: 0, + frequency: 1, + allowed() { + return (powerUps.research.count > 3 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste + }, + requires: "not superdeterminism or Ψ(t) collapse
at least 4 research", + effect() { + tech.renormalization = true; + }, + remove() { + tech.renormalization = false; + } }, { name: "perturbation theory", description: "66% decreased delay after firing
when you have no research in your inventory", @@ -2319,7 +2423,7 @@ }, { name: "meta-analysis", - description: "if you choose a junk tech you instead get a
random non-junk tech and spawn 2 research", + description: "if you choose a JUNK tech you instead get a
random normal tech and 2 research", maxCount: 1, count: 0, frequency: 2, @@ -2336,7 +2440,7 @@ }, { name: "replication", - description: "7% chance to duplicate spawned power ups
add 12 junk tech to the potential pool", + description: "7% chance to duplicate spawned power ups
add 12 JUNK tech to the potential pool", maxCount: 9, count: 0, frequency: 1, @@ -2378,14 +2482,14 @@ }, { name: "futures exchange", - description: "clicking × to cancel a field, tech, or gun
adds 4.5% power up duplication chance", + description: "clicking × to cancel a field, tech, or gun
adds 4.5% power up duplication 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 difficulty by 1 level
add 18 junk tech to the potential pool", + description: "reduce combat difficulty by 1 level
add 18 JUNK tech to the potential pool", maxCount: 1, count: 0, frequency: 1, @@ -2584,7 +2688,7 @@ } }, { - name: "field technology", + name: "vector fields", description: "double the frequency of finding field tech
spawn a field", maxCount: 1, count: 0, @@ -2646,7 +2750,7 @@ } }, { name: "determinism", - description: "spawn 5 tech
tech, fields, and guns have only 1 choice", + description: "spawn 5 tech, but you have no cancel
and 1 choice for tech, fields, and guns", maxCount: 1, count: 0, frequency: 1, @@ -2666,7 +2770,7 @@ } }, { name: "superdeterminism", - description: "spawn 7 tech
research, guns, and fields no longer spawn", + description: "spawn 5 tech
research, guns, and fields no longer spawn", maxCount: 1, count: 0, frequency: 3, @@ -2732,108 +2836,6 @@ tech.isRewindGun = false } } - }, { - name: "incendiary ammunition", - description: "shotgun, super balls, and drones
are loaded with explosives", - 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 detonations and collisions eject nails
blocks, rail gun, grenades, missiles, shotgun slugs", - 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: "freeze 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 dies,
leftover radiation spreads 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 bullets last 30% longer
drones, spores, missiles, foam, wave, neutron", - 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
wave beam, neutron bomb", - effect() { - tech.isBulletsLastLonger += 0.3 - }, - remove() { - tech.isBulletsLastLonger = 1; - } - }, { - name: "microstates", - description: "increase damage by 4%
for every 10 active bullets", - 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: "nail gun fires 3 mob piercing needles
requires 3 times more ammo", @@ -2872,7 +2874,7 @@ } } }, { - name: "ceramic needle", + name: "ceramic needles", description: `your needles pierce shields
directly damaging shielded mobs`, isGunTech: true, maxCount: 1, @@ -3600,6 +3602,31 @@ remove() { tech.isDroneGrab = false } + }, { + name: "planned obsolescence", + description: "reduce all drone production costs by 300%
reduce the average drone lifetime by 53%", + 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: "foam bubbles grow and split into 3 copies
when the mob they are stuck to dies", @@ -4845,7 +4872,7 @@ remove() {} }, { name: "defragment", - description: "set the frequency of finding junk tech to zero", + description: "set the frequency of finding JUNK tech to zero", maxCount: 1, count: 0, frequency: 0, @@ -5021,7 +5048,7 @@ remove() {} }, { name: "expert system", - description: "spawn a tech power up
add 64 junk tech to the potential pool", + description: "spawn a tech power up
add 64 JUNK tech 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 } \ No newline at end of file diff --git a/style.css b/style.css index e3550e1..88ae013 100644 --- a/style.css +++ b/style.css @@ -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; diff --git a/todo.txt b/todo.txt index 72846d0..cc2209b 100644 --- a/todo.txt +++ b/todo.txt @@ -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