From de6d910aca525dcc4d57d28a5c6560e1e81296e4 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sun, 23 Oct 2022 19:07:07 -0700 Subject: [PATCH] pigeonhole principle tech: junk DNA - +53% spore/worm/flea damage per JUNK tech you have, +50% JUNK added to tech pool tech: pigeonhole principle - +31% damage for each gun you have, while a chosen gun is active chosen gun cycles each level syncs well with generalist heuristics 30->25% fire rate, and now spawns a gun arsenal gives 13->22% damage per gun, but no longer counts your current gun active cooling gives 18->28% fire rate per gun, but no longer counts your current gun supply chain adds 4% JUNK dead reckoning 36->50% damage alternator harpoon 60->80% energy cost reduction quickly releasing the fire button retracts harpoon early JUNK tech - circular symmetry - ship gets 200% damage, ship only faces forward but you can rotate the universe several bug fixes coupling for molecular assembler 5->8 energy per second but also fixed a bug where coupling was giving 10x regen --- js/bullet.js | 18 +-- js/level.js | 28 +++-- js/player.js | 6 +- js/powerup.js | 36 +++--- js/simulation.js | 9 ++ js/tech.js | 279 +++++++++++++++++++++++++++++++++++------------ js/visibility.js | 3 +- style.css | 5 + todo.txt | 58 +++++++--- 9 files changed, 314 insertions(+), 128 deletions(-) diff --git a/js/bullet.js b/js/bullet.js index e80fc71..929995c 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -284,7 +284,7 @@ const b = { b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage if (m.fieldMode === 6) b.fireCDscale *= 0.75 if (tech.isFastTime) b.fireCDscale *= 0.5 - if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, b.inventory.length) + if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, Math.max(0, b.inventory.length - 1)) if (tech.isFireMoveLock) b.fireCDscale *= 0.55 }, fireAttributes(dir, rotate = true) { @@ -1441,7 +1441,7 @@ const b = { minDmgSpeed: 4, lookFrequency: Math.floor(7 + Math.random() * 3), density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed - drain: tech.isRailEnergy ? 0.002 : 0.006, + drain: tech.isRailEnergy ? 0.001 : 0.006, beforeDmg(who) { if (tech.isShieldPierce && who.isShielded) { //disable shields who.isShielded = false @@ -1697,7 +1697,7 @@ const b = { friction: 1, frictionAir: 0.4, thrustMag: 0.1, - drain: tech.isRailEnergy ? 0.002 : 0.006, + drain: tech.isRailEnergy ? 0.001 : 0.006, turnRate: isReturn ? 0.1 : 0.03, //0.015 drawStringControlMagnitude: 3000 + 5000 * Math.random(), drawStringFlip: (Math.round(Math.random()) ? 1 : -1), @@ -1862,7 +1862,7 @@ const b = { this.cycle++ if (isReturn || target) { if (isReturn) { - if (this.cycle > totalCycles || m.energy < 0.05) { //return to player + if (this.cycle > totalCycles || m.energy < 0.05 || !input.fire) { //return to player this.do = this.returnToPlayer if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) Matter.Sleeping.set(this, false) @@ -2698,7 +2698,7 @@ const b = { thrust: (tech.isSporeFollow ? 0.0012 : 0.00055) * (1 + 0.5 * (Math.random() - 0.5)), wormSize: wormSize, wormTail: 1 + Math.max(4, Math.min(wormSize - 2 * tech.wormSize, 30)), - dmg: (tech.isMutualism ? 8 : 3.2) * wormSize, //bonus damage from tech.isMutualism //2.5 is extra damage as worm + dmg: (tech.isMutualism ? 8 : 3.2) * wormSize * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1), //bonus damage from tech.isMutualism //2.5 is extra damage as worm lookFrequency: 100 + Math.floor(37 * Math.random()), classType: "bullet", collisionFilter: { @@ -2814,7 +2814,7 @@ const b = { friction: 0, frictionAir: 0.025, thrust: (tech.isSporeFollow ? 0.0011 : 0.0005) * (1 + 0.3 * (Math.random() - 0.5)), - dmg: tech.isMutualism ? 16.8 : 7, //bonus damage from tech.isMutualism + dmg: (tech.isMutualism ? 16.8 : 7) * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1), //bonus damage from tech.isMutualism lookFrequency: 100 + Math.floor(117 * Math.random()), classType: "bullet", isSpore: true, @@ -3031,7 +3031,7 @@ const b = { cd: simulation.cycle + 10, dmg: 0, //radius * (tech.isMutualism ? 2.5 : 1), setDamage() { //dmg is set to zero after doing damage once, and set back to normal after jumping - this.dmg = radius * (tech.isMutualism ? 2.5 : 1) //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18 + this.dmg = radius * (tech.isMutualism ? 2.5 : 1) * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1) //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18 }, beforeDmg(who) { Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target @@ -6777,7 +6777,7 @@ const b = { charge: 0, railDo() { if (this.charge > 0) { - const DRAIN = (tech.isRailEnergy ? 0.0005 : 0.002) + const DRAIN = (tech.isRailEnergy ? 0.00025 : 0.002) //exit railgun charging without firing if (m.energy < DRAIN) { // m.energy += 0.025 + this.charge * 22 * this.drain @@ -7051,7 +7051,7 @@ const b = { } } if (input.down && m.onGround) { - b.harpoon(where, null, m.angle, harpoonSize, true, 1.5 * totalCycles, (input.down && tech.crouchAmmoCount && (tech.crouchAmmoCount - 1) % 2) ? false : true) + b.harpoon(where, null, m.angle, harpoonSize, true, 1.5 * totalCycles, (input.down && tech.crouchAmmoCount && (tech.crouchAmmoCount - 1) % 2) ? false : true) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true) { } else { b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles) } diff --git a/js/level.js b/js/level.js index 039c232..fc648cf 100644 --- a/js/level.js +++ b/js/level.js @@ -28,19 +28,20 @@ const level = { // m.setField("time dilation") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave // simulation.molecularMode = 2 // m.damage(0.1); - // b.giveGuns("missiles") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser + // b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.giveGuns("wave") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser - // b.guns[0].ammo = 10000 - - // tech.giveTech("arsenal") - // for (let i = 0; i < 1; ++i) tech.giveTech("compound lens") + // b.guns[9].ammo = 10000 + // tech.giveTech("ship") + // for (let i = 0; i < 1; ++i) tech.giveTech("junk DNA") // tech.giveTech("dye laser") - // for (let i = 0; i < 1; ++i) tech.giveTech("CPT symmetry") + // for (let i = 0; i < 1; ++i) tech.giveTech("grappling hook") // for (let i = 0; i < 5; i++) tech.giveTech("laser-bot") // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "boost"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling"); + // canvas.requestPointerLock() + // level.testing(); // spawn.starter(1900, -500, 200) // spawn.starter(1900, -500) @@ -94,6 +95,14 @@ const level = { m.resetHistory(); spawn.quantumEraserCheck(); //remove mobs from tech: quantum eraser + //used for generalist and pigeonhole principle + tech.buffedGun++ + if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0; + if (tech.isGunCycle) { + b.inventoryGun = tech.buffedGun; + simulation.switchGun(); + } + if (tech.isForeverDrones) { if (tech.isDroneRadioactive) { for (let i = 0; i < tech.isForeverDrones * 0.25; i++) { @@ -111,11 +120,6 @@ const level = { tech.healMaxEnergyBonus += 0.1 * powerUps.totalPowerUps //Math.min(0.02 * powerUps.totalPowerUps, 0.51) m.setMaxEnergy(); } - if (tech.isGunCycle) { - b.inventoryGun++; - if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0; - simulation.switchGun(); - } if (tech.isSwitchReality && powerUps.research.count > 0) { powerUps.research.changeRerolls(-1); simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`); @@ -162,7 +166,7 @@ const level = { if (m.plasmaBall) m.plasmaBall.reset() if (localSettings.entanglement && localSettings.entanglement.levelName === level.levels[level.onLevel]) { const flip = localSettings.entanglement.isHorizontalFlipped === simulation.isHorizontalFlipped ? 1 : -1 - powerUps.spawn(flip * localSettings.entanglement.position.x, localSettings.entanglement.position.y, "entanglement", false); + powerUps.directSpawn(flip * localSettings.entanglement.position.x, localSettings.entanglement.position.y, "entanglement", false); } }, trainingText(say) { diff --git a/js/player.js b/js/player.js index 86a9405..b6d9685 100644 --- a/js/player.js +++ b/js/player.js @@ -362,6 +362,7 @@ const m = { tech.cancelCount = 0; tech.extraMaxHealth = 0; tech.totalCount = 0; + tech.countJunkTech(); const randomBotCount = b.totalBots() b.zeroBotCount() //remove all bullets, respawn bots @@ -1066,7 +1067,8 @@ const m = { } else { m.fieldRegen = 0.001 //6 energy per second } - if (m.fieldMode === 0 || m.fieldMode === 4) m.fieldRegen += 0.008333 * m.coupling + if (m.fieldMode === 0 || m.fieldMode === 4) m.fieldRegen += 0.00133 * m.coupling //return `generate ${(6*couple).toFixed(0)} energy per second` + if (tech.isTimeCrystals) { m.fieldRegen *= 3 } else if (tech.isGroundState) { @@ -1589,7 +1591,7 @@ const m = { case 3: //negative mass return `+${((1-0.73 ** couple)*100).toFixed(1)}% defense` case 4: //assembler - return `generate ${(5*couple).toFixed(0)} energy per second` + return `generate ${(8*couple).toFixed(0)} energy per second` case 5: //plasma return `+${(15*couple).toFixed(0)}% damage` case 6: //time dilation diff --git a/js/powerup.js b/js/powerup.js index 1daef9c..11623e0 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -332,7 +332,7 @@ const powerUps = { }, endDraft(type, isCanceled = false) { //type should be a gun, tech, or field if (isCanceled) { - if (tech.isCancelTech && Math.random() < 0.88) { + if (tech.isCancelTech && Math.random() < 0.85) { // powerUps.research.use('tech') powerUps[type].effect(); return @@ -356,7 +356,7 @@ const powerUps = { powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false); } } - if (tech.isCancelCouple) powerUps.coupling.spawnDelay(5) + if (tech.isCancelCouple) powerUps.spawnDelay("coupling", 5) // if (tech.isCancelTech && Math.random() < 0.3) { // powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "tech", false); // simulation.makeTextLog(`options exchange: returns 1 tech`) @@ -401,20 +401,20 @@ const powerUps = { effect() { m.couplingChange(0.1) }, - spawnDelay(num) { - let count = num - let respawnDrones = () => { - if (count > 0) { - requestAnimationFrame(respawnDrones); - if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2) - count-- - const where = { x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) } - powerUps.spawn(where.x, where.y, "coupling"); - } - } - } - requestAnimationFrame(respawnDrones); - } + // spawnDelay(num) { + // let count = num + // let respawnDrones = () => { + // if (count > 0) { + // requestAnimationFrame(respawnDrones); + // if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2) + // count-- + // const where = { x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) } + // powerUps.spawn(where.x, where.y, "coupling"); + // } + // } + // } + // requestAnimationFrame(respawnDrones); + // } }, boost: { name: "boost", @@ -1149,8 +1149,8 @@ const powerUps = { let count = num let cycle = () => { if (count > 0) { - requestAnimationFrame(cycle); - if (!simulation.paused && !simulation.isChoosing && m.alive) { //&& !(simulation.cycle % 2) + if (m.alive) requestAnimationFrame(cycle); + if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2) count-- const where = { x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) } powerUps.spawn(where.x, where.y, type); diff --git a/js/simulation.js b/js/simulation.js index 30d9a08..897a5d1 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -531,6 +531,15 @@ const simulation = { simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; }, + cameraNoLook() { + ctx.save(); + ctx.translate(canvas.width2, canvas.height2); //center + // ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered + ctx.translate(-canvas.width2 + m.transX, -canvas.height2 + m.transY); //translate + //calculate in game mouse position by undoing the zoom and translations + simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; + simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; + }, restoreCamera() { ctx.restore(); }, diff --git a/js/tech.js b/js/tech.js index 57e9bfa..0fbf538 100644 --- a/js/tech.js +++ b/js/tech.js @@ -31,6 +31,7 @@ const tech = { // tech.addLoreTechToPool(); tech.extraMaxHealth = 0; tech.totalCount = 0; + tech.junkCount = 0 //tech.countJunkTech(); simulation.updateTechHUD(); }, removeTech(index = 'random') { @@ -61,6 +62,7 @@ const tech = { tech.tech[index].remove(); tech.tech[index].count = 0; tech.totalCount -= totalRemoved + tech.countJunkTech(); simulation.updateTechHUD(); tech.tech[index].isLost = true simulation.updateTechHUD(); @@ -90,7 +92,7 @@ const 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 + const num = Math.ceil(percent * countNonJunk) //scale number added 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 @@ -154,9 +156,17 @@ const tech = { tech.tech[index].effect(); //give specific tech tech.tech[index].count++ tech.totalCount++ //used in power up randomization + tech.countJunkTech(); simulation.updateTechHUD(); } }, + junkCount: 0, + countJunkTech() { + tech.junkCount = 0 + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].count > 0 && tech.tech[i].isJunk) tech.junkCount++ + } + }, // setTechoNonRefundable(name) { // for (let i = 0; i < tech.tech.length; i++) { // if (tech.tech.name === name) { @@ -210,6 +220,7 @@ const tech = { damage: 1, //used for tech changes to player damage that don't have complex conditions damageFromTech() { let dmg = tech.damage //m.fieldDamage + if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.15 * m.coupling if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.33 * m.coupling) @@ -218,7 +229,7 @@ const tech = { if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555 if (tech.isAnthropicDamage && tech.isDeathAvoidedThisLevel) dmg *= 2.3703599 if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance()) - if (tech.isDamageForGuns) dmg *= 1 + 0.13 * b.inventory.length + if (tech.isDamageForGuns) dmg *= 1 + 0.22 * Math.max(0, b.inventory.length - 1) if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25 if (tech.isAcidDmg && m.health > 1) dmg *= 1.35; if (tech.isRerollDamage) dmg *= 1 + 0.038 * powerUps.research.count @@ -288,7 +299,7 @@ const tech = { }, tech: [{ name: "ordnance", - description: "double the frequency of finding guntech
spawn a gun and +5% JUNK to tech pool", + description: "double the frequency of finding guntech
spawn a gun and +7% JUNK to tech pool", maxCount: 1, count: 0, frequency: 1, @@ -302,7 +313,7 @@ const tech = { for (let i = 0, len = tech.tech.length; i < len; i++) { if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2 } - this.refundAmount += tech.addJunkTechToPool(0.05) + this.refundAmount += tech.addJunkTechToPool(0.07) }, refundAmount: 0, remove() { @@ -315,7 +326,7 @@ const tech = { { name: "ad hoc", descriptionFunction() { - return `spawn a ${powerUps.orb.heal()}, ${powerUps.orb.research(1)}, field, ${powerUps.orb.ammo(1)}, or tech
for each of your guns` + return `spawn a ${powerUps.orb.heal()}, ${powerUps.orb.research(1)}, ${powerUps.orb.ammo(1)}, field, gun, or tech
for each of your guns` }, maxCount: 1, //random power up count: 0, @@ -325,10 +336,12 @@ const tech = { allowed() { return b.inventory.length > 1 }, - requires: "NOT EXPERIMENT MODE, at least 2 guns", + requires: "at least 2 guns", effect() { for (let i = 0; i < b.inventory.length; i++) { - if (Math.random() < 1 / 5) { + if (Math.random() < 1 / 6) { + powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun"); + } else if (Math.random() < 1 / 5) { powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "tech"); } else if (Math.random() < 1 / 4) { powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field"); @@ -354,9 +367,9 @@ const tech = { allowed() { return b.inventory.length > 1 }, - requires: "NOT EXPERIMENT MODE, at least 2 guns", + requires: "at least 2 guns", effect() { - for (let i = b.inventory.length - 1; i > -1; i--) { + for (let i = b.inventory.length - 1; i > -1; i--) { //backwards because some tech can remove or add guns const gunTechPool = [] //find gun tech for this gun for (let j = 0, len = tech.tech.length; j < len; j++) { // console.log(j, tech.tech[j].isGunTech, tech.tech[j].allowed(), !tech.tech[j].isJunk, !tech.tech[j].isBadRandomOption, tech.tech[j].count < tech.tech[j].maxCount) @@ -382,13 +395,13 @@ const tech = { }, { name: "arsenal", - descriptionFunction() { return `+13% damage per gun (${(13 * b.inventory.length).toFixed(0)}%)` }, + descriptionFunction() { return `+22% damage per unequipped gun (${(22 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)` }, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed: () => true, - requires: "", + allowed: () => b.inventory.length > 1, + requires: "at least 2 guns", effect() { tech.isDamageForGuns = true; }, @@ -398,13 +411,13 @@ const tech = { }, { name: "active cooling", - descriptionFunction() { return `+18% fire rate per gun (${(18 * b.inventory.length).toFixed(0)}%)` }, + descriptionFunction() { return `+28% fire rate per unequipped gun (${(28 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)` }, //
but not including your equipped gun` }, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed: () => true, - requires: "", + allowed: () => b.inventory.length > 1, + requires: "at least 2 guns", effect() { tech.isFireRateForGuns = true; b.setFireCD(); @@ -414,6 +427,67 @@ const tech = { b.setFireCD(); } }, + { + name: "pigeonhole principle", + descriptionFunction() { + var info = "" + if (this.count > 0 && Number.isInteger(tech.buffedGun) && b.inventory.length) { + var gun = b.guns[b.inventory[tech.buffedGun]].name + var info = `
this level: +${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for ${gun}` + } + + // return ` + // a gun is chosen to be improved each level + //
+${(31*b.inventory.length).toFixed(0)}% damage for ${gun} + //
damage scales by 31% per unequipped gun` + return ` + a new gun is chosen to be improved each level +
+31% damage per gun for the chosen gun${info}` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return b.inventory.length > 1 + }, + requires: "at least 2 guns", + effect() { + tech.isGunChoice = true + //switches gun on new level + //generalist uses the same chosen gun so they match + }, + remove() { + tech.isGunChoice = false; + } + }, + { + name: "generalist", + description: "spawn 7 guns, but you can't switch guns
your equipped gun cycles after each level", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + isNonRefundable: true, + isBadRandomOption: true, + allowed() { + return b.inventory.length < b.guns.length - 5 && b.inventory.length > 1 + }, + requires: "at least 2 guns, at least 5 unclaimed guns", + effect() { + tech.isGunCycle = true; + for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun"); + }, + remove() { + if (!this.count) tech.isGunCycle = false; // only set to false if you don't have this tech + // if (tech.isGunCycle) { + // for (let i = 0; i < 8; i++) { + // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun + // } + // tech.isGunCycle = false; + // } + } + }, { name: "first derivative", descriptionFunction() { return `while your first gun is equipped
+15% defense per gun (${(100*(1-0.85 ** b.inventory.length)).toFixed(0)}%)` }, @@ -449,37 +523,9 @@ const tech = { tech.isOneGun = false; } }, - { - name: "generalist", - description: "spawn 7 guns, but you can't switch guns
guns cycle automatically with each new level", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - isNonRefundable: true, - isBadRandomOption: true, - allowed() { - return b.inventory.length < b.guns.length - 5 && b.inventory.length > 1 //(tech.isDamageForGuns || tech.isFireRateForGuns) && - }, - requires: "at least 2 guns, at least 5 unclaimed guns", - effect() { - tech.isGunCycle = true; - for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun"); - }, - remove() { - if (!this.count) tech.isGunCycle = false; // only set to false if you don't have this tech - // if (tech.isGunCycle) { - // for (let i = 0; i < 8; i++) { - // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun - // } - // tech.isGunCycle = false; - // } - } - }, { name: "supply chain", - junk: 0.05, - descriptionFunction() { return `for each gun in your inventory
double its ammo` }, + descriptionFunction() { return `double your current ammo
+4% JUNK to tech pool` }, maxCount: 9, count: 0, frequency: 1, @@ -491,7 +537,7 @@ const tech = { if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo) } simulation.makeGunHUD(); - // this.refundAmount += tech.addJunkTechToPool(this.junk) + this.refundAmount += tech.addJunkTechToPool(0.04) }, refundAmount: 0, remove() { @@ -501,10 +547,10 @@ const tech = { } } simulation.makeGunHUD(); - // if (this.count > 0 && this.refundAmount > 0) { - // tech.removeJunkTechFromPool(this.refundAmount) - // this.refundAmount = 0 - // } + if (this.count > 0 && this.refundAmount > 0) { + tech.removeJunkTechFromPool(this.refundAmount) + this.refundAmount = 0 + } } }, { @@ -622,7 +668,7 @@ const tech = { }, { name: "dead reckoning", - description: "if your speed is 0
+36% damage", + description: "if your speed is 0
+50% damage", maxCount: 9, count: 0, frequency: 1, @@ -630,7 +676,7 @@ const tech = { allowed() { return true }, requires: "", effect() { - tech.restDamage += 0.36 + tech.restDamage += 0.5 }, remove() { tech.restDamage = 1; @@ -811,7 +857,7 @@ const tech = { }, { name: "heuristics", - description: "+30% fire rate", + description: "+25% fire rate
spawn a gun", maxCount: 9, count: 0, frequency: 1, @@ -819,8 +865,9 @@ const tech = { allowed() { return true }, requires: "", effect() { - tech.fireRate *= 0.7 + tech.fireRate *= 0.75 b.setFireCD(); + powerUps.spawn(m.pos.x, m.pos.y, "gun"); }, remove() { tech.fireRate = 1; @@ -2871,7 +2918,7 @@ const tech = { isNonRefundable: true, isBadRandomOption: true, allowed() { return true }, - requires: "NOT EXPERIMENT MODE", + requires: "", effect() { for (let i = 0; i < 13; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "heal"); for (let i = 0, len = tech.tech.length; i < len; i++) { @@ -3251,7 +3298,7 @@ const tech = { allowed() { return !tech.extraChoices && !tech.isExtraGunField && !tech.isFlipFlopChoices }, - requires: "NOT EXPERIMENT MODE, not emergence, cross disciplinary, integrated circuit", + requires: "not emergence, cross disciplinary, integrated circuit", effect() { tech.isDeterminism = true; //if you change the number spawned also change it in Born rule @@ -3322,13 +3369,13 @@ const tech = { }, { name: "meta-analysis", - description: `if you choose a JUNK tech you instead get a
random normal tech and spawn ${powerUps.orb.research(2)}`, + description: `if you choose a JUNKtech you instead get a
random normal tech and spawn ${powerUps.orb.research(2)}`, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, - requires: "", + allowed() { return tech.junkCount > 0 }, + requires: "some JUNK tech", effect() { tech.isMetaAnalysis = true }, @@ -3611,7 +3658,7 @@ const tech = { { name: "options exchange", link: `options exchange`, - description: `clicking × for a field, tech, or gun has a 88%
chance to randomize choices and not cancel`, + description: `clicking × for a field, tech, or gun has a 85%
chance to randomize choices and not cancel`, maxCount: 1, count: 0, frequency: 1, @@ -3700,7 +3747,7 @@ const tech = { }, { name: "metastability", - description: "+11% chance to duplicate spawned power ups
duplicates explode with a 3 second half-life", + description: "+12% chance to duplicate spawned power ups
duplicates explode with a 3 second half-life", maxCount: 1, count: 0, frequency: 1, @@ -4773,8 +4820,10 @@ const tech = { }, remove() { tech.infiniteWaveAmmo = 1 - b.guns[3].ammo = b.guns[3].savedAmmo - simulation.updateGunHUD(); + if (this.count > 1 && b.guns[3].savedAmmo !== undefined) { + b.guns[3].ammo = b.guns[3].savedAmmo + simulation.updateGunHUD(); + } } }, { @@ -4858,7 +4907,7 @@ const tech = { }, { name: "sympathetic resonance", - description: "after a mob gets vibrated by a phonon
a new resonance wave expands from their location", + description: "after a mob gets vibrated by a phonon
a new resonance wave expands", isGunTech: true, maxCount: 1, count: 0, @@ -5538,6 +5587,57 @@ const tech = { tech.isSporeFollow = false } }, + { + name: "junk DNA", + descriptionFunction() { return `+53% ${b.guns[6].nameString()} damage per JUNKtech (${(53*tech.junkCount).toFixed(0)}%)
+50% JUNK to tech pool` }, + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea + }, + requires: "spores", + effect() { + tech.isJunkDNA = true + this.refundAmount += tech.addJunkTechToPool(0.5) + }, + refundAmount: 0, + remove() { + tech.isJunkDNA = false + if (this.count > 0 && this.refundAmount > 0) { + tech.removeJunkTechFromPool(this.refundAmount) + this.refundAmount = 0 + } + } + }, + // { + // name: "junk DNA", + // //increase damage by 10% for each JUNK tech percent in the tech pool, remove all JUNK tech, + // descriptionFunction() { return `+50% ${b.guns[6].nameString()} damage
+15% JUNK to tech pool` }, + // isGunTech: true, + // maxCount: 1, + // count: 0, + // frequency: 3, + // frequencyDefault: 3, + // allowed() { + // return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea + // }, + // requires: "spores", + // effect() { + // tech.isSporeWorm = true + // this.refundAmount += tech.addJunkTechToPool(0.15) + // }, + // refundAmount: 0, + // remove() { + // tech.isSporeWorm = false + // if (this.count > 0 && this.refundAmount > 0) { + // tech.removeJunkTechFromPool(this.refundAmount) + // this.refundAmount = 0 + // } + // } + // }, { name: "mutualism", descriptionFunction() { return `+150% ${b.guns[6].nameString()} damage
${b.guns[6].nameString('s')} borrow 0.5 health until they die` }, @@ -5603,8 +5703,8 @@ const tech = { isGunTech: true, maxCount: 3, count: 0, - frequency: 3, - frequencyDefault: 3, + frequency: 2, + frequencyDefault: 2, allowed() { return tech.isSporeWorm || tech.isSporeFlea }, @@ -6159,7 +6259,7 @@ const tech = { }, { name: "alternator", - description: "+60% harpoon energy efficiency", + description: "+80% harpoon energy efficiency", isGunTech: true, maxCount: 1, count: 0, @@ -8184,7 +8284,9 @@ const tech = { isJunk: true, allowed: () => true, requires: "", - effect() {}, + effect() { + if (Math.random() < 0.1) tech.damage *= 7.77 + }, remove() {} }, { @@ -8347,7 +8449,7 @@ const tech = { // }, { name: "discount", - description: "get 3 random JUNK tech for the price of 1!", + description: "get 3 random JUNKtech for the price of 1!", maxCount: 1, count: 0, frequency: 0, @@ -9255,7 +9357,7 @@ const tech = { }, { name: "defragment", - description: "set the frequency of finding JUNK tech to zero", + description: "set the frequency of finding JUNKtech to zero", maxCount: 1, count: 0, frequency: 0, @@ -9899,6 +10001,38 @@ const tech = { effect() { m.shipMode() level.difficultyDecrease(simulation.difficultyMode) + //unlock relativistic rotation + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].name === "relativistic rotation") tech.tech[i].frequency = 10 + } + }, + remove() {} + }, + { + name: "circular symmetry", + description: "turning the ship rotates the universe instead
+200% damage", + maxCount: 1, + count: 0, + frequency: 0, + isNonRefundable: true, + isJunk: true, + allowed() { return m.isShipMode }, + requires: "", + effect() { + tech.damage *= 2 + + m.look = () => { + // const scale = 0; + m.transSmoothX = canvas.width2 - m.pos.x // - (simulation.mouse.x - canvas.width2) * scale; + m.transSmoothY = canvas.height2 - m.pos.y // - (simulation.mouse.y - canvas.height2) * scale; + m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing; + m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing; + ctx.restore(); + ctx.save(); + ctx.translate(canvas.width2, canvas.height2); //center + ctx.rotate(-m.angle) + ctx.translate(-canvas.width2, -canvas.height2); //center + } }, remove() {} }, @@ -10269,7 +10403,7 @@ const tech = { }, { name: "tinker", - description: "permanently unlock JUNK tech in experiment mode
this effect is stored for future visits", + description: "permanently unlock JUNKtech in experiment mode
this effect is stored for future visits", maxCount: 1, count: 0, frequency: 0, @@ -10799,5 +10933,8 @@ const tech = { isBoostPowerUps: null, isBoostReplaceAmmo: null, isFlipFlopCoupling: null, - infiniteWaveAmmo: null + infiniteWaveAmmo: null, + isJunkDNA: null, + buffedGun: 0, + isGunChoice: null, } \ No newline at end of file diff --git a/js/visibility.js b/js/visibility.js index 2a10809..d1686b7 100644 --- a/js/visibility.js +++ b/js/visibility.js @@ -1,4 +1,5 @@ -// redblobgames.com/articles/visibility +// https://ncase.me/sight-and-light/ +// redblobgames.com/articles/visibility // https://github.com/Silverwolf90/2d-visibility/tree/master/src // could apply to explosions, neutron bomb, player LOS diff --git a/style.css b/style.css index 83a3bca..43248ba 100644 --- a/style.css +++ b/style.css @@ -557,6 +557,11 @@ summary { color: hsl(218, 100%, 58%); } +.highlight { + border-radius: 6px; + background-color: #ff0; + padding: 3px; +} /* colors for pause, selection and experiment */ /* #text-log { diff --git a/todo.txt b/todo.txt index c2966e4..b212a0c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,25 +1,62 @@ ******************************************************** NEXT PATCH ************************************************** -entanglement - your death leaves a power up for next run - renamed entanglement - also stores your gun and field - improved graphics for incompatible tech +tech: junk DNA - +53% spore/worm/flea damage per JUNK tech you have, +50% JUNK added to tech pool +tech: pigeonhole principle - +31% damage for each gun you have, while a chosen gun is active + chosen gun cycles each level + syncs well with generalist + +heuristics 30->25% fire rate, and now spawns a gun +arsenal gives 13->22% damage per gun, but no longer counts your current gun +active cooling gives 18->28% fire rate per gun, but no longer counts your current gun +supply chain adds 4% JUNK +dead reckoning 36->50% damage +alternator harpoon 60->80% energy cost reduction +quickly releasing the fire button retracts harpoon early + +JUNK tech - circular symmetry - ship gets 200% damage, ship only faces forward but you can rotate the universe + +several bug fixes + coupling for molecular assembler 5->8 energy per second + but also fixed a bug where coupling was giving 10x regen *********************************************************** TODO ***************************************************** +lock mouse to the window until you press escape + https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API + canvas.requestPointerLock() + exitPointerLock + toggle off and on when: + you die and start a game + when choosing? + If this doesn't work it could at least be a fun JUNK tech + +run canvas direct pixel editing while game is paused + just update once every second? + if it uses too much processing have a setting to toggle it off + this might help get players to spend more time relaxing on the power up selection + increase the click delay? + +try again - line of sight https://ncase.me/sight-and-light/ + +for tech power ups no tech options are displayed until you research once + or display only JUNK until you research once + increase the number of options after each research + tech increase max energy and energy to 5000, but you can no longer regen energy through any process it would be nice if there was incentive to go slow when choosing tech so n-gon is more relaxing add some css based visual effects for opening up a tech,gun,field -make freeze and __ not cause death at health health, but just 600% extra damage for that bullet +make freeze and __ not cause death at 50% health, but just 600% extra damage for that bullet -new mob attibute - phosphorescence - mobs fire lasers for a few seconds after being hit with lasers +new mob status effect - phosphorescence - mobs fire lasers for a few seconds after being hit with lasers make a new coupling effect for perfect diamagnetism or standing wave +make a faster smaller version of cell boss that also has map collisions + laserMines need a copy of laser-bot method this is a very rare bug, so not a priority @@ -53,13 +90,6 @@ JUNK tech description that changes similar to cards in inscription that changes based on mouse position can you tell if mouse is over card? -tech that encourages gun swapping - a field tech: molecular assembler, pilot wave, negative mass? - something similar to applied science, but also spawn a gun? - a bonus for each time a mob dies with a different active gun each level - +damage on that level - ammo, heals, research? - tech - buff MACHO range, effect, move speed? while you are inside MACHO it will damage mobs? @@ -1021,7 +1051,6 @@ possible names for tech Gödel's incompleteness quantum zeno effect (perturbation of a system prevents some systems from evolving because it scrambles coherence) (apply to lasers, fields) counterfactual - something false - Pigeonhole principle - if there are several things that are matched up regression to the mean phlogiston theory is a superseded scientific theory that postulated the existence of a fire-like element called phlogiston Laplace's demon was a notable published articulation of causal determinism on a scientific basis by Pierre-Simon Laplace in 1814.[1] According to determinism, if someone (the demon) knows the precise location and momentum of every atom in the universe, their past and future values for any given time are entailed; they can be calculated from the laws of classical mechanics. @@ -1043,7 +1072,6 @@ possible names for tech https://en.wikipedia.org/wiki/High-entropy_alloys https://en.wikipedia.org/wiki/Refractory_metals https://en.wikipedia.org/wiki/Upper-atmospheric_lightning#Elves - entanglement prion quine - self replicating protein Unitarity - https://en.wikipedia.org/wiki/Unitarity_(physics) - all probabilities add up to 1, calculations work the same forward and backwards in time this is violated by expansion of the universe