diff --git a/js/bullet.js b/js/bullet.js index 72ba461..7f50098 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -1519,7 +1519,7 @@ const b = { if (this.pickUpTarget) { if (tech.isReel && this.blockDist > 150) { // console.log(0.0003 * Math.min(this.blockDist, 1000)) - m.energy += 0.0009 * Math.min(this.blockDist, 800) //max 0.352 energy + m.energy += 0.00113 * Math.min(this.blockDist, 800) //max 0.352 energy simulation.drawList.push({ //add dmg to draw queue x: m.pos.x, y: m.pos.y, diff --git a/js/index.js b/js/index.js index 3c216a6..633155b 100644 --- a/js/index.js +++ b/js/index.js @@ -129,6 +129,19 @@ function vertexCollision(v1, v1End, domains) { //= [map, body, [playerBody, pla return best } +// prompts to reload and exit for JUNK tech named "beforeunload" +function beforeUnloadEventListener(event) { + event.preventDefault(); + if (tech.isExitPrompt) { + tech.damage *= 1.25 + simulation.makeTextLog(`damage *= ${1.25}`) + if (Math.random() < 0.25) { + removeEventListener('beforeunload', beforeUnloadEventListener); + } + } +} +// addEventListener('beforeunload', beforeUnloadEventListener); + //collision groups // cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.mobShield | cat.phased @@ -425,6 +438,7 @@ const build = { pauseGrid() { build.generatePauseLeft() //makes the left side of the pause menu with the tech build.generatePauseRight() //makes the right side of the pause menu with the tech + // build.sortTech('') //sorts tech into the order the player got them using tech.tech[i].cycle = m.cycle document.getElementById("tech").style.display = "none" document.getElementById("guns").style.display = "none" document.getElementById("field").style.display = "none" @@ -436,15 +450,6 @@ const build = { simulation.lastLogTime = m.cycle //hide in game console }, generatePauseLeft() { - //used for junk estimation - let junkCount = 0 - let totalCount = 1 //start at one to avoid NaN issues - 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 - } - } //left side let botText = "" if (tech.nailBotCount) botText += `
nail-bots: ${tech.nailBotCount}` @@ -487,7 +492,7 @@ ${botText} mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})
tech: ${tech.totalCount}   research: ${powerUps.research.count} velocity: (${player.velocity.x.toFixed(3)}, ${player.velocity.y.toFixed(3)}) -${junkCount ? `
JUNK: ${(junkCount / totalCount * 100).toFixed(1)}% ` : ""} +${tech.junkChance ? `
JUNK: ${(100 * tech.junkChance).toFixed(1)}% ` : ""}

level: ${level.levelsCleared} ${level.levels[level.onLevel]} (${level.difficultyText()})
mobs: ${spawn.pickList[0]}, ${spawn.pickList[0]} @@ -542,14 +547,6 @@ ${simulation.isCheating ? "

lore disabled" : ""} el.innerHTML = text }, generatePauseRight() { - //right side - // - // - - // - // - - // let text = `
@@ -560,38 +557,13 @@ ${simulation.isCheating ? "

lore disabled" : ""}
`; - // const style = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'style="animation: techColorCycle 1s linear infinite alternate;"' : '' const ejectClass = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'pause-eject' : '' for (let i = 0, len = tech.tech.length; i < len; i++) { if (tech.tech[i].count > 0) { - // const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; - // if (tech.tech[i].isNonRefundable) { - // text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - // } else if (tech.tech[i].isFieldTech) { - // text += `
- // - //
- //
- //
- //         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - // } else if (tech.tech[i].isGunTech) { - // text += `
- // - //
- //
- //
- //         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - // } else if (tech.tech[i].isLore) { - // text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - // } else { - // text += `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - // } const style = (localSettings.isHideImages || tech.tech[i].isJunk || tech.tech[i].isLore) ? `style="height:auto;"` : `style = "background-image: url('img/${tech.tech[i].name}.webp');"` const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; if (tech.tech[i].isNonRefundable) { text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}
` - // } else if (tech.tech[i].isLore) { - // text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` } else if (tech.tech[i].isFieldTech) { text += `
` text += build.fieldTechText(i) + "
" @@ -601,6 +573,9 @@ ${simulation.isCheating ? "

lore disabled" : ""} } else if (tech.tech[i].isSkin) { text += `
` text += build.skinTechText(i) + "
" + } else if (tech.tech[i].isJunk) { + text += `
` + text += build.junkTechText(i) + "
" } else { text += `
` text += build.techText(i) + "
" @@ -612,6 +587,17 @@ ${simulation.isCheating ? "

lore disabled" : ""} const el = document.getElementById("pause-grid-right") el.style.display = "grid" el.innerHTML = text + + //add event listener for pressing enter key when in sort + function pressEnterSort(event) { + if (event.key === 'Enter') { + requestAnimationFrame(() => { document.getElementById("sort-input").focus(); }); + // event.preventDefault(); // Prevent the default action to avoid form submission or any other default action + build.sortTech('input') + } + } + document.getElementById("sort-input").addEventListener('keydown', pressEnterSort); + requestAnimationFrame(() => { document.getElementById("sort-input").focus(); }); }, sortTech(find, isExperiment = false) { const sortKeyword = (a, b) => { @@ -621,6 +607,16 @@ ${simulation.isCheating ? "

lore disabled" : ""} if (!aHasKeyword && bHasKeyword) return 1; return 0; } + + // if (find === '') { + // tech.tech.sort((a, b) => { //sorts tech into the order the player got them using tech.tech[i].cycle = m.cycle + // console.log(a.cycle, b.cycle) + // if (a.cycle === undefined && b.cycle !== undefined) return -1; + // if (a.cycle !== undefined && b.cycle === undefined) return 1; + // if (a.cycle === undefined && b.cycle === undefined) return 0; + // if (a.cycle !== b.cycle) return a.cycle - b.cycle; + // }); + // } else if (find === 'guntech') { tech.tech.sort((a, b) => { if (a.isGunTech && b.isGunTech) { @@ -704,6 +700,7 @@ ${simulation.isCheating ? "

lore disabled" : ""} build.generatePauseRight() //makes the right side of the pause menu with the tech } document.getElementById("sort-input").value = find; //make the sorted string display in the keyword search input field + simulation.updateTechHUD(); }, unPauseGrid() { document.getElementById("guns").style.display = "inline" @@ -961,10 +958,17 @@ ${simulation.isCheating ? "

lore disabled" : ""} } } document.getElementById("experiment-grid").innerHTML = text - // for (let i = 0, len = tech.tech.length; i < len; i++) { - // if (tech.tech[i].count) - // document.getElementById("tech-" + i).classList.add("build-tech-selected") - // } + + + + //add event listener for pressing enter key when in sort + function pressEnterSort(event) { + if (event.key === 'Enter') { + // event.preventDefault(); // Prevent the default action to avoid form submission or any other default action + build.sortTech('input', true) + } + } + document.getElementById("sort-input").addEventListener('keydown', pressEnterSort); document.getElementById("difficulty-select-experiment").value = document.getElementById("difficulty-select").value document.getElementById("difficulty-select-experiment").addEventListener("input", () => { @@ -1348,12 +1352,15 @@ window.addEventListener("keydown", function (event) { simulation.previousGun(); break case input.key.pause: - if (!simulation.isChoosing && input.isPauseKeyReady && m.alive) { + + if (input.isPauseKeyReady && m.alive && !build.isExperimentSelection) { input.isPauseKeyReady = false - setTimeout(function () { - input.isPauseKeyReady = true - }, 300); - if (simulation.paused) { + setTimeout(function () { input.isPauseKeyReady = true }, 300); + if (simulation.isChoosing) { + + build.pauseGrid() + + } else if (simulation.paused) { build.unPauseGrid() simulation.paused = false; // level.levelAnnounce(); @@ -1404,7 +1411,7 @@ window.addEventListener("keydown", function (event) { } break case input.key.testing: - if (m.alive && localSettings.loreCount > 0 && !simulation.paused) { + if (m.alive && localSettings.loreCount > 0 && !simulation.paused && !build.isExperimentSelection) { if (simulation.difficultyMode > 4) { simulation.makeTextLog("testing mode disabled for this difficulty"); break diff --git a/js/level.js b/js/level.js index cfb4fba..884f39a 100644 --- a/js/level.js +++ b/js/level.js @@ -33,26 +33,25 @@ const level = { // m.energy = 0 // simulation.molecularMode = 2 // m.damage(0.1); - // b.giveGuns("drones") //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("mine") //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("laser") //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[8].ammo = 100000000 - // requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") }); - // for (let i = 0; i < 1; ++i) tech.giveTech("flame test") - // for (let i = 0; i < 1; ++i) tech.giveTech("dazzler") - // for (let i = 0; i < 1; ++i) tech.giveTech("mass production") - // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") }); + // requestAnimationFrame(() => { tech.giveTech("eternalism") }); + // for (let i = 0; i < 1; ++i) tech.giveTech("beforeunload") + // for (let i = 0; i < 1; ++i) tech.giveTech("Sleipnir") + // for (let i = 0; i < 1; ++i) tech.giveTech("dark patterns") + // requestAnimationFrame(() => { for (let i = 0; i < 1; i++) tech.giveTech("paradigm shift") }); // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) }); // m.skin.hexagon(); - // for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide") // m.lastKillCycle = m.cycle - // for (let i = 0; i < 1; ++i) tech.giveTech("swarf") + // for (let i = 0; i < 1; ++i) tech.giveTech("what the block?") // for (let i = 0; i < 1; ++i) tech.giveTech("unified field theory") // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research"); // for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); // spawn.mapRect(575, -700, 25, 425); //block mob line of site on testing - // level.testing(); + // level.testChamber(); // for (let i = 0; i < 1; ++i) spawn.laserLayer(1400, -500) // Matter.Body.setPosition(player, { x: -200, y: -3330 }); @@ -75,7 +74,7 @@ const level = { // simulation.isAutoZoom = false; //look in close // simulation.zoomScale *= 0.5; // simulation.setZoom(); - // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); + // for (let i = 0; i < 10; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "boost"); // for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "heal"); // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false); @@ -1570,7 +1569,6 @@ const level = { } } } - // if (body.length) { for (let i = 0, len = body.length; i < len; i++) { if (body[i] !== m.holdingTarget) { // body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100 @@ -1591,17 +1589,20 @@ const level = { } //rotate velocity let mag - if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up + if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires up mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11 + let v = Vector.mult(this.portalPair.unit, mag) + //rotate the velocity vector of blocks fired directly up to keep them from getting stuck endlessly in vertical portals + Matter.Body.setVelocity(body[i], Vector.rotate(v, 0.5 * (Math.random() - 0.5))); } else { mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity))) + let v = Vector.mult(this.portalPair.unit, mag) + Matter.Body.setVelocity(body[i], v); } - let v = Vector.mult(this.portalPair.unit, mag) - Matter.Body.setVelocity(body[i], v); + } } } - // } //remove block if touching // if (body.length) { diff --git a/js/player.js b/js/player.js index afdab53..e65d5af 100644 --- a/js/player.js +++ b/js/player.js @@ -362,10 +362,10 @@ const m = { // tech.removeLoreTechFromPool(); // tech.addLoreTechToPool(); // tech.removeJunkTechFromPool(); + tech.junkChance = 0; tech.duplication = 0; tech.extraMaxHealth = 0; tech.totalCount = 0; - tech.countJunkTech(); const randomBotCount = b.totalBots() b.zeroBotCount() //remove all bullets, respawn bots @@ -547,7 +547,6 @@ const m = { if (m.health > m.maxHealth) m.health = m.maxHealth; m.displayHealth(); }, - defaultFPSCycle: 0, //tracks when to return to normal fps immuneCycle: 0, //used in engine lastCalculatedDamage: 0, //used to decided if damage bar needs to be redrawn (in simulation.checks) @@ -2329,7 +2328,8 @@ const m = { m.isHolding = false } }, - throwBlock() { + throwBlock() { }, + throwBlockDefault() { if (m.holdingTarget) { if (input.field) { if (m.energy > 0.001) { @@ -2478,6 +2478,116 @@ const m = { m.isHolding = false } }, + throwSelf() { + if (m.holdingTarget) { + if (input.field) { + if (m.energy > 0.001) { + if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle + if (tech.isCapacitor && m.throwCharge < 4) m.throwCharge = 4 + m.throwCharge += 0.5 / m.holdingTarget.mass / b.fireCDscale + if (m.throwCharge < 6) m.energy -= 0.001 / b.fireCDscale; // m.throwCharge caps at 5 + + //trajectory path prediction + //draw charge + const x = m.pos.x + 15 * Math.cos(m.angle); + const y = m.pos.y + 15 * Math.sin(m.angle); + const len = m.holdingTarget.vertices.length - 1; + const edge = m.throwCharge * m.throwCharge * m.throwCharge; + const grd = ctx.createRadialGradient(x, y, edge, x, y, edge + 5); + grd.addColorStop(0, "rgba(255,50,150,0.3)"); + grd.addColorStop(1, "transparent"); + ctx.fillStyle = grd; + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(m.holdingTarget.vertices[len].x, m.holdingTarget.vertices[len].y); + ctx.lineTo(m.holdingTarget.vertices[0].x, m.holdingTarget.vertices[0].y); + ctx.fill(); + for (let i = 0; i < len; i++) { + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(m.holdingTarget.vertices[i].x, m.holdingTarget.vertices[i].y); + ctx.lineTo(m.holdingTarget.vertices[i + 1].x, m.holdingTarget.vertices[i + 1].y); + ctx.fill(); + } + //trajectory prediction + const cycles = 30 + const charge = Math.min(m.throwCharge / 5, 1) + const speed = (tech.isPrinter ? 15 + 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.1)) : 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25))) + const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } + ctx.beginPath() + for (let i = 1, len = 10; i < len + 1; i++) { + const time = cycles * i / len + ctx.lineTo(m.pos.x + time * v.x, m.pos.y + time * v.y + 0.34 * time * time) + } + ctx.strokeStyle = "rgba(68, 68, 68, 0.15)" //color.map + ctx.lineWidth = 2 + ctx.stroke() + + } else { + m.drop() + } + } else if (m.throwCharge > 0) { //Matter.Query.region(mob, player.bounds) + if (m.holdingTarget.isPrinted) m.holdingTarget.isPrinted = undefined + //throw the body + m.fieldCDcycle = m.cycle + 20; + m.fireCDcycle = m.cycle + 20; + + m.isHolding = false; + //bullet-like collisions + m.holdingTarget.collisionFilter.category = cat.bullet + m.holdingTarget.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield; + if (tech.isBlockRestitution) { + m.holdingTarget.restitution = 0.999 //extra bouncy + m.holdingTarget.friction = m.holdingTarget.frictionStatic = m.holdingTarget.frictionAir = 0.001 + } + //check every second to see if player is away from thrown body, and make solid + const solid = function (that) { + const dx = that.position.x - player.position.x; + const dy = that.position.y - player.position.y; + // if (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) { + if (dx * dx + dy * dy > 10000 && that !== m.holdingTarget) { + that.collisionFilter.category = cat.body; //make solid + that.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; //can hit player now + } else { + setTimeout(solid, 40, that); + } + }; + setTimeout(solid, 200, m.holdingTarget); + + const charge = Math.min(m.throwCharge / 5, 1) + //***** scale throw speed with the first number, 80 ***** + // let speed = 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25)); + let speed = (tech.isPrinter ? 15 + 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.1)) : 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25))) + + + m.throwCharge = 0; + m.throwCycle = m.cycle + 180 //used to detect if a block was thrown in the last 3 seconds + Matter.Body.setVelocity(m.holdingTarget, { + x: Math.cos(m.angle) * speed / (m.crouch ? 30 : 10) * Math.sqrt(m.holdingTarget.mass), + y: player.velocity.y - Math.sin(m.angle) * speed / 30 * Math.sqrt(m.holdingTarget.mass) + }); + Matter.Body.setVelocity(player, { + x: player.velocity.x - player.velocity.x * 0.5 + Math.cos(m.angle) * speed, + y: player.velocity.y - player.velocity.y * 0.5 + Math.sin(m.angle) * speed + }); + m.definePlayerMass() //return to normal player mass + + if (tech.isAddBlockMass) { + const expand = function (that, massLimit) { + if (that.mass < massLimit) { + const scale = 1.04; + Matter.Body.scale(that, scale, scale); + setTimeout(expand, 20, that, massLimit); + } + }; + expand(m.holdingTarget, Math.min(20, m.holdingTarget.mass * 3)) + } + + } + } else { + m.isHolding = false + } + }, drawField() { if (m.holdingTarget) { ctx.fillStyle = "rgba(110,170,200," + (m.energy * (0.05 + 0.05 * Math.random())) + ")"; diff --git a/js/powerup.js b/js/powerup.js index c836f6e..d70b30a 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -326,7 +326,7 @@ const powerUps = { return } if (tech.isCancelDuplication) { - tech.duplication += 0.047 + tech.duplication += 0.05 tech.maxDuplicationEvent() simulation.makeTextLog(`tech.duplicationChance() += ${0.043}`) simulation.circleFlare(0.043); @@ -344,7 +344,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.spawnDelay("coupling", 6) + if (tech.isCancelCouple) powerUps.spawnDelay("coupling", 8) // 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`) @@ -958,9 +958,6 @@ const powerUps = { if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i) } if (botTech.length > 0) { //pick random bot tech - // const choose = botTech[Math.floor(Math.random() * botTech.length)]; - // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; - // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` @@ -1024,9 +1021,6 @@ const powerUps = { if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i) } if (botTech.length > 0) { //pick random bot tech - // const choose = botTech[Math.floor(Math.random() * botTech.length)]; - // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; - // text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` @@ -1051,14 +1045,10 @@ const powerUps = { effect() { if (m.alive) { // powerUps.animatePowerUpGrab('hsla(246, 100%, 77%,0.5)') - let junkCount = 0 //used for junk estimation - let totalCount = 0 //used for junk estimation 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); } @@ -1110,20 +1100,28 @@ const powerUps = { if (i === 0) simulation.makeTextLog(`options.length = ${optionLengthNoDuplicates} //tech removed from pool by decoherence`) } removeOption(choose) //move from future options pool to avoid repeats on this selection - tech.tech[choose].isRecentlyShown = true //this flag prevents this option from being shown the next time you pick up a tech power up - const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; - if (tech.tech[choose].isFieldTech) { - text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`) - } else if (tech.tech[choose].isGunTech) { - text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`) - } else if (tech.tech[choose].isJunk) { - text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`) - } else if (tech.tech[choose].isSkin) { - text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`) - } else { //normal tech - text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`) + tech.tech[choose].isRecentlyShown = true //this flag prevents this option from being shown the next time you pick up a tech power up + if (Math.random() < tech.junkChance) { // choose is set to a random JUNK tech + const list = [] + for (let i = 0; i < tech.tech.length; i++) { + if (tech.tech[i].isJunk) list.push(i) + } + chooseJUNK = list[Math.floor(Math.random() * list.length)] + text += powerUps.junkTechText(chooseJUNK, `powerUps.choose('tech',${chooseJUNK})`) + } else { + if (tech.tech[choose].isFieldTech) { + text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`) + } else if (tech.tech[choose].isGunTech) { + text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`) + } else if (tech.tech[choose].isJunk) { + text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`) + } else if (tech.tech[choose].isSkin) { + text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`) + } else { //normal tech + text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`) + } + if (options.length < 1) break } - if (options.length < 1) break } if (tech.isExtraBotOption) { const botTech = [] //make an array of bot options diff --git a/js/simulation.js b/js/simulation.js index 1dfeb9c..70d5bb4 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -418,6 +418,15 @@ const simulation = { simulation.boldActiveGunHUD(); }, updateTechHUD() { + + // tech.tech.sort((a, b) => { + // console.log(a.cycle, b.cycle) + // if (a.cycle === undefined && b.cycle !== undefined) return -1; + // if (a.cycle !== undefined && b.cycle === undefined) return 1; + // if (a.cycle === undefined && b.cycle === undefined) return 0; + // if (a.cycle !== b.cycle) return a.cycle - b.cycle; + // }); + let text = "" for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech if (tech.tech[i].isLost) { diff --git a/js/tech.js b/js/tech.js index aaf08b3..533ba52 100644 --- a/js/tech.js +++ b/js/tech.js @@ -29,9 +29,9 @@ const tech = { // tech.removeJunkTechFromPool(); // tech.removeLoreTechFromPool(); // tech.addLoreTechToPool(); + tech.junkChance = 0; tech.extraMaxHealth = 0; tech.totalCount = 0; - tech.junkCount = 0 //tech.countJunkTech(); simulation.updateTechHUD(); simulation.updateGunHUD(); }, @@ -63,7 +63,6 @@ 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(); @@ -82,36 +81,41 @@ const tech = { // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1) // } // }, + junkChance: 0, addJunkTechToPool(percent) { //percent is number between 0-1 - tech.junkPoolPercent += percent + tech.junkChance += (1 - tech.junkChance) * percent + return percent //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); - } - if (options.length) { - 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 = 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 - } else { - return 0 - } + // 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); + // } + // if (options.length) { + // 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 = 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 + // } else { + // return 0 + // } }, - removeJunkTechFromPool(num = 1) { - for (let j = 0; j < num; j++) { - for (let i = 0; i < tech.tech.length; i++) { - if (tech.tech[i].isJunk && tech.tech[i].frequency > 0 && tech.tech[i].count < tech.tech[i].maxCount) { - tech.tech[i].frequency-- - break - } - } + removeJunkTechFromPool(percent) { + // for (let j = 0; j < num; j++) { + // for (let i = 0; i < tech.tech.length; i++) { + // if (tech.tech[i].isJunk && tech.tech[i].frequency > 0 && tech.tech[i].count < tech.tech[i].maxCount) { + // tech.tech[i].frequency-- + // break + // } + // } + // } + if (percent > 0) { + tech.junkChance = (tech.junkChance - percent) / (1 - percent) + if (tech.junkChance < 0.001 || tech.junkChance === undefined) tech.junkChance = 0 } - tech.junkPoolPercent = 0 }, giveRandomJUNK() { const list = [] @@ -123,6 +127,10 @@ const tech = { simulation.makeTextLog(`tech.giveTech("${name}")`); }, giveTech(index = 'random') { + // if (Math.random() < tech.junkChance) { + // tech.giveRandomJUNK(); + // return + // } if (index === 'random') { let options = []; for (let i = 0; i < tech.tech.length; i++) { @@ -157,27 +165,20 @@ const tech = { if (tech.isBanish && tech.tech[index].isBanished) tech.tech[index].isBanished = false //stops the bug where you can't gets stacks of tech you take with decoherence, I think tech.tech[index].effect(); //give specific tech tech.tech[index].count++ + // tech.tech[index].cycle = m.cycle + console.log(tech.tech[index].cycle) tech.totalCount++ //used in power up randomization - tech.countJunkTech(); + //move new tech to the top of the tech list + if (index > 0) { + // Remove the element from the array + const [item] = tech.tech.splice(index, 1); + // Add the element to the front of the array + tech.tech.unshift(item); + } + simulation.updateTechHUD(); } }, - junkPoolPercent: 0, - 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) { - // tech.tech[i].isNonRefundable = true; - // return - // } - // } - // }, setCheating() { if (!simulation.isCheating) { simulation.isCheating = true; @@ -261,7 +262,7 @@ const tech = { if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3; if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit * (2 - m.defense()) // if (!simulation.paused) m.lastHit = 0 if (tech.isLowHealthDmg) dmg *= 1 + 0.7 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health)) - if (tech.isJunkDNA) dmg *= 1 + tech.junkPoolPercent + if (tech.isJunkDNA) dmg *= 1 + 2 * tech.junkChance return dmg }, duplicationChance() { @@ -536,7 +537,9 @@ const tech = { name: "depolarization", descriptionFunction() { // return `+300% damage or -50% damage
if a mob has died in the last 5 seconds` - return `+333% damage if no mobs died in the last ${(tech.isDamageCooldownTime / 60).toFixed(0)} seconds
-55% damage if a mob died in the last ${(tech.isDamageCooldownTime / 60).toFixed(0)} seconds
` + // return `+333% damage if no mobs died in the last ${(tech.isDamageCooldownTime / 60).toFixed(1)} seconds
-55% damage if a mob died in the last ${(tech.isDamageCooldownTime / 60).toFixed(0)} seconds
` + // return `-55% damage if a mob died in the last ${(tech.isDamageCooldownTime / 60).toFixed(1)} seconds
otherwise do +333% damage
` + return `-55% damage for ${(tech.isDamageCooldownTime / 60).toFixed(1)} seconds after a mob dies
+333% damage otherwise
` }, maxCount: 1, count: 0, @@ -559,7 +562,7 @@ const tech = { { name: "hyperpolarization", descriptionFunction() { - return `the damage from depolarization
resets 1 second sooner after a mob has died` + return `the damage from depolarization
resets 1.25 seconds sooner after a mob dies` }, maxCount: 3, count: 0, @@ -570,7 +573,7 @@ const tech = { }, requires: "depolarization", effect() { - tech.isDamageCooldownTime -= 60 + tech.isDamageCooldownTime -= 75 }, remove() { tech.isDamageCooldownTime = 240 @@ -661,7 +664,7 @@ const tech = { }, { name: "ordnance", - description: "double the frequency of finding guntech
spawn a gun and +7% JUNK to tech pool", + description: "double the frequency of finding guntech
spawn a gun and +6% JUNK to tech pool", maxCount: 1, count: 0, frequency: 1, @@ -675,7 +678,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.07) + this.refundAmount += tech.addJunkTechToPool(0.06) }, refundAmount: 0, remove() { @@ -2915,7 +2918,7 @@ const tech = { }, { name: "overcharge", - description: "+66 maximum energy
+5% JUNK to tech pool", + description: "+88 maximum energy
+5% JUNK to tech pool", maxCount: 9, count: 0, frequency: 1, @@ -3942,7 +3945,7 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return tech.junkCount > 0 + return tech.junkChance > 0 }, requires: "some JUNK tech", effect() { @@ -3954,7 +3957,7 @@ const tech = { }, { name: "dark patterns", - description: "+22% damage
+22% JUNK to tech pool", + description: "+22% damage
+11% JUNK to tech pool", maxCount: 9, count: 0, frequency: 1, @@ -3966,7 +3969,7 @@ const tech = { damage: 1.22, effect() { tech.damage *= this.damage - this.refundAmount += tech.addJunkTechToPool(0.22) + this.refundAmount += tech.addJunkTechToPool(0.11) }, refundAmount: 0, remove() { @@ -3979,29 +3982,21 @@ const tech = { { name: "junk DNA", descriptionFunction() { - // return ` +100% ${b.guns[6].nameString()} damage per JUNKtech (${(100 * tech.junkCount).toFixed(0)}%)
+33% JUNK to tech pool` - return `damage scales with JUNK tech pool percent` + return `increase damage by twice the
JUNK tech pool percent (${(200 * tech.junkChance).toFixed(0)}%)` }, - // isGunTech: true, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return tech.junkPoolPercent > 0 + return tech.junkChance > 0 }, requires: "JUNK in tech pool", effect() { tech.isJunkDNA = true - // this.refundAmount += tech.addJunkTechToPool(0.20) }, - // refundAmount: 0, remove() { tech.isJunkDNA = false - // if (this.count > 0 && this.refundAmount > 0) { - // tech.removeJunkTechFromPool(this.refundAmount) - // this.refundAmount = 0 - // } } }, { @@ -4246,7 +4241,7 @@ const tech = { name: "residual dipolar coupling", descriptionFunction() { // return `clicking cancel for a field, tech, or gun
spawns ${powerUps.orb.coupling(5)}that each give +0.1 coupling`//
${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling"} - return `clicking cancel spawns ${powerUps.orb.coupling(6)}
${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)}` + return `clicking cancel spawns ${powerUps.orb.coupling(8)}
${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)}` }, maxCount: 1, count: 0, @@ -4304,7 +4299,7 @@ const tech = { }, { name: "futures exchange", - description: "clicking cancel for a field, tech, or gun
gives +4.7% power up duplication chance", + description: "clicking cancel for a field, tech, or gun
gives +5% power up duplication chance", // descriptionFunction() { // return `clicking × to cancel a field, tech, or gun
gives +${4.9 - 0.15*simulation.difficultyMode}% power up duplication chance` // }, @@ -4327,7 +4322,7 @@ const tech = { }, { name: "replication", - description: "+10% chance to duplicate spawned power ups
+33% JUNK to tech pool", + description: "+10% chance to duplicate spawned power ups
+22% JUNK to tech pool", maxCount: 9, count: 0, frequency: 1, @@ -4339,8 +4334,8 @@ const tech = { effect() { tech.duplicateChance += 0.1 powerUps.setPowerUpMode(); //needed after adjusting duplication chance - if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11); - this.refundAmount += tech.addJunkTechToPool(0.33) + if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.1); + this.refundAmount += tech.addJunkTechToPool(0.22) }, refundAmount: 0, remove() { @@ -4677,30 +4672,6 @@ const tech = { }, remove() { } }, - { - name: "reinforcement learning", - description: "increase the frequency of finding copies of
your current tech by 1000%", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return tech.totalCount > 9 - }, - requires: "at least 10 tech", - effect() { - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10 - } - }, - remove() { - if (this.count) { - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 10 - } - } - } - }, // { // name: "backward induction", // descriptionFunction() { @@ -6230,10 +6201,7 @@ const tech = { requires: "mines", effect() { tech.isMineDrop = true; - if (tech.isMineDrop) b.mine(m.pos, { - x: 0, - y: 0 - }, 0) + if (tech.isMineDrop) b.mine(m.pos, { x: 0, y: 0 }, 0) this.refundAmount += tech.addJunkTechToPool(0.30) }, refundAmount: 0, @@ -9057,7 +9025,7 @@ const tech = { }, { name: "reel", - description: "+400% block collision damage
up to +75 energy after reeling in blocks", + description: "+400% block collision damage
up to +100 energy after reeling in blocks", isFieldTech: true, maxCount: 1, count: 0, @@ -9549,6 +9517,30 @@ const tech = { }, remove() { } }, + { + name: "reinforcement learning", + description: "+1000% frequency of finding copies of current tech
", + maxCount: 1, + count: 0, + frequency: 1, + isJunk: true, + allowed() { + return tech.totalCount > 9 + }, + requires: "at least 10 tech", + effect() { + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10 + } + }, + remove() { + if (this.count) { + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 10 + } + } + } + }, { name: "startle response", description: `if a threat is nearby, activate a ${powerUps.orb.boost(1)}
and lock your mouse until you press escape`, @@ -10228,6 +10220,25 @@ const tech = { }, remove() { } }, + { + name: "what the block?", + description: "throwing a block throws you instead", + maxCount: 1, + count: 0, + frequency: 0, + isNonRefundable: true, + isJunk: true, + allowed() { + return m.fieldMode !== 8 && m.fieldMode !== 9 && !tech.isTokamak + }, + requires: "not pilot wave, tokamak, wormhole", + effect() { + + }, + remove() { + m.throwBlock = m.throwBlockDefault + } + }, { name: "spinor", description: "the direction you aim is determined by your position", @@ -10599,9 +10610,7 @@ const tech = { }, requires: "", effect() { - for (let i = tech.tech.length - 1; i > 0; i--) { - if (tech.tech[i].isJunk) tech.tech[i].frequency = 0 - } + tech.junkChance = 0; }, remove() { } }, @@ -11592,6 +11601,26 @@ const tech = { }, remove() { } }, + { + name: "beforeunload", + description: "75% of the time when you attempt to exit n-gon
you are prompted to cancel or continue.
Each time you cancel gain +25% damage.", + maxCount: 1, + count: 0, + frequency: 1, + isJunk: true, + allowed() { + return tech.totalCount > 9 + }, + requires: "at least 10 tech", + effect() { + tech.isExitPrompt = true + addEventListener('beforeunload', beforeUnloadEventListener); + }, + remove() { + tech.isExitPrompt = false + if (this.count > 0) removeEventListener('beforeunload', beforeUnloadEventListener); + } + }, { name: "planetesimals", description: `play planetesimals (an asteroids-like game)
clear levels in planetesimals to spawn tech
if you die in planetesimals you die in n-gon`, @@ -12189,4 +12218,5 @@ const tech = { isDamageCooldown: null, isDamageCooldownTime: null, isPowerUpDamage: null, + isExitPrompt: null, } \ No newline at end of file diff --git a/todo.txt b/todo.txt index e6d3a66..651378c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,19 +1,41 @@ ******************************************************** NEXT PATCH ************************************************** -laserLayerBoss - sends lasers to player's location -snakes bosses - after you kill a tail piece the rest of the tails lose 5% life - this makes targeting any part of the tail a viable strategy +new tech are sorted to the top of the tech list + pause menu tech list matches the tech list in game +JUNK tech icons are properly displayed in pause +Sort interface works with enter key +bug fix: you can no longer pause or enter testing in experiment selection on text input +pressing P in power up selection menu brings up the pause menu + so you can see your tech and stats +blocks stuck in vertical portals have a bit of randomness added to their velocity to help them escape -accretion disk - 5% damage for every power up on this level - requires accretion -unified field theory has buttons to cycle field forwards or backwards when paused -iceIX range and damage increased 15% -electric tech in labs level is finally nerfed - drains energy, but doesn't do damage - pushes player away +JUNK tech chance is a raw percent chance to display a random JUNK + it was previously a specific JUNK tech directly added to the pool + this might cause bugs +JUNK tech: beforeunload - asks if you want to cancel if you exit game, if you cancel gain 25% damage, but there is a 25% chance to exit anyways +JUNK tech: what the block? - trying to throw a block, throws you instead +reinforcement learning converted into a JUNK tech +JUNK DNA - scale damage by 100->200% of JUNK pool tech percent +dark patterns 33->22% JUNK +replication 33->22% JUNK + +overcharge 66->88 max energy +residual dipolar coupling 6->8 coupling per cancel +futures exchange 4.7->5% duplication per cancel +hyperpolarization reduces polarization time by 1->1.25 seconds +reel +75->100 energy + +updated physics engine to matter.js 0.19 (from 0.18) *********************************************************** TODO ***************************************************** + +List of ways to break the game + CPT + high energy regen + research->bot fabrication-> ersatz bots -> various bot upgrades + duplication 100% + electronegativity and high energy? + boss - tracks the position, velocity, angle of power ups, blocks, and bullets it fires reactor only? will rewind time @@ -32,7 +54,7 @@ button/switch input ideas from Cocoon game draw field effect make it still functional without the field button -tech: - getting a new gun also gives you 2 random tech for that gun +tech - getting a new gun also gives you 2 random tech for that gun or a field? can these guntech tech be converted into a player choice? @@ -149,6 +171,7 @@ super-bot: fires super balls tech: after a needle hits a mobs the needle splits into 3 needles? reset your fire CD? + fire again for zero ammo 2x damage for each consecutive mob hit? mob non-combat behaviors, like Rain World @@ -277,9 +300,6 @@ Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when rel or toggle other power ups health/ammo -JUNK: what the golf? - trying to throw a block throws you instead - complete blowSuckBoss... or don't tech: laser reflections increase damage @@ -1136,6 +1156,7 @@ possible names for tech Unruh effect - accelerating makes heat/thermal particles configuration space - holds the position of everything stress–energy tensor + radioisotope thermoelectric generator - ******************************************************** CARS IMAGES ********************************************************