From 88f891250b8ea14edab302a5e54adde0165047ed Mon Sep 17 00:00:00 2001 From: landgreen Date: Sun, 14 Aug 2022 19:43:01 -0700 Subject: [PATCH] coupling tech: coupling - +1 coupling, coupling is a new stat that provides different buffs for each field releasing this early for feedback about balance and bugs removed tech Pauli exclusion now the perfect diamagnatism coupling effect snakeBoss tails are closer together some bosses have a higher vision memory and response time phonon gets 10% less ammo and 10% less damage meta-analysis gives 2 research per use energy drain rework in many situations drain no longer scales with regen this might have some bad side effects, let me know bug fixes made several tech effects not an arrow function timeSkip graphical glitches might be improved --- js/bullet.js | 26 +++-- js/engine.js | 8 +- js/index.js | 21 +++- js/level.js | 31 +++--- js/mob.js | 9 +- js/player.js | 205 ++++++++++++++++++++++++------------- js/powerup.js | 9 +- js/spawn.js | 169 +++++++++++++++---------------- js/tech.js | 276 ++++++++++++++++++++++++-------------------------- todo.txt | 48 ++++++--- 10 files changed, 450 insertions(+), 352 deletions(-) diff --git a/js/bullet.js b/js/bullet.js index 2f4f2f6..25f36a7 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -280,10 +280,15 @@ const b = { }, fireCDscale: 1, setFireCD() { - b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage * m.fieldFireRate + b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage + if (m.fieldMode === 0) { + b.fireCDscale *= 0.8 ** (m.coupling) + } else if (m.fieldMode === 6) { + b.fireCDscale *= 0.75 * 0.8 ** (m.coupling) + } if (tech.isFastTime) b.fireCDscale *= 0.5 - if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.8, b.inventory.length) - if (tech.isFireMoveLock) b.fireCDscale *= 0.5 + if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, b.inventory.length) + if (tech.isFireMoveLock) b.fireCDscale *= 0.55 }, fireAttributes(dir, rotate = true) { if (rotate) { @@ -4876,7 +4881,7 @@ const b = { const DIST = Vector.magnitude(sub); const unit = Vector.normalise(sub) if (DIST < tech.isPlasmaRange * 450 && m.energy > this.drainThreshold) { - m.energy -= 0.00035 + m.fieldRegen //0.004; //normal plasma field is 0.00008 + m.fieldRegen = 0.00108 + m.energy -= 0.00135 //0.004; //normal plasma field is 0.00008 + m.fieldRegen = 0.00108 // if (m.energy < 0) { // m.fieldCDcycle = m.cycle + 120; // m.energy = 0; @@ -5866,7 +5871,7 @@ const b = { ctx.lineWidth = 2 * tech.wavePacketDamage ctx.beginPath(); const end = 700 * Math.sqrt(tech.isBulletsLastLonger) / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1060 - const damage = 2 * m.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage * (tech.isBulletTeleport ? 1.43 : 1) //damage is lower for large radius mobs, since they feel the waves longer + const damage = 1.8 * m.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage * (tech.isBulletTeleport ? 1.43 : 1) //damage is lower for large radius mobs, since they feel the waves longer for (let i = this.waves.length - 1; i > -1; i--) { //draw wave @@ -5959,7 +5964,7 @@ const b = { ctx.lineWidth = 2 * tech.wavePacketDamage ctx.beginPath(); const end = 1100 * tech.isBulletsLastLonger / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1767 - const damage = 2 * m.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage * (tech.isBulletTeleport ? 1.43 : 1) //damage is lower for large radius mobs, since they feel the waves longer + const damage = 1.8 * m.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage * (tech.isBulletTeleport ? 1.43 : 1) //damage is lower for large radius mobs, since they feel the waves longer for (let i = this.waves.length - 1; i > -1; i--) { const v1 = Vector.add(this.waves[i].position, Vector.mult(this.waves[i].unit1, this.waves[i].radius)) @@ -7024,7 +7029,6 @@ const b = { this.fire = () => { const drain = 0.01 * (tech.isCapacitor ? 10 : 1) / b.fireCDscale if (m.energy > drain) { - // m.energy -= m.fieldRegen if (this.charge < 50 * m.maxEnergy) { m.energy -= drain this.charge += drain * 100 @@ -7106,7 +7110,7 @@ const b = { // b.photon({ x: m.pos.x + 23 * Math.cos(m.angle), y: m.pos.y + 23 * Math.sin(m.angle) }, m.angle) // }, fireLaser() { - const drain = m.fieldRegen + tech.laserDrain / b.fireCDscale + const drain = 0.001 + tech.laserDrain / b.fireCDscale if (m.energy < drain) { m.fireCDcycle = m.cycle + 100; // cool down if out of energy } else { @@ -7124,7 +7128,7 @@ const b = { }, firePulse() {}, fireSplit() { - const drain = m.fieldRegen + tech.laserDrain / b.fireCDscale + const drain = 0.001 + tech.laserDrain / b.fireCDscale if (m.energy < drain) { m.fireCDcycle = m.cycle + 100; // cool down if out of energy } else { @@ -7149,7 +7153,7 @@ const b = { } }, fireWideBeam() { - const drain = m.fieldRegen + tech.laserDrain / b.fireCDscale + const drain = 0.001 + tech.laserDrain / b.fireCDscale if (m.energy < drain) { m.fireCDcycle = m.cycle + 100; // cool down if out of energy } else { @@ -7214,7 +7218,7 @@ const b = { } }, fireHistory() { - drain = m.fieldRegen + tech.laserDrain / b.fireCDscale + drain = 0.001 + tech.laserDrain / b.fireCDscale if (m.energy < drain) { m.fireCDcycle = m.cycle + 100; // cool down if out of energy } else { diff --git a/js/engine.js b/js/engine.js index 5767467..399ce79 100644 --- a/js/engine.js +++ b/js/engine.js @@ -42,7 +42,7 @@ function playerOnGroundCheck(event) { //falling damage if (tech.isFallingDamage && m.immuneCycle < m.cycle && momentum > 150) { m.damage(Math.min(Math.sqrt(momentum - 133) * 0.01, 0.25)); - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles } } else { m.yOffGoal = m.yOffWhen.stand; @@ -148,7 +148,7 @@ function collisionChecks(event) { if (tech.isPiezo) m.energy += 20.48; if (tech.isStimulatedEmission) powerUps.ejectTech() if (mob[k].onHit) mob[k].onHit(); - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles //extra kick between player and mob //this section would be better with forces but they don't work... let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); Matter.Body.setVelocity(player, { @@ -162,7 +162,7 @@ function collisionChecks(event) { if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy && mob[k].damageReduction > 0) { m.energy -= 0.33 * Math.max(m.maxEnergy, m.energy) //0.33 * m.energy - if (m.immuneCycle === m.cycle + tech.collisionImmuneCycles) m.immuneCycle = 0; //player doesn't go immune to collision damage + if (m.immuneCycle === m.cycle + m.collisionImmuneCycles) m.immuneCycle = 0; //player doesn't go immune to collision damage mob[k].death(); simulation.drawList.push({ //add dmg to draw queue x: pairs[i].activeContacts[0].vertex.x, @@ -224,7 +224,7 @@ function collisionChecks(event) { } } - let dmg = tech.blockDamage * m.dmgScale * v * obj.mass * (tech.isMobBlockFling ? 2.5 : 1) * (tech.isBlockRestitution ? 2.5 : 1); + let dmg = tech.blockDamage * m.dmgScale * v * obj.mass * (tech.isMobBlockFling ? 2.5 : 1) * (tech.isBlockRestitution ? 2.5 : 1) * ((m.fieldMode === 0 || m.fieldMode === 8) ? 1 + 0.4 * m.coupling : 1); if (mob[k].isShielded) dmg *= 0.7 mob[k].damage(dmg, true); diff --git a/js/index.js b/js/index.js index 3eae6ad..a77ed0b 100644 --- a/js/index.js +++ b/js/index.js @@ -226,6 +226,17 @@ for (let i = 0, len = tech.tech.length; i < len; i++) { } const build = { pauseGrid() { + + //used for junk estimation + let junkCount = 0 + let totalCount = 0 + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isBanished) { + totalCount += tech.tech[i].frequency + if (tech.tech[i].isJunk) junkCount += tech.tech[i].frequency + } + } + // ${m.coupling> 0 ? '
'+m.couplingDescription(): ""} //left side let botText = "" if (tech.nailBotCount) botText += `
nail-bots: ${tech.nailBotCount}` @@ -248,13 +259,14 @@ const build = {
fire rate: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
duplication: ${(tech.duplicationChance()*100).toFixed(0)}%
coupling: ${(m.coupling).toFixed(2)} -${m.coupling> 0 ? '
'+m.couplingDescription(): ""} + ${botText}

health: (${(m.health*100).toFixed(0)} / ${(m.maxHealth*100).toFixed(0)}) -
energy: (${(m.energy*100).toFixed(0)} / ${(m.maxEnergy*100).toFixed(0)}) +
energy: (${(m.energy*100).toFixed(0)} / ${(m.maxEnergy*100).toFixed(0)}) +(${(m.fieldRegen*6000).toFixed(0)}/s)
gun: ${b.activeGun === null || b.activeGun === undefined ? "undefined":b.guns[b.activeGun].name}   ammo: ${b.activeGun === null || b.activeGun === undefined ? "0":b.guns[b.activeGun].ammo} -
tech: ${tech.totalCount}   research: ${powerUps.research.count} +
tech: ${tech.totalCount}   research: ${powerUps.research.count} +
JUNK: ${(junkCount / totalCount * 100).toFixed(1)}%

seed: ${Math.initialSeed}
level: ${level.levels[level.onLevel]} (${level.difficultyText()})   ${m.cycle} cycles @@ -972,7 +984,7 @@ window.addEventListener("keydown", function(event) { if (m.alive && localSettings.loreCount > 0) { if (simulation.difficultyMode > 4) { simulation.makeTextLog("testing mode disabled for this difficulty"); - // break + break } if (simulation.testing) { simulation.testing = false; @@ -1281,6 +1293,7 @@ if (localSettings.isAllowed && !localSettings.isEmpty) { } document.getElementById("fps-select").value = localSettings.fpsCapDefault + if (!localSettings.banList) localSettings.banList = "" if (localSettings.banList.length === 0 || localSettings.banList === "undefined") { localSettings.banList = "" localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage diff --git a/js/level.js b/js/level.js index c2f9a30..19db768 100644 --- a/js/level.js +++ b/js/level.js @@ -16,19 +16,19 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.enableConstructMode() //used to build maps in testing mode - // level.difficultyIncrease(5 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(1 * 4) //30 is near max on hard //60 is near max on why // simulation.isHorizontalFlipped = true // m.maxHealth = m.health = 100 // tech.isRerollDamage = true // powerUps.research.changeRerolls(100000) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 - // m.setField("time dilation") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass - // b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser + m.setField("time dilation") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass + // b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.guns[0].ammo = 1000000 - // tech.giveTech("sentry"); - // tech.giveTech("MACHO"); - // tech.giveTech("elephant's toothpaste") + // tech.giveTech("coupling"); + // tech.giveTech("time crystals"); + tech.giveTech("retrocausality") // for (let i = 0; i < 1; ++i) tech.giveTech("slow light") // for (let i = 0; i < 1; ++i) tech.giveTech("free-electron laser") // m.damage(0.1); @@ -37,7 +37,8 @@ const level = { // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research"); // spawn.starter(1900, -500, 200) - // spawn.snakeSpitBoss(1900, -400) + // spawn.beetleBoss(1900, -400) + // spawn.timeBoss(1900, -400) // for (let i = 0; i < 15; ++i) spawn.starter(1900 + 300 * Math.random(), -500 + 300 * Math.random()) // level.testing(); // for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); @@ -1134,10 +1135,10 @@ const level = { player.isInPortal = this.portalPair //teleport if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles Matter.Body.setPosition(player, this.portalPair.portal.position); } else { //if at some odd angle - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles Matter.Body.setPosition(player, this.portalPair.position); } //rotate velocity @@ -1325,7 +1326,7 @@ const level = { //collision with player if (this.height > 0 && Matter.Query.region([player], this).length && !(m.isCloak)) { if (m.immuneCycle < m.cycle) { - m.immuneCycle = m.cycle + tech.collisionImmuneCycles; + m.immuneCycle = m.cycle + m.collisionImmuneCycles; m.damage(damage) simulation.drawList.push({ //add dmg to draw queue x: player.position.x, @@ -1357,7 +1358,7 @@ const level = { if (this.height > 0 && Matter.Query.region([player], this).length) { if (m.immuneCycle < m.cycle) { - const DRAIN = 0.0022 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen + const DRAIN = 0.0032 * (tech.isRadioactiveResistance ? 0.25 : 1) if (m.energy > DRAIN) { m.energy -= DRAIN // m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1) * 0.03) //still take 2% damage while you have energy @@ -10253,7 +10254,7 @@ const level = { me.onDeath = function() { //damage player if in range if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) { - m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage + m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage m.damage(0.02 * simulation.dmgScale); } simulation.drawList.push({ //add dmg to draw queue @@ -10616,7 +10617,7 @@ const level = { // Trolled const hasCPT = tech.isRewindAvoidDeath; tech.isRewindAvoidDeath = false; - const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen; + const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + 0.001; if (m.energy > DRAIN && !tech.isEnergyHealth) { m.energy -= DRAIN; } @@ -10698,7 +10699,7 @@ const level = { if (this.isHeal) { m.energy += 0.005; } else { - m.energy = Math.max(m.energy - 0.007 - m.fieldRegen, 0); + m.energy = Math.max(m.energy - 0.006, 0); if (m.energy <= 0.01 && m.immuneCycle < m.cycle) m.damage(0.002); } }, @@ -11640,7 +11641,7 @@ const level = { // me.onDeath = function() { // //damage player if in range // if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) { - // m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage + // m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage // m.damage(0.02 * simulation.dmgScale); // } // simulation.drawList.push({ //add dmg to draw queue diff --git a/js/mob.js b/js/mob.js index aa51a78..ff0348b 100644 --- a/js/mob.js +++ b/js/mob.js @@ -235,7 +235,10 @@ const mobs = { // }) // } // }, - + mobSpawnWithHealth: 1, + setMobSpawnHealth() { + mobs.mobSpawnWithHealth = 0.87 ** (tech.mobSpawnWithHealth) //+ (m.fieldMode === 0 || m.fieldMode === 7) * m.coupling + }, //********************************************************************************************** //********************************************************************************************** spawn(xPos, yPos, sides, radius, color) { @@ -256,7 +259,7 @@ const mobs = { onHit: undefined, alive: true, index: i, - health: tech.mobSpawnWithHealth, + health: mobs.mobSpawnWithHealth, showHealthBar: true, accelMag: 0.001 * simulation.accelScale, cd: 0, //game cycle when cooldown will be over @@ -602,7 +605,7 @@ const mobs = { const hitPlayer = Matter.Query.ray([player], this.position, Vector.add(this.position, Vector.mult(perp, radius * 2.05)), minorRadius) if (hitPlayer.length && m.immuneCycle < m.cycle) { m.damage(dmg * simulation.dmgScale); - // m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage + // m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage } }, searchSpring() { diff --git a/js/player.js b/js/player.js index cd8ce46..6b3f1fa 100644 --- a/js/player.js +++ b/js/player.js @@ -56,12 +56,20 @@ const m = { light: 100, }, setFillColors() { - this.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)` - this.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 25}%)` + m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)` + m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 25}%)` let grd = ctx.createLinearGradient(-30, 0, 30, 0); grd.addColorStop(0, m.fillColorDark); grd.addColorStop(1, m.fillColor); - this.bodyGradient = grd + m.bodyGradient = grd + }, + setFillColorsAlpha(alpha = 0.5) { + m.fillColor = `hsla(${m.color.hue},${m.color.sat}%,${m.color.light}%,${alpha})` + m.fillColorDark = `hsla(${m.color.hue},${m.color.sat}%,${m.color.light - 25}%,${alpha})` + let grd = ctx.createLinearGradient(-30, 0, 30, 0); + grd.addColorStop(0, m.fillColorDark); + grd.addColorStop(1, m.fillColor); + m.bodyGradient = grd }, height: 42, yOffWhen: { @@ -498,7 +506,7 @@ const m = { }, baseHealth: 1, setMaxHealth() { - m.maxHealth = m.baseHealth + tech.extraMaxHealth + tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth + m.maxHealth = m.baseHealth + tech.extraMaxHealth + tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth + (m.fieldMode === 0 || m.fieldMode === 5) * 0.5 * m.coupling document.getElementById("health-bg").style.width = `${Math.floor(300 * m.maxHealth)}px` simulation.makeTextLog(`m.maxHealth = ${m.maxHealth.toFixed(2)}`) if (m.health > m.maxHealth) m.health = m.maxHealth; @@ -532,6 +540,7 @@ const m = { if (tech.isEntanglement && b.inventory[0] === b.activeGun) { for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.87 // 1 - 0.15 } + if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.75 ** m.coupling return dmg }, rewind(steps) { // m.rewind(Math.floor(Math.min(599, 137 * m.energy))) @@ -599,7 +608,7 @@ const m = { } } m.energy = Math.max(m.energy - steps / 150, 0.01) - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles let isDrawPlayer = true const shortPause = function() { @@ -647,6 +656,7 @@ const m = { } } }, + collisionImmuneCycles: 30, damage(dmg) { if (tech.isRewindAvoidDeath && m.energy > 0.6 && dmg > 0.01) { const steps = Math.floor(Math.min(299, 150 * m.energy)) @@ -845,7 +855,7 @@ const m = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -873,7 +883,7 @@ const m = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -902,7 +912,6 @@ const m = { // these values are set on reset by setHoldDefaults() fieldFx: 1, fieldJump: 1, - fieldFireRate: 1, blockingRecoil: 4, grabPowerUpRange2: 0, isFieldActive: false, @@ -935,7 +944,7 @@ const m = { fieldArc: 0, fieldThreshold: 0, calculateFieldThreshold() { - m.fieldThreshold = Math.cos(m.fieldArc * Math.PI) + m.fieldThreshold = Math.cos((m.fieldArc) * Math.PI) }, setHoldDefaults() { if (tech.isFreeWormHole && m.fieldUpgrades[m.fieldMode].name !== "wormhole") { @@ -947,7 +956,6 @@ const m = { if (removed) powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); } if (m.energy < m.maxEnergy) m.energy = m.maxEnergy; - // m.fieldRegen = 0.001 m.fieldMeterColor = "#0cf" m.eyeFillColor = m.fieldMeterColor m.fieldShieldingScale = 1; @@ -956,7 +964,6 @@ const m = { m.lastHit = 0 m.isSneakAttack = false m.duplicateChance = 0 - powerUps.setDupChance(); m.grabPowerUpRange2 = 156000; m.blockingRecoil = 4; m.fieldRange = 155; @@ -965,10 +972,9 @@ const m = { m.isCloak = false; player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield m.airSpeedLimit = 125 - m.fieldFireRate = 1 - b.setFireCD(); m.fieldFx = 1 m.fieldJump = 1 + m.setFieldRegen(); m.setMovement(); m.drop(); m.holdingMassScale = 0.5; @@ -976,7 +982,7 @@ const m = { m.calculateFieldThreshold(); //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) m.isBodiesAsleep = true; m.wakeCheck(); - m.setMaxEnergy(); + m.couplingChange() m.hole = { isOn: false, isReady: false, @@ -991,12 +997,12 @@ const m = { } }, setMaxEnergy() { - m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 0.6 * (m.fieldUpgrades[m.fieldMode].name === "standing wave") + m.maxEnergy = (m.fieldMode === 0 || m.fieldMode === 1) * 0.4 * m.coupling + (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 0.6 * (m.fieldUpgrades[m.fieldMode].name === "standing wave") // if (tech.isEnergyHealth) m.maxEnergy *= Math.sqrt(m.harmReduction()) simulation.makeTextLog(`m.maxEnergy = ${(m.maxEnergy.toFixed(2))}`) }, fieldMeterColor: "#0cf", - drawFieldMeter(bgColor = "rgba(0, 0, 0, 0.4)", range = 60) { + drawRegenEnergy(bgColor = "rgba(0, 0, 0, 0.4)", range = 60) { if (m.energy < m.maxEnergy) { m.regenEnergy(); ctx.fillStyle = bgColor; @@ -1014,8 +1020,8 @@ const m = { ctx.fillRect(xOff, yOff, range * m.energy, 10); } }, - drawFieldMeterCloaking: function() { - if (m.energy < m.maxEnergy) { // replaces m.drawFieldMeter() with custom code + drawRegenEnergyCloaking: function() { + if (m.energy < m.maxEnergy) { // replaces m.drawRegenEnergy() with custom code m.regenEnergy(); const xOff = m.pos.x - m.radius * m.maxEnergy const yOff = m.pos.y - 50 @@ -1030,7 +1036,22 @@ const m = { ctx.stroke(); } }, - regenEnergy: function() { //used in drawFieldMeter // rewritten by some tech + setFieldRegen() { + if (m.fieldMode === 6) { + m.fieldRegen = 0.003 //18 energy per second + } else if (m.fieldMode === 4) { + m.fieldRegen = 0.002 //12 energy per second + } else { + m.fieldRegen = 0.001 //6 energy per second + } + if (m.fieldMode === 0 || m.fieldMode === 4) m.fieldRegen += 0.001 * m.coupling + if (tech.isTimeCrystals) { + m.fieldRegen *= 3 + } else if (tech.isGroundState) { + m.fieldRegen *= 0.5 + } + }, + regenEnergy: function() { //used in drawRegenEnergy // rewritten by some tech if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 }, @@ -1428,7 +1449,6 @@ const m = { } }, lookForPickUp() { //find body to pickup - if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen; const grabbing = { targetIndex: null, targetRange: 150, @@ -1521,27 +1541,61 @@ const m = { couplingDescription() { switch (m.fieldMode) { case 0: //field emitter - return `gain the effects of all fields` + return `gain the effects of all other fields` case 1: //standing wave - return `+20 max energy per coupling` + return `+40 max energy per coupling` case 2: //perfect diamagnetism - return `+10° arc per coupling` + return `invulnerable +3 seconds post collision per coupling` case 3: //negative mass - return `+25% defense per coupling` + return `+20% defense per coupling` case 4: //assembler - return `generate 4 energy per second per coupling` + return `generate 6 energy per second per coupling` case 5: //plasma - return `+13% damage per coupling` + return `+50 max health per coupling` case 6: //time dilation return `+20% fire rate per coupling` //movement, jumping, and case 7: //cloaking - return `remove +10% mob durability per coupling` + return `+15% damage per coupling` case 8: //pilot wave - return `________ per coupling` + return `+40% block collision damage per coupling` case 9: //wormhole return `+5% duplication per coupling` } }, + couplingChange() { + m.setMaxEnergy(); + m.setMaxHealth(); + m.setFieldRegen() + mobs.setMobSpawnHealth(); + powerUps.setDupChance(); + b.setFireCD(); + m.collisionImmuneCycles = 30 + m.coupling * 180 + // switch (m.fieldMode) { + // case 0: //field emitter + // // m.fieldFireRate = 0.8 ** (m.coupling) + // // b.setFireCD(); + // break + // // case 1: //standing wave + // // break + // // case 2: //perfect diamagnetism + // // break + // // case 3: //negative mass + // // break + // // case 4: //assembler + // // break + // // case 5: //plasma + // // break + // case 6: //time dilation + // // m.fieldFireRate = 0.75 * 0.8 ** (m.coupling) + // break + // // case 7: //cloaking + // // break + // // case 8: //pilot wave + // // break + // // case 9: //wormhole + // // break + // } + }, setField(index) { if (isNaN(index)) { //find index by name let found = false @@ -1572,6 +1626,7 @@ const m = { m.holding(); m.throwBlock(); } else if ((input.field && m.fieldCDcycle < m.cycle)) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); if (m.energy > 0.05) { @@ -1583,7 +1638,7 @@ const m = { } else { m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - m.drawFieldMeter() + m.drawRegenEnergy() } } }, @@ -1667,6 +1722,7 @@ const m = { m.holding(); m.throwBlock(); } else if ((input.field) && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released @@ -1686,7 +1742,7 @@ const m = { } m.harmonicShield() } - m.drawFieldMeter() + m.drawRegenEnergy() } } }, @@ -1835,6 +1891,7 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); m.fieldPosition = { x: m.pos.x, y: m.pos.y } @@ -1883,8 +1940,8 @@ const m = { m.perfectPush(true); } } - // m.drawFieldMeter() - m.drawFieldMeter("rgba(0,0,0,0.2)") + // m.drawRegenEnergy() + m.drawRegenEnergy("rgba(0,0,0,0.2)") if (tech.isPerfectBrake) { //cap mob speed around player const range = 200 + 140 * wave + 150 * m.energy for (let i = 0; i < mob.length; i++) { @@ -1925,6 +1982,7 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field && m.fieldCDcycle < m.cycle) { //push away + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); const DRAIN = 0.00035 @@ -2035,14 +2093,15 @@ const m = { // } // } // } - //draw zero-G range - ctx.beginPath(); - ctx.arc(m.pos.x, m.pos.y, this.fieldDrawRadius, 0, 2 * Math.PI); - ctx.fillStyle = "#f5f5ff"; - ctx.globalCompositeOperation = "difference"; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; + if (!simulation.isTimeSkipping) { + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, this.fieldDrawRadius, 0, 2 * Math.PI); + ctx.fillStyle = "#f5f5ff"; + ctx.globalCompositeOperation = "difference"; + ctx.fill(); + ctx.globalCompositeOperation = "source-over"; + } } } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released m.pickUp(); @@ -2051,7 +2110,7 @@ const m = { m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) this.fieldDrawRadius = 0 } - m.drawFieldMeter("rgba(0,0,0,0.2)") + m.drawRegenEnergy("rgba(0,0,0,0.2)") } } }, @@ -2136,6 +2195,7 @@ const m = { m.holding(); m.throwBlock(); } else if ((input.field && m.fieldCDcycle < m.cycle)) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); if (m.energy > 0.05) { @@ -2147,8 +2207,7 @@ const m = { } else { m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - m.regenEnergy() - m.drawFieldMeter() + m.drawRegenEnergy() } } }, @@ -2177,7 +2236,7 @@ const m = { // } else { // m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) // } - // m.drawFieldMeter("rgba(0, 0, 0, 0.2)") + // m.drawRegenEnergy("rgba(0, 0, 0, 0.2)") // if (tech.isExtruder) { // if (input.field) { @@ -2434,6 +2493,7 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); @@ -2514,7 +2574,7 @@ const m = { m.plasmaBall.fire() } } - m.drawFieldMeter("rgba(0, 0, 0, 0.2)") + m.drawRegenEnergy("rgba(0, 0, 0, 0.2)") m.plasmaBall.do() } } else if (tech.isExtruder) { @@ -2525,6 +2585,7 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); b.extruder(); @@ -2533,7 +2594,7 @@ const m = { } else { m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - m.drawFieldMeter("rgba(0, 0, 0, 0.2)") + m.drawRegenEnergy("rgba(0, 0, 0, 0.2)") if (input.field) { b.wasExtruderOn = true } else { @@ -2565,6 +2626,7 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); b.plasma(); @@ -2573,7 +2635,7 @@ const m = { } else { m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - m.drawFieldMeter("rgba(0, 0, 0, 0.2)") + m.drawRegenEnergy("rgba(0, 0, 0, 0.2)") } } }, @@ -2592,9 +2654,6 @@ const m = { // m.fieldMeterColor = "#ff0" m.fieldMeterColor = "#3fe" m.eyeFillColor = m.fieldMeterColor - - m.fieldFireRate = 0.75 - b.setFireCD(); m.fieldFx = 1.2 m.fieldJump = 1.09 m.setMovement(); @@ -2654,6 +2713,9 @@ const m = { m.throwBlock(); m.wakeCheck(); } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed + const drain = 0.002 + if (m.energy > drain) m.energy -= drain + m.grabPowerUp(); if (this.rewindCount === 0) m.lookForPickUp(); @@ -2716,13 +2778,11 @@ const m = { this.rewindCount = 0; m.wakeCheck(); } - if (m.energy < m.maxEnergy) m.regenEnergy(); //extra energy regen - m.drawFieldMeter() // this calls m.regenEnergy(); also + m.drawRegenEnergy() // this calls m.regenEnergy(); also } } else { m.fieldFire = true; m.isBodiesAsleep = false; - m.drain = 0.002 m.hold = function() { if (m.isHolding) { m.wakeCheck(); @@ -2730,17 +2790,16 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field && m.fieldCDcycle < m.cycle) { + const drain = 0.0026 + if (m.energy > drain) m.energy -= drain m.grabPowerUp(); - m.lookForPickUp(); - if (m.energy > m.drain) { - m.energy -= m.drain; - if (m.energy < m.drain) { //out of energy - m.fieldCDcycle = m.cycle + 120; - m.energy = 0; - m.wakeCheck(); - } + m.lookForPickUp(); //this drains energy 0.001 + if (m.energy > drain) { timeStop(); } else { //holding, but field button is released + m.fieldCDcycle = m.cycle + 120; + m.energy = 0; + m.wakeCheck(); m.wakeCheck(); } } else if (tech.isTimeStop && player.speed < 1 && m.onGround && m.fireCDcycle < m.cycle && !input.fire) { @@ -2765,9 +2824,7 @@ const m = { m.wakeCheck(); m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - if (m.energy < m.maxEnergy) m.regenEnergy(); //extra energy regen - if (m.energy < m.maxEnergy) m.regenEnergy(); //extra energy regen - m.drawFieldMeter() + m.drawRegenEnergy() } } }, @@ -2813,6 +2870,7 @@ const m = { m.holding(); m.throwBlock(); } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold and field button is pressed + if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding target exists, and field button is not pressed @@ -2825,6 +2883,15 @@ const m = { if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing if (!m.isCloak) { m.isCloak = true //enter cloak + + // m.color = { + // hue: 0, + // sat: 0, + // light: 100 + // } + // m.setFillColorsAlpha(0) + + m.enterCloakCycle = m.cycle if (tech.isCloakHealLastHit && m.lastHit > 0) { const heal = Math.min(0.75 * m.lastHit, m.energy) @@ -2914,7 +2981,7 @@ const m = { player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions } } - this.drawFieldMeterCloaking() + this.drawRegenEnergyCloaking() //show sneak attack status // if (m.cycle > m.lastKillCycle + 240) { // if (m.sneakAttackCharge > 0) { @@ -3258,7 +3325,7 @@ const m = { m.fieldOn = false m.fieldRadius = 0 } - m.drawFieldMeter("rgba(0,0,0,0.2)") + m.drawRegenEnergy("rgba(0,0,0,0.2)") } } }, @@ -3685,7 +3752,7 @@ const m = { // } else { // m.hole.isReady = true; // } - m.drawFieldMeter() + m.drawRegenEnergy() } }, @@ -3771,7 +3838,7 @@ const m = { // m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) // } // } - // m.drawFieldMeter() + // m.drawRegenEnergy() // }, }, ], @@ -3955,7 +4022,7 @@ const m = { //body ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -3998,7 +4065,7 @@ const m = { if (tech.isPiezo) m.energy += 20.48; if (tech.isStimulatedEmission) powerUps.ejectTech() if (mob[k].onHit) mob[k].onHit(); - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles //extra kick between player and mob //this section would be better with forces but they don't work... let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); Matter.Body.setVelocity(player, { diff --git a/js/powerup.js b/js/powerup.js index 3e53405..0ad1750 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -825,15 +825,20 @@ const powerUps = { if (!tech.isSuperDeterminism) text += `
${tech.isCancelTech ? "?":"✕"}
` text += `

tech

` + //used for junk estimation + let junkCount = 0 + let totalCount = 0 + let options = []; //generate all options optionLengthNoDuplicates = 0 for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isBanished) { + totalCount += tech.tech[i].frequency + if (tech.tech[i].isJunk) junkCount += tech.tech[i].frequency if (tech.tech[i].frequency > 0) optionLengthNoDuplicates++ for (let j = 0, len = tech.tech[i].frequency; j < len; j++) options.push(i); } } - // console.log(optionLengthNoDuplicates, options.length) function removeOption(index) { for (let i = options.length; i > -1; i--) { @@ -1202,7 +1207,7 @@ const powerUps = { randomPowerUpCounter: 0, spawnBossPowerUp(x, y) { //boss spawns field and gun tech upgrades if (level.levels[level.onLevel] !== "final") { - if (m.fieldMode === 0) { + if (m.fieldMode === 0 && !m.coupling) { powerUps.spawn(x, y, "field") } else { powerUps.randomPowerUpCounter++; diff --git a/js/spawn.js b/js/spawn.js index d9c8bc9..a91f1e8 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -241,45 +241,47 @@ const spawn = { tech.isHarmMACHO = false; } me.do = function() { - const sine = Math.sin(simulation.cycle * 0.015) - this.radius = 370 * (1 + 0.1 * sine) - //chase player - const sub = Vector.sub(player.position, this.position) - const mag = Vector.magnitude(sub) - // follow physics - // Matter.Body.setVelocity(this, { x: 0, y: 0 }); - // const where = Vector.add(this.position, Vector.mult(Vector.normalise(sub), this.chaseSpeed)) - // if (mag > 10) Matter.Body.setPosition(this, { x: where.x, y: where.y }); + if (!simulation.isTimeSkipping) { + const sine = Math.sin(simulation.cycle * 0.015) + this.radius = 370 * (1 + 0.1 * sine) + //chase player + const sub = Vector.sub(player.position, this.position) + const mag = Vector.magnitude(sub) + // follow physics + // Matter.Body.setVelocity(this, { x: 0, y: 0 }); + // const where = Vector.add(this.position, Vector.mult(Vector.normalise(sub), this.chaseSpeed)) + // if (mag > 10) Matter.Body.setPosition(this, { x: where.x, y: where.y }); - //realistic physics - const force = Vector.mult(Vector.normalise(sub), 0.000000003) - this.force.x += force.x - this.force.y += force.y + //realistic physics + const force = Vector.mult(Vector.normalise(sub), 0.000000003) + this.force.x += force.x + this.force.y += force.y - if (mag < this.radius) { //buff to player when inside radius - tech.isHarmMACHO = true; + if (mag < this.radius) { //buff to player when inside radius + tech.isHarmMACHO = true; - //draw halo - ctx.strokeStyle = "rgba(80,120,200,0.2)" //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + //draw halo + ctx.strokeStyle = "rgba(80,120,200,0.2)" //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + ctx.beginPath(); + ctx.arc(m.pos.x, m.pos.y, 36, 0, 2 * Math.PI); + ctx.lineWidth = 10; + ctx.stroke(); + // ctx.strokeStyle = "rgba(255,255,0,0.17)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + // ctx.beginPath(); + // ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI); + // ctx.lineWidth = 30; + // ctx.stroke(); + } else { + tech.isHarmMACHO = false; + } + //draw outline ctx.beginPath(); - ctx.arc(m.pos.x, m.pos.y, 36, 0, 2 * Math.PI); - ctx.lineWidth = 10; + ctx.arc(this.position.x, this.position.y, this.radius + 15, 0, 2 * Math.PI); + ctx.strokeStyle = "#000" + ctx.lineWidth = 1; ctx.stroke(); - // ctx.strokeStyle = "rgba(255,255,0,0.17)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI); - // ctx.lineWidth = 30; - // ctx.stroke(); - } else { - tech.isHarmMACHO = false; } - //draw outline - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.radius + 15, 0, 2 * Math.PI); - ctx.strokeStyle = "#000" - ctx.lineWidth = 1; - ctx.stroke(); } }, WIMP(x = level.exit.x + tech.wimpCount * 200 * (Math.random() - 0.5), y = level.exit.y + tech.wimpCount * 200 * (Math.random() - 0.5)) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the exit @@ -1296,7 +1298,7 @@ const spawn = { // Matter.Body.setDensity(me, 0.001); //normal is 0.001 me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map me.memory = Infinity; - me.seePlayerFreq = 20 + me.seePlayerFreq = 17 me.lockedOn = null; if (vertices === 9) { //on primary spawn @@ -1359,7 +1361,7 @@ const spawn = { y: 0 }) } - this.seePlayerByHistory(); + this.seePlayerByHistory(50); this.attraction(); this.checkStatus(); }; @@ -2724,7 +2726,7 @@ const spawn = { me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front Matter.Body.rotate(me, Math.random() * Math.PI * 2); me.accelMag = 0.0006 + 0.0007 * Math.sqrt(simulation.accelScale); - me.frictionAir = 0.05; + me.frictionAir = 0.04; // me.seePlayerFreq = 40 + Math.floor(13 * Math.random()) me.memory = 240; me.restitution = 1; @@ -2761,7 +2763,7 @@ const spawn = { const angle = this.angle + Math.PI / 2; c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; const threshold = 0.4; - const turn = 0.00003 * this.inertia + const turn = 0.000025 * this.inertia if (c > threshold) { this.torque += turn; } else if (c < -threshold) { @@ -2793,7 +2795,7 @@ const spawn = { Matter.Body.rotate(me, Math.random() * Math.PI * 2); me.accelMag = 0.00045 + 0.0005 * Math.sqrt(simulation.accelScale); me.frictionAir = 0.05; - me.seePlayerFreq = 20 + me.seePlayerFreq = 13 me.memory = 420; me.restitution = 1; me.frictionStatic = 0; @@ -2902,7 +2904,7 @@ const spawn = { } }; me.do = function() { - this.seePlayerByHistory() + this.seePlayerByHistory(50) this.checkStatus(); if (this.isInvulnerable) { this.invulnerableCount-- @@ -3329,7 +3331,7 @@ const spawn = { } me.do = function() { // this.armor(); - this.seePlayerByHistory() + this.seePlayerByHistory(40) if (this.nextBlinkCycle < simulation.cycle && this.seePlayer.yes) { //teleport towards the player this.nextBlinkCycle = simulation.cycle + this.delay; const dist = Vector.sub(this.seePlayer.position, this.position); @@ -4424,13 +4426,13 @@ const spawn = { } //time dilation if (!simulation.isTimeSkipping) { - // requestAnimationFrame(() => { - // simulation.timePlayerSkip(2) - // m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast - // }); //wrapping in animation frame prevents errors, probably + requestAnimationFrame(() => { + simulation.timePlayerSkip(2) + m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast + }); //wrapping in animation frame prevents errors, probably - simulation.timePlayerSkip(2) - m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast + // simulation.timePlayerSkip(2) + // m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast //draw invulnerable ctx.beginPath(); @@ -4516,7 +4518,7 @@ const spawn = { powerUps.spawnBossPowerUp(this.position.x, this.position.y) }; me.do = function() { - this.seePlayerByHistory(); + this.seePlayerByHistory(40); this.attraction(); this.checkStatus(); this.sword() //does various things depending on what stage of the sword swing @@ -5659,7 +5661,7 @@ const spawn = { // spawn.seeker(where.x, where.y); //give the bullet a rotational velocity as if they were attached to a vertex }; me.do = function() { - this.seePlayerByHistory(); + this.seePlayerByHistory(60); this.attraction(); this.checkStatus(); this.eventHorizon = 900 + 200 * Math.sin(simulation.cycle * 0.005) @@ -5673,12 +5675,14 @@ const spawn = { // // simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations // }); //wrapping in animation frame prevents errors, probably - // requestAnimationFrame(() => { + // // simulation.timePlayerSkip(1) // m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast // }); //wrapping in animation frame prevents errors, probably + requestAnimationFrame(() => { + simulation.timePlayerSkip(1) + }); //wrapping in animation frame prevents errors, probably - simulation.timePlayerSkip(1) m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast ctx.beginPath(); @@ -5925,12 +5929,11 @@ const spawn = { }; }, snakeSpitBoss(x, y, radius = 50) { - const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40) let angle = Math.PI - let mag = 300 + const tailRadius = 300 const color1 = "rgb(235,180,255)" - mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" + mobs.spawn(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)" let me = mob[mob.length - 1]; me.isBoss = true; me.accelMag = 0.0001 + 0.0004 * Math.sqrt(simulation.accelScale) @@ -5938,7 +5941,7 @@ const spawn = { me.memory = 250; me.laserRange = 500; Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0 me.isInvulnerable = true @@ -5956,7 +5959,7 @@ const spawn = { me.cycle = 0 me.do = function() { // this.armor(); - this.seePlayerByHistory() + this.seePlayerByHistory(40) this.checkStatus(); this.attraction(); this.cycle++ @@ -6017,24 +6020,19 @@ const spawn = { } }; //extra space to give head room - angle -= 0.1 - mag -= 10 + angle -= 0.07 let previousTailID = 0 - - const damping = 1 - const stiffness = 1 + const nodes = Math.min(10 + Math.ceil(0.6 * simulation.difficulty), 60) for (let i = 0; i < nodes; ++i) { - angle -= 0.15 + i * 0.008 - mag -= (i < 2) ? -15 : 5 - spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20); - // mag -= 5 - // spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 20); + angle -= 0.1 + spawn.snakeBody(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), i === 0 ? 25 : 20); if (i < 3) mob[mob.length - 1].snakeHeadID = me.id mob[mob.length - 1].previousTailID = previousTailID previousTailID = mob[mob.length - 1].id } + const damping = 1 + const stiffness = 1 this.constrain2AdjacentMobs(nodes, stiffness, false, damping); - for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors if (i % 2) { mob[i].fill = "#778" @@ -6064,21 +6062,21 @@ const spawn = { damping: damping }); Composite.add(engine.world, consBB[consBB.length - 1]); - // spawn.shield(me, x, y, 1); }, dragonFlyBoss(x, y, radius = 42) { //snake boss with a laser head let angle = Math.PI - let mag = 300 - mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, "#000"); //"rgb(55,170,170)" + const tailRadius = 300 + mobs.spawn(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), 8, radius, "#000"); //"rgb(55,170,170)" let me = mob[mob.length - 1]; me.isBoss = true; Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger - me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0 me.isInvulnerable = true - me.accelMag = 0.0001 + 0.0004 * Math.sqrt(simulation.accelScale) + me.accelMag = 0.00008 + 0.00045 * Math.sqrt(simulation.accelScale) me.memory = 250; + me.seePlayerFreq = 13 me.flapRate = 0.4 me.flapArc = 0.2 //don't go past 1.57 for normal flaps me.wingLength = 150 @@ -6092,7 +6090,7 @@ const spawn = { } }; me.do = function() { - this.seePlayerByHistory() + this.seePlayerByHistory(40) this.checkStatus(); this.attraction(); @@ -6118,26 +6116,24 @@ const spawn = { this.wing(a - Math.PI / 2 + this.angleOff + this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity) this.wing(a + Math.PI / 2 - this.angleOff - this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity) }; - angle -= 0.1 - mag -= 10 + + angle -= 0.07 let previousTailID = 0 - const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40) + const nodes = Math.min(10 + Math.ceil(0.6 * simulation.difficulty), 60) for (let i = 0; i < nodes; ++i) { - angle -= 0.15 + i * 0.008 - mag -= (i < 2) ? -15 : 5 - spawn.snakeBody(x + mag * Math.cos(angle), y + mag * Math.sin(angle), i === 0 ? 25 : 20); - if (i < 3) mob[mob.length - 1].snakeHeadID = me.id - if (i === 0) me.snakeBody1 = mob[mob.length - 1] //track this segment, so the difference in position between this segment and the head can be used to angle the wings - mob[mob.length - 1].previousTailID = previousTailID - previousTailID = mob[mob.length - 1].id + angle -= 0.1 + spawn.snakeBody(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), i === 0 ? 25 : 20); + const who = mob[mob.length - 1] + who.fill = `hsl(${160+40*Math.random()}, 100%, ${5 + 25*Math.random()*Math.random()}%)` + if (i < 3) who.snakeHeadID = me.id + if (i === 0) me.snakeBody1 = who //track this segment, so the difference in position between this segment and the head can be used to angle the wings + who.previousTailID = previousTailID + previousTailID = who.id } const damping = 1 const stiffness = 1 this.constrain2AdjacentMobs(nodes, stiffness, false, damping); - for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors - mob[i].fill = `hsla(${160+40*Math.random()}, 100%, ${5 + 25*Math.random()*Math.random()}%, 0.9)` - } - //constraint with first 3 mobs in line + //constraint with first few mobs in tail consBB[consBB.length] = Constraint.create({ bodyA: mob[mob.length - nodes], bodyB: mob[mob.length - 1 - nodes], @@ -6159,13 +6155,12 @@ const spawn = { damping: damping }); Composite.add(engine.world, consBB[consBB.length - 1]); - // spawn.shield(me, x, y, 1); }, snakeBody(x, y, radius = 10) { mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)"); let me = mob[mob.length - 1]; me.collisionFilter.mask = cat.bullet | cat.player //| cat.mob //| cat.body - me.damageReduction = 0.015 + me.damageReduction = 0.021 Matter.Body.setDensity(me, 0.0001); //normal is 0.001 // me.accelMag = 0.0007 * simulation.accelScale; diff --git a/js/tech.js b/js/tech.js index efcef70..46cd82b 100644 --- a/js/tech.js +++ b/js/tech.js @@ -78,37 +78,20 @@ const tech = { // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1) // } // }, - addJunkTechToPool(chance) { //chance is number between 0-1 - // { //count JUNK - // let count = 0 - // for (let i = 0, len = tech.tech.length; i < len; i++) { - // if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && tech.tech[i].isJunk && tech.tech[i].frequency > 0) count += tech.tech[i].frequency - // } - // console.log(count) - // } - // { //count not JUNK - // let count = 0 - // for (let i = 0, len = tech.tech.length; i < len; i++) { - // if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk && tech.tech[i].frequency > 0) count++ - // } - // console.log(count) - // } - // count total non junk tech - id = "github" - - let count = 0 - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk) count += tech.tech[i].frequency - } + addJunkTechToPool(percent) { //percent is number between 0-1 //make an array for possible junk tech to add let options = []; for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].isJunk) options.push(i); } - //add random array options to tech pool if (options.length) { - const num = chance * count //scale number added - for (let i = 0; i < num; i++) tech.tech[options[Math.floor(Math.random() * options.length)]].frequency++ + let countNonJunk = 0 // count total non junk tech + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk) countNonJunk += tech.tech[i].frequency + } + const num = percent * countNonJunk //scale number added + console.log(num) + for (let i = 0; i < num; i++) tech.tech[options[Math.floor(Math.random() * options.length)]].frequency++ //add random array options to tech pool simulation.makeTextLog(`tech.tech.push(${num.toFixed(0)} JUNK)`) return num } else { @@ -162,7 +145,7 @@ const tech = { if (tech.isMetaAnalysis && tech.tech[index].isJunk) { simulation.makeTextLog(`//tech: meta-analysis replaced junk tech with random tech`); tech.giveTech('random') - for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x + 40 * Math.random(), m.pos.y + 40 * Math.random(), "research"); + for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * Math.random(), m.pos.y + 40 * Math.random(), "research"); return } @@ -225,6 +208,7 @@ const tech = { }, damageFromTech() { let dmg = 1 //m.fieldDamage + if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 7)) dmg *= 1 + 0.15 * m.coupling if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime if (tech.isNoDraftPause) dmg *= 1.34 if (tech.isCloakingDamage) dmg *= 1.35 @@ -257,7 +241,7 @@ const tech = { return dmg * tech.slowFire * tech.aimDamage }, duplicationChance() { - return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) + tech.isQuantumEraserDuplication * (1 - 0.016 * (simulation.difficultyMode ** 2))) + return Math.max(0, (tech.isPowerUpsVanish ? 0.12 : 0) + (tech.isStimulatedEmission ? 0.15 : 0) + tech.cancelCount * 0.045 + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0) + tech.isQuantumEraserDuplication * (1 - 0.016 * (simulation.difficultyMode ** 2)) + (m.fieldMode === 0 || m.fieldMode === 9) * 0.05 * m.coupling) }, isScaleMobsWithDuplication: false, maxDuplicationEvent() { @@ -306,41 +290,7 @@ const tech = { } } }, - tech: [ - // { - // name: "field coupling", - // descriptionFunction() { - // return `+1 field coupling (${m.fieldUpgrades[m.fieldMode].name})
${ m.couplingDescription()}` - // }, - // // isFieldTech: true, - // maxCount: 9, - // count: 0, - // frequency: 2, - // frequencyDefault: 2, - // allowed() { - // return (build.isExperimentSelection || powerUps.research.count > 1) - // }, - // requires: "", - // // researchUsed: 0, - // // couplingToResearch: 0.1, - // effect() { - // m.coupling++ - // // while (powerUps.research.count > 0) { - // // powerUps.research.changeRerolls(-1) - // // this.researchUsed++ - // // m.coupling += this.couplingToResearch - // // } - // }, - // remove() { - // m.coupling = 0 - // // if (this.count) { - // // m.coupling -= this.researchUsed * this.couplingToResearch - // // powerUps.research.changeRerolls(this.researchUsed) - // // this.researchUsed = 0 - // // } - // } - // }, - { + tech: [{ name: "ordnance", description: "double the frequency of finding guntech
spawn a gun", maxCount: 1, @@ -449,7 +399,7 @@ const tech = { }, { name: "active cooling", - description: "for each gun in your inventory
+20% fire rate", + description: "for each gun in your inventory
+18% fire rate", maxCount: 1, count: 0, frequency: 1, @@ -624,7 +574,7 @@ const tech = { return !tech.isEnergyNoAmmo }, requires: "not exciton", - effect: () => { + effect() { tech.isAmmoFromHealth = true; }, remove() { @@ -695,7 +645,7 @@ const tech = { frequencyDefault: 1, allowed() { return true }, requires: "", - effect: () => { + effect() { tech.restDamage += 0.36 }, remove() { @@ -704,7 +654,7 @@ const tech = { }, { name: "Higgs mechanism", - description: "+50% fire rate
while firing your position is fixed", + description: "+45% fire rate
while firing your position is fixed", maxCount: 1, count: 0, frequency: 1, @@ -713,7 +663,7 @@ const tech = { return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple }, requires: "not ship mode, automatic, grappling hook", - effect: () => { + effect() { tech.isFireMoveLock = true; b.setFireCD(); b.setFireMethod(); @@ -876,7 +826,7 @@ const tech = { }, { name: "heuristics", - description: "+33% fire rate", + description: "+30% fire rate", maxCount: 9, count: 0, frequency: 1, @@ -884,7 +834,7 @@ const tech = { allowed() { return true }, requires: "", effect() { - tech.fireRate *= 0.67 + tech.fireRate *= 0.7 b.setFireCD(); }, remove() { @@ -941,7 +891,7 @@ const tech = { return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath }, requires: "no other mob death tech", - effect: () => { + effect() { tech.isExplodeMob = true; }, remove() { @@ -959,7 +909,7 @@ const tech = { return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath }, requires: "no other mob death tech", - effect: () => { + effect() { tech.nailsDeathMob++ }, remove() { @@ -993,7 +943,7 @@ const tech = { }, { name: "reaction inhibitor", - description: "after mobs spawn
remove +13% of their durability", //health + description: "-13% maximum mob health", //health maxCount: 3, count: 0, frequency: 1, @@ -1002,16 +952,17 @@ const tech = { return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath }, requires: "", //"any mob death tech", - effect: () => { - tech.mobSpawnWithHealth *= 0.87 - + effect() { + tech.mobSpawnWithHealth++ + mobs.setMobSpawnHealth() //set all mobs at full health to 0.85 for (let i = 0; i < mob.length; i++) { - if (mob.health > tech.mobSpawnWithHealth) mob.health = tech.mobSpawnWithHealth + if (mob.health > mobs.mobSpawnWithHealth) mob.health = mobs.mobSpawnWithHealth } }, remove() { - tech.mobSpawnWithHealth = 1; + tech.mobSpawnWithHealth = 0 + mobs.setMobSpawnHealth() } }, { @@ -1620,7 +1571,7 @@ const tech = { return b.totalBots() > 1 || build.isExperimentSelection }, requires: "at least 2 bots", - effect: () => { + effect() { tech.isExtraBotOption = true for (let i = 0; i < 2; i++) b.randomBot() }, @@ -1645,7 +1596,7 @@ const tech = { return tech.isExtraBotOption }, requires: "robotics", - effect: () => { + effect() { for (let i = 0; i < 3; i++) b.randomBot() for (let i = 0, len = tech.tech.length; i < len; i++) { if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 3 @@ -1771,23 +1722,23 @@ const tech = { tech.isBlockPowerUps = false } }, - { - name: "Pauli exclusion", - description: `after mob collisions
become invulnerable for +3 seconds`, - maxCount: 9, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - tech.collisionImmuneCycles += 180; - if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage - }, - remove() { - tech.collisionImmuneCycles = 30; - } - }, + // { + // name: "Pauli exclusion", + // description: `after mob collisions
become invulnerable for +3 seconds`, + // maxCount: 9, + // count: 0, + // frequency: 1, + // frequencyDefault: 1, + // allowed() { return true }, + // requires: "", + // effect() { + // m.collisionImmuneCycles += 180; + // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage + // }, + // remove() { + // m.collisionImmuneCycles = 30; + // } + // }, { name: "spin–statistics theorem", description: `every 7 seconds
become invulnerable for +1.75 seconds`, @@ -1796,7 +1747,7 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return true //tech.collisionImmuneCycles > 30 + return true //m.collisionImmuneCycles > 30 }, requires: "", effect() { @@ -2002,7 +1953,7 @@ const tech = { return tech.isRelay }, requires: "relay switch", - effect: () => { + effect() { tech.isRelayEnergy = true m.setMaxEnergy() }, @@ -2076,7 +2027,7 @@ const tech = { return !tech.isEnergyHealth }, requires: "not mass-energy", - effect: () => { + effect() { tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO spawn.MACHO() }, @@ -2099,7 +2050,7 @@ const tech = { return tech.isMACHO }, requires: "MACHO", - effect: () => { + effect() { tech.isAxion = true }, remove() { @@ -2233,7 +2184,7 @@ const tech = { return !tech.isZeno && !tech.isNoHeals && !tech.isPiezo && !tech.isRewindAvoidDeath && !tech.isMutualism //&& !tech.isAmmoFromHealth && !tech.isRewindGun }, requires: "not Zeno, ergodicity, piezoelectricity, CPT, antiscience, mutualism", - effect: () => { + effect() { m.health = 0 document.getElementById("health").style.display = "none" document.getElementById("health-bg").style.display = "none" @@ -2329,7 +2280,7 @@ const tech = { frequencyDefault: 1, allowed() { return true }, requires: "", - effect: () => { + effect() { tech.isEnergyDamage = true }, remove() { @@ -2348,14 +2299,14 @@ const tech = { return !tech.isTimeCrystals }, requires: "not time crystals", - effect: () => { - m.fieldRegen = 0.0005 + effect() { tech.isGroundState = true + m.setFieldRegen() m.setMaxEnergy() }, remove() { - m.fieldRegen = 0.001; tech.isGroundState = false + m.setFieldRegen() m.setMaxEnergy() } }, @@ -2475,7 +2426,7 @@ const tech = { effect() { tech.isCrouchRegen = true; //only used to check for requirements m.regenEnergy = function() { - if (m.immuneCycle < m.cycle && m.crouch) m.energy += 7 * m.fieldRegen; //m.fieldRegen = 0.001 + if (m.immuneCycle < m.cycle && m.crouch) m.energy += 7 * m.fieldRegen; if (m.energy < 0) m.energy = 0 } }, @@ -2549,7 +2500,7 @@ const tech = { effect() { tech.isDamageAfterKillNoRegen = true; m.regenEnergy = function() { - if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen; //m.fieldRegen = 0.001 + if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 } }, @@ -3013,7 +2964,7 @@ const tech = { }, { name: "perturbation theory", - description: `if you have no ${powerUps.orb.research(1)} in your inventory
+66% fire rate`, + description: `if you have no ${powerUps.orb.research(1)} in your inventory
+60% fire rate`, maxCount: 1, count: 0, frequency: 1, @@ -3024,7 +2975,7 @@ const tech = { requires: "no research", effect() { tech.isRerollHaste = true; - tech.researchHaste = 0.33; + tech.researchHaste = 0.4; b.setFireCD(); }, remove() { @@ -3044,7 +2995,7 @@ const tech = { return powerUps.research.count === 0 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality }, requires: "no research, not superdeterminism, Ψ(t) collapse, perturbation theory", - effect: () => { + effect() { tech.isAnsatz = true; }, remove() { @@ -3119,7 +3070,7 @@ const tech = { return !tech.isDeterminism && tech.duplicationChance() < 1 }, requires: "below 100% duplication chance not determinism", - effect: () => { + effect() { tech.isExtraGunField = true; }, remove() { @@ -3137,7 +3088,7 @@ const tech = { return !tech.isDeterminism }, requires: "not determinism", - effect: () => { + effect() { tech.extraChoices += 2; this.refundAmount += tech.addJunkTechToPool(0.04) }, @@ -3183,7 +3134,7 @@ const tech = { return !tech.extraChoices && !tech.isExtraGunField && !tech.isFlipFlopChoices }, requires: "NOT EXPERIMENT MODE, not emergence, cross disciplinary, integrated circuit", - effect: () => { + effect() { tech.isDeterminism = true; //if you change the number spawned also change it in Born rule for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech"); @@ -3205,7 +3156,7 @@ const tech = { return tech.isDeterminism && !tech.isAnsatz }, requires: "NOT EXPERIMENT MODE, determinism, not ansatz", - effect: () => { + effect() { tech.isSuperDeterminism = true; //if you change the number spawned also change it in Born rule for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech"); @@ -3314,7 +3265,7 @@ const tech = { }, { name: "meta-analysis", - description: `if you choose a JUNK tech you instead get a
random normal tech and ${powerUps.orb.research(1)}`, + description: `if you choose a JUNK tech you instead get a
random normal tech and ${powerUps.orb.research(2)}`, maxCount: 1, count: 0, frequency: 1, @@ -3496,7 +3447,7 @@ const tech = { return tech.duplicationChance() < 1.11 }, requires: "below 111% duplication chance", - effect: () => { + effect() { tech.isStimulatedEmission = true powerUps.setDupChance(); //needed after adjusting duplication chance if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.15); @@ -3517,7 +3468,7 @@ const tech = { return tech.duplicationChance() < 1.11 }, requires: "below 111% duplication chance", - effect: () => { + effect() { tech.isPowerUpsVanish = true powerUps.setDupChance(); //needed after adjusting duplication chance if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.12); @@ -3596,7 +3547,7 @@ const tech = { return (tech.totalCount > 6) }, requires: "NOT EXPERIMENT MODE, more than 6 tech", - effect: () => { + effect() { //remove active bullets //to get rid of bots for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]); bullet = []; @@ -3664,7 +3615,7 @@ const tech = { return (tech.totalCount > 3) && !tech.isSuperDeterminism }, requires: "NOT EXPERIMENT MODE, at least 4 tech, not superdeterminism", - effect: () => { + effect() { const have = [] //find which tech you have for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i) @@ -3696,7 +3647,7 @@ const tech = { return (tech.totalCount > 3) && tech.duplicationChance() > 0 && !tech.isSuperDeterminism }, requires: "NOT EXPERIMENT MODE, some duplication, at least 4 tech, not superdeterminism", - effect: () => { + effect() { const removeTotal = tech.removeTech() for (let i = 0; i < removeTotal + 1; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech"); }, @@ -3716,7 +3667,7 @@ const tech = { return !tech.isSuperDeterminism && tech.duplicationChance() > 0 && powerUps.research.count > 1 }, requires: "NOT EXPERIMENT MODE, some duplication, not superdeterminism", - effect: () => { + effect() { powerUps.research.changeRerolls(-2) simulation.makeTextLog(`m.research -= 2`) powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); @@ -3735,7 +3686,7 @@ const tech = { return tech.totalCount > 9 }, requires: "at least 10 tech", - effect: () => { + effect() { for (let i = 0, len = tech.tech.length; i < len; i++) { if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10 } @@ -4575,13 +4526,14 @@ const tech = { return tech.haveGunCheck("matter wave") && !tech.isPhaseVelocity && !tech.isBulletTeleport }, requires: "matter wave, not phase velocity, uncertainty principle", + ammoScale: 11, effect() { tech.isLongitudinal = true; for (i = 0, len = b.guns.length; i < len; i++) { //find which gun if (b.guns[i].name === "matter wave") { b.guns[i].chooseFireMethod() - b.guns[i].ammoPack = b.guns[i].defaultAmmoPack / 10 - b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 10); + b.guns[i].ammoPack = b.guns[i].defaultAmmoPack / this.ammoScale + b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoScale); simulation.updateGunHUD(); break } @@ -4594,7 +4546,7 @@ const tech = { tech.isLongitudinal = false; b.guns[i].chooseFireMethod() b.guns[i].ammoPack = b.guns[i].defaultAmmoPack - b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 10); + b.guns[i].ammo = Math.ceil(b.guns[i].ammo * this.ammoScale); simulation.updateGunHUD(); break } @@ -4771,7 +4723,7 @@ const tech = { return tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.isBoomBotUpgrade || tech.isTokamak) }, requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation", - effect: () => { + effect() { tech.isExplodeRadio = true; //iridium-192 }, remove() { @@ -4809,7 +4761,7 @@ const tech = { return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() }, requires: "an explosive damage source, not iridium-192", - effect: () => { + effect() { tech.explosiveRadius += 0.24; }, remove() { @@ -4828,7 +4780,7 @@ const tech = { return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isExplosionHarm }, requires: "an explosive damage source, not iridium-192, acetone peroxide", - effect: () => { + effect() { tech.isSmallExplosion = true; }, remove() { @@ -4848,7 +4800,7 @@ const tech = { return tech.hasExplosiveDamageCheck() && !tech.isSmallExplosion }, requires: "an explosive damage source, not nitroglycerin", - effect: () => { + effect() { tech.isExplosionHarm = true; }, remove() { @@ -4886,7 +4838,7 @@ const tech = { return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 3) && (tech.haveGunCheck("missiles") || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) }, requires: "an explosive damage source, not electric reactive armor", - effect: () => { + effect() { tech.isSmartRadius = true; for (let i = 0; i < 4; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) @@ -4910,7 +4862,7 @@ const tech = { return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isEnergyHealth }, requires: "an explosive damage source, not iridium-192, mass-energy", - effect: () => { + effect() { tech.isImmuneExplosion = true; }, remove() { @@ -6461,6 +6413,41 @@ const tech = { //************************************************** field //************************************************** tech //************************************************** + { + name: "coupling", + descriptionFunction() { + return `+1 field coupling (${m.fieldUpgrades[m.fieldMode].name})
${ m.couplingDescription()}` + }, + // isFieldTech: true, + maxCount: 9, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return (build.isExperimentSelection || powerUps.research.count > 1) + }, + requires: "", + // researchUsed: 0, + // couplingToResearch: 0.1, + effect() { + m.coupling++ + m.couplingChange() + // while (powerUps.research.count > 0) { + // powerUps.research.changeRerolls(-1) + // this.researchUsed++ + // m.coupling += this.couplingToResearch + // } + }, + remove() { + m.coupling -= this.count + m.couplingChange() + // if (this.count) { + // m.coupling -= this.researchUsed * this.couplingToResearch + // powerUps.research.changeRerolls(this.researchUsed) + // this.researchUsed = 0 + // } + } + }, { name: "zero point energy", description: `use ${powerUps.orb.research(2)}
+100 maximum energy`, @@ -6808,7 +6795,7 @@ const tech = { return powerUps.research.count > 1 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") }, requires: "NOT EXPERIMENT MODE, molecular assembler", - effect: () => { + effect() { for (let i = 0; i < 2; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) } @@ -6834,7 +6821,7 @@ const tech = { return powerUps.research.count > 2 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") }, requires: "NOT EXPERIMENT MODE, molecular assembler", - effect: () => { + effect() { for (let i = 0; i < 3; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) } @@ -6988,7 +6975,7 @@ const tech = { return m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" }, requires: "molecular assembler, pilot wave, standing wave", - effect: () => { + effect() { tech.isMassEnergy = true // used in m.grabPowerUp m.energy += 2 }, @@ -7278,13 +7265,13 @@ const tech = { return !tech.isGroundState && (m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") }, requires: "time dilation or pilot wave, not ground state", - effect: () => { - m.fieldRegen = 0.004 + effect() { tech.isTimeCrystals = true + m.setFieldRegen() }, remove() { - m.fieldRegen = 0.001 tech.isTimeCrystals = false + m.setFieldRegen() } }, { @@ -7492,7 +7479,7 @@ const tech = { return m.fieldUpgrades[m.fieldMode].name === "wormhole" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "time dilation" }, requires: "wormhole or pilot wave", - effect: () => { + effect() { tech.wimpCount++ spawn.WIMP() for (let j = 0, len = 5; j < len; j++) powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false) @@ -8646,7 +8633,7 @@ const tech = { return !tech.isFireMoveLock }, requires: "not Higgs mechanism", - effect: () => { + effect() { tech.isAlwaysFire = true; b.setFireMethod(); }, @@ -9346,7 +9333,7 @@ const tech = { ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -9389,7 +9376,7 @@ const tech = { ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.arc(15, 0, 4, 0, 2 * Math.PI); ctx.strokeStyle = "#333"; @@ -9458,7 +9445,7 @@ const tech = { ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.stroke(); ctx.moveTo(19, 0); @@ -9566,7 +9553,7 @@ const tech = { ctx.rotate(m.angle); ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient + ctx.fillStyle = m.bodyGradient ctx.fill(); ctx.strokeStyle = "#333"; ctx.lineWidth = 2; @@ -9586,7 +9573,7 @@ const tech = { ctx.stroke(); ctx.beginPath(); ctx.arc(18, 13, 10, 0, 2 * Math.PI); - ctx.fillStyle = this.bodyGradient; + ctx.fillStyle = m.bodyGradient; ctx.fill(); ctx.stroke(); ctx.beginPath(); @@ -10266,7 +10253,6 @@ const tech = { plasmaBotCount: null, missileBotCount: null, orbitBotCount: null, - collisionImmuneCycles: null, blockDmg: null, isBlockRadiation: null, isPiezo: null, diff --git a/todo.txt b/todo.txt index 76e01cd..4f02019 100644 --- a/todo.txt +++ b/todo.txt @@ -1,30 +1,52 @@ ******************************************************** NEXT PATCH ************************************************** -new setting: level ban list -bug fix: removed a command to preventDefault on space key, this might break something else -new boss added to level - Temple +tech: coupling - +1 coupling, coupling is a new stat that provides different buffs for each field + releasing this early for feedback about balance and bugs + +removed tech Pauli exclusion + now the perfect diamagnatism coupling effect + +snakeBoss tails are closer together +some bosses have a higher vision memory and response time + +phonon gets 10% less ammo and 10% less damage +meta-analysis gives 2 research per use +energy drain rework + in many situations drain no longer scales with regen + this might have some bad side effects, let me know + +bug fixes + made several tech effects not an arrow function + timeSkip graphical glitches might be improved -snake tails have a lower mass and whip around a bit -auto targeting no longer works for stealth mobs - snipers, sneakers, ghosters -snipers fire more often at high difficulty, but bullets move slower at all difficulties -hoppers have move gravity, so it feels like they are hopping a bit faster - *********************************************************** TODO ***************************************************** -tech: field coupling - +1 field coupling, coupling is a new stat that provides different buffs for each field - you can see your coupling in the pause menu -make field coupling a stat that shows in pause menu and is effected by other tech? + +coupling: + field emitter balance? + +coupling tech names: fine-structure constant, strongly coupled, Vibronic coupling tech: convert all research into "coupling" tech: +x% field coupling, your field changes randomly every y seconds tech: coupling starts at 200%, but decays when the field is in use, coupling recharges when the field is not in use some fields aren't used much (that's ok?) + Tech: Cancelling a tech/gun/field gives x coupling buffing your deflecting for 1 second after pressing the field button sounds cool 2 second cooldown on the effect to prevent spamming it buff: giving energy or doing damage makes sense maybe this could be a rework for bremstralung +rewindBoss: after hitting 1/5 damage theasholds the boss rewinds back in time to where it was a few seconds ago + track it's data like player history + +worms can target player, buff their damage + can't target player in first few seconds? + +draw player transparent or opaque when cloaking field is on + +plasma field tech - similar to regression, but for plasma ticks + greatly increase walking speed not mid air control? for time dilation field @@ -36,6 +58,8 @@ after taking damage explode while invulnerable quantum immortality: send you to a new tab after you die with a random load out basically everything is the same as it is now, but you switch tabs +Tech: Tech/guns/fields can no longer be duplicated. Duplication applies twice + tech: get sent to a new tab that closes in 3 minutes in the new tab you play reactor if you die in reactor you die in game, if you win you get 2-3 tech in the original game?