JUNK % and pause sort

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

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)
This commit is contained in:
landgreen
2024-03-11 20:19:37 -07:00
parent 64f2a9f081
commit 64c81cd802
8 changed files with 389 additions and 213 deletions

View File

@@ -1519,7 +1519,7 @@ const b = {
if (this.pickUpTarget) { if (this.pickUpTarget) {
if (tech.isReel && this.blockDist > 150) { if (tech.isReel && this.blockDist > 150) {
// console.log(0.0003 * Math.min(this.blockDist, 1000)) // 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 simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x, x: m.pos.x,
y: m.pos.y, y: m.pos.y,

View File

@@ -129,6 +129,19 @@ function vertexCollision(v1, v1End, domains) { //= [map, body, [playerBody, pla
return best 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 <span class='color-symbol'>*=</span> ${1.25}`)
if (Math.random() < 0.25) {
removeEventListener('beforeunload', beforeUnloadEventListener);
}
}
}
// addEventListener('beforeunload', beforeUnloadEventListener);
//collision groups //collision groups
// cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.mobShield | cat.phased // 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() { pauseGrid() {
build.generatePauseLeft() //makes the left side of the pause menu with the tech 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.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("tech").style.display = "none"
document.getElementById("guns").style.display = "none" document.getElementById("guns").style.display = "none"
document.getElementById("field").style.display = "none" document.getElementById("field").style.display = "none"
@@ -436,15 +450,6 @@ const build = {
simulation.lastLogTime = m.cycle //hide in game console simulation.lastLogTime = m.cycle //hide in game console
}, },
generatePauseLeft() { 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 //left side
let botText = "" let botText = ""
if (tech.nailBotCount) botText += `<br>nail-bots: ${tech.nailBotCount}` if (tech.nailBotCount) botText += `<br>nail-bots: ${tech.nailBotCount}`
@@ -487,7 +492,7 @@ ${botText}
<span style="float: right;">mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})</span> <span style="float: right;">mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})</span>
<br><strong class='color-m'>tech</strong>: ${tech.totalCount} &nbsp; <strong class='color-r'>research</strong>: ${powerUps.research.count} <br><strong class='color-m'>tech</strong>: ${tech.totalCount} &nbsp; <strong class='color-r'>research</strong>: ${powerUps.research.count}
<span style="float: right;">velocity: (${player.velocity.x.toFixed(3)}, ${player.velocity.y.toFixed(3)})</span> <span style="float: right;">velocity: (${player.velocity.x.toFixed(3)}, ${player.velocity.y.toFixed(3)})</span>
${junkCount ? `<br><strong class='color-junk'>JUNK</strong>: ${(junkCount / totalCount * 100).toFixed(1)}% ` : ""} ${tech.junkChance ? `<br><strong class='color-junk'>JUNK</strong>: ${(100 * tech.junkChance).toFixed(1)}% ` : ""}
<br> <br>
<br>level: ${level.levelsCleared} ${level.levels[level.onLevel]} (${level.difficultyText()}) <br>level: ${level.levelsCleared} ${level.levels[level.onLevel]} (${level.difficultyText()})
<br>mobs: ${spawn.pickList[0]}, ${spawn.pickList[0]} <br>mobs: ${spawn.pickList[0]}, ${spawn.pickList[0]}
@@ -542,14 +547,6 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
el.innerHTML = text el.innerHTML = text
}, },
generatePauseRight() { generatePauseRight() {
//right side
// <input onclick="" type="checkbox" id="sort-damage" name="sort-damage" style="width:1em; height:1em;">
// <label for="sort-damage" title="sort tech by damage"><strong class='color-d'>damage</strong></label>
// <input onclick="build.sortTech('guntech')" type="checkbox" id="sort-guntech" name="sort-guntech" style="width:1em; height:1em;">
// <label for="sort-guntech" title="sort guntech"> <strong class='color-g'>gun</strong><strong class='color-m'>tech</strong></label>
// <button onclick="build.sortTech('bot')" class='sort-button'><strong class='color-bot'>bot</strong></button>
let text = `<div class="sort"> let text = `<div class="sort">
<button onclick="build.sortTech('damage')" class='sort-button'><strong class='color-d'>damage</strong></button> <button onclick="build.sortTech('damage')" class='sort-button'><strong class='color-d'>damage</strong></button>
<button onclick="build.sortTech('guntech')" class='sort-button'><strong class='color-g'>gun</strong><strong class='color-m'>tech</strong></button> <button onclick="build.sortTech('guntech')" class='sort-button'><strong class='color-g'>gun</strong><strong class='color-m'>tech</strong></button>
@@ -560,38 +557,13 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
<input type="search" id="sort-input" style="width: 8em;font-size: 0.6em;color:#000;" placeholder="sort by"/> <input type="search" id="sort-input" style="width: 8em;font-size: 0.6em;color:#000;" placeholder="sort by"/>
<button onclick="build.sortTech('input')" class='sort-button' style="border-radius: 0em;border: 1.5px #000 solid;font-size: 0.6em;" value="damage">sort</button> <button onclick="build.sortTech('input')" class='sort-button' style="border-radius: 0em;border: 1.5px #000 solid;font-size: 0.6em;" value="damage">sort</button>
</div>`; </div>`;
// const style = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'style="animation: techColorCycle 1s linear infinite alternate;"' : ''
const ejectClass = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'pause-eject' : '' const ejectClass = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'pause-eject' : ''
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].count > 0) { if (tech.tech[i].count > 0) {
// const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
// if (tech.tech[i].isNonRefundable) {
// text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" style = "border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
// } else if (tech.tech[i].isFieldTech) {
// text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" ${style}><div class="grid-title">
// <span style="position:relative;">
// <div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
// <div class="circle-grid field" style="position:absolute; top:0; left:10px;opacity:0.65;"></div>
// </span>
// &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
// } else if (tech.tech[i].isGunTech) {
// text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" ${style}><div class="grid-title">
// <span style="position:relative;">
// <div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
// <div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div>
// </span>
// &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
// } else if (tech.tech[i].isLore) {
// text += `<div class="pause-grid-module"><div class="grid-title lore-text"><div class="circle-grid lore"></div> &nbsp; ${tech.tech[i].name} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
// } else {
// text += `<div class="pause-grid-module" id ="${i}-pause-tech" onclick="powerUps.pauseEjectTech(${i})" ${style}><div class="grid-title"><div class="circle-grid tech"></div> &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
// }
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 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)` : ""; const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
if (tech.tech[i].isNonRefundable) { if (tech.tech[i].isNonRefundable) {
text += `<div class="pause-grid-module" id ="${i}-pause-tech" style = "border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding: 6px;"><div class="grid-title">${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}</div></div>` text += `<div class="pause-grid-module" id ="${i}-pause-tech" style = "border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding: 6px;"><div class="grid-title">${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}</div></div>`
// } else if (tech.tech[i].isLore) {
// text += `<div class="pause-grid-module"><div class="grid-title lore-text"><div class="circle-grid lore"></div> &nbsp; ${tech.tech[i].name} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div></div>`
} else if (tech.tech[i].isFieldTech) { } else if (tech.tech[i].isFieldTech) {
text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>` text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>`
text += build.fieldTechText(i) + "</div>" text += build.fieldTechText(i) + "</div>"
@@ -601,6 +573,9 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
} else if (tech.tech[i].isSkin) { } else if (tech.tech[i].isSkin) {
text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>` text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>`
text += build.skinTechText(i) + "</div>" text += build.skinTechText(i) + "</div>"
} else if (tech.tech[i].isJunk) {
text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>`
text += build.junkTechText(i) + "</div>"
} else { } else {
text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>` text += `<div id="${i}-pause-tech" class="pause-grid-module card-background ${ejectClass}" onclick="powerUps.pauseEjectTech(${i})" ${style}>`
text += build.techText(i) + "</div>" text += build.techText(i) + "</div>"
@@ -612,6 +587,17 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
const el = document.getElementById("pause-grid-right") const el = document.getElementById("pause-grid-right")
el.style.display = "grid" el.style.display = "grid"
el.innerHTML = text 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) { sortTech(find, isExperiment = false) {
const sortKeyword = (a, b) => { const sortKeyword = (a, b) => {
@@ -621,6 +607,16 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
if (!aHasKeyword && bHasKeyword) return 1; if (!aHasKeyword && bHasKeyword) return 1;
return 0; 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') { if (find === 'guntech') {
tech.tech.sort((a, b) => { tech.tech.sort((a, b) => {
if (a.isGunTech && b.isGunTech) { if (a.isGunTech && b.isGunTech) {
@@ -704,6 +700,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
build.generatePauseRight() //makes the right side of the pause menu with the tech 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 document.getElementById("sort-input").value = find; //make the sorted string display in the keyword search input field
simulation.updateTechHUD();
}, },
unPauseGrid() { unPauseGrid() {
document.getElementById("guns").style.display = "inline" document.getElementById("guns").style.display = "inline"
@@ -961,10 +958,17 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
} }
} }
document.getElementById("experiment-grid").innerHTML = text 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").value = document.getElementById("difficulty-select").value
document.getElementById("difficulty-select-experiment").addEventListener("input", () => { document.getElementById("difficulty-select-experiment").addEventListener("input", () => {
@@ -1348,12 +1352,15 @@ window.addEventListener("keydown", function (event) {
simulation.previousGun(); simulation.previousGun();
break break
case input.key.pause: case input.key.pause:
if (!simulation.isChoosing && input.isPauseKeyReady && m.alive) {
if (input.isPauseKeyReady && m.alive && !build.isExperimentSelection) {
input.isPauseKeyReady = false input.isPauseKeyReady = false
setTimeout(function () { setTimeout(function () { input.isPauseKeyReady = true }, 300);
input.isPauseKeyReady = true if (simulation.isChoosing) {
}, 300);
if (simulation.paused) { build.pauseGrid()
} else if (simulation.paused) {
build.unPauseGrid() build.unPauseGrid()
simulation.paused = false; simulation.paused = false;
// level.levelAnnounce(); // level.levelAnnounce();
@@ -1404,7 +1411,7 @@ window.addEventListener("keydown", function (event) {
} }
break break
case input.key.testing: 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) { if (simulation.difficultyMode > 4) {
simulation.makeTextLog("<em>testing mode disabled for this difficulty</em>"); simulation.makeTextLog("<em>testing mode disabled for this difficulty</em>");
break break

View File

@@ -33,26 +33,25 @@ const level = {
// m.energy = 0 // m.energy = 0
// simulation.molecularMode = 2 // simulation.molecularMode = 2
// m.damage(0.1); // 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.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 // b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") }); // requestAnimationFrame(() => { tech.giveTech("eternalism") });
// for (let i = 0; i < 1; ++i) tech.giveTech("flame test") // for (let i = 0; i < 1; ++i) tech.giveTech("beforeunload")
// for (let i = 0; i < 1; ++i) tech.giveTech("dazzler") // for (let i = 0; i < 1; ++i) tech.giveTech("Sleipnir")
// for (let i = 0; i < 1; ++i) tech.giveTech("mass production") // for (let i = 0; i < 1; ++i) tech.giveTech("dark patterns")
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") }); // 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) }); // requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) });
// m.skin.hexagon(); // m.skin.hexagon();
// for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide") // for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide")
// m.lastKillCycle = m.cycle // 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 < 1; ++i) tech.giveTech("unified field theory")
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // 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 < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); // 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 // 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) // for (let i = 0; i < 1; ++i) spawn.laserLayer(1400, -500)
// Matter.Body.setPosition(player, { x: -200, y: -3330 }); // Matter.Body.setPosition(player, { x: -200, y: -3330 });
@@ -75,7 +74,7 @@ const level = {
// simulation.isAutoZoom = false; //look in close // simulation.isAutoZoom = false; //look in close
// simulation.zoomScale *= 0.5; // simulation.zoomScale *= 0.5;
// simulation.setZoom(); // 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 < 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 < 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); // 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++) { for (let i = 0, len = body.length; i < len; i++) {
if (body[i] !== m.holdingTarget) { 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 // 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 //rotate velocity
let mag 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 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 { } else {
mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity))) mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity)))
}
let v = Vector.mult(this.portalPair.unit, mag) let v = Vector.mult(this.portalPair.unit, mag)
Matter.Body.setVelocity(body[i], v); Matter.Body.setVelocity(body[i], v);
} }
}
} }
} }
// }
//remove block if touching //remove block if touching
// if (body.length) { // if (body.length) {

View File

@@ -362,10 +362,10 @@ const m = {
// tech.removeLoreTechFromPool(); // tech.removeLoreTechFromPool();
// tech.addLoreTechToPool(); // tech.addLoreTechToPool();
// tech.removeJunkTechFromPool(); // tech.removeJunkTechFromPool();
tech.junkChance = 0;
tech.duplication = 0; tech.duplication = 0;
tech.extraMaxHealth = 0; tech.extraMaxHealth = 0;
tech.totalCount = 0; tech.totalCount = 0;
tech.countJunkTech();
const randomBotCount = b.totalBots() const randomBotCount = b.totalBots()
b.zeroBotCount() b.zeroBotCount()
//remove all bullets, respawn bots //remove all bullets, respawn bots
@@ -547,7 +547,6 @@ const m = {
if (m.health > m.maxHealth) m.health = m.maxHealth; if (m.health > m.maxHealth) m.health = m.maxHealth;
m.displayHealth(); m.displayHealth();
}, },
defaultFPSCycle: 0, //tracks when to return to normal fps defaultFPSCycle: 0, //tracks when to return to normal fps
immuneCycle: 0, //used in engine immuneCycle: 0, //used in engine
lastCalculatedDamage: 0, //used to decided if damage bar needs to be redrawn (in simulation.checks) lastCalculatedDamage: 0, //used to decided if damage bar needs to be redrawn (in simulation.checks)
@@ -2329,7 +2328,8 @@ const m = {
m.isHolding = false m.isHolding = false
} }
}, },
throwBlock() { throwBlock() { },
throwBlockDefault() {
if (m.holdingTarget) { if (m.holdingTarget) {
if (input.field) { if (input.field) {
if (m.energy > 0.001) { if (m.energy > 0.001) {
@@ -2478,6 +2478,116 @@ const m = {
m.isHolding = false 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() { drawField() {
if (m.holdingTarget) { if (m.holdingTarget) {
ctx.fillStyle = "rgba(110,170,200," + (m.energy * (0.05 + 0.05 * Math.random())) + ")"; ctx.fillStyle = "rgba(110,170,200," + (m.energy * (0.05 + 0.05 * Math.random())) + ")";

View File

@@ -326,7 +326,7 @@ const powerUps = {
return return
} }
if (tech.isCancelDuplication) { if (tech.isCancelDuplication) {
tech.duplication += 0.047 tech.duplication += 0.05
tech.maxDuplicationEvent() tech.maxDuplicationEvent()
simulation.makeTextLog(`tech.duplicationChance() <span class='color-symbol'>+=</span> ${0.043}`) simulation.makeTextLog(`tech.duplicationChance() <span class='color-symbol'>+=</span> ${0.043}`)
simulation.circleFlare(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); 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) { // 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); // powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "tech", false);
// simulation.makeTextLog(`<strong>options exchange</strong>: returns 1 <strong class='color-m'>tech</strong>`) // simulation.makeTextLog(`<strong>options exchange</strong>: returns 1 <strong class='color-m'>tech</strong>`)
@@ -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 (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 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 += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
const choose = botTech[Math.floor(Math.random() * botTech.length)]; const choose = botTech[Math.floor(Math.random() * botTech.length)];
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; 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');"` 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 (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 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 += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
const choose = botTech[Math.floor(Math.random() * botTech.length)]; const choose = botTech[Math.floor(Math.random() * botTech.length)];
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : ""; 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');"` const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
@@ -1051,14 +1045,10 @@ const powerUps = {
effect() { effect() {
if (m.alive) { if (m.alive) {
// powerUps.animatePowerUpGrab('hsla(246, 100%, 77%,0.5)') // 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 let options = []; //generate all options
optionLengthNoDuplicates = 0 optionLengthNoDuplicates = 0
for (let i = 0; i < tech.tech.length; i++) { 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) { 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++ if (tech.tech[i].frequency > 0) optionLengthNoDuplicates++
for (let j = 0, len = tech.tech[i].frequency; j < len; j++) options.push(i); for (let j = 0, len = tech.tech[i].frequency; j < len; j++) options.push(i);
} }
@@ -1111,7 +1101,14 @@ const powerUps = {
} }
removeOption(choose) //move from future options pool to avoid repeats on this selection 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 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 (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) { if (tech.tech[choose].isFieldTech) {
text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`) text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isGunTech) { } else if (tech.tech[choose].isGunTech) {
@@ -1125,6 +1122,7 @@ const powerUps = {
} }
if (options.length < 1) break if (options.length < 1) break
} }
}
if (tech.isExtraBotOption) { if (tech.isExtraBotOption) {
const botTech = [] //make an array of bot options const botTech = [] //make an array of bot options
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {

View File

@@ -418,6 +418,15 @@ const simulation = {
simulation.boldActiveGunHUD(); simulation.boldActiveGunHUD();
}, },
updateTechHUD() { 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 = "" let text = ""
for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech
if (tech.tech[i].isLost) { if (tech.tech[i].isLost) {

View File

@@ -29,9 +29,9 @@ const tech = {
// tech.removeJunkTechFromPool(); // tech.removeJunkTechFromPool();
// tech.removeLoreTechFromPool(); // tech.removeLoreTechFromPool();
// tech.addLoreTechToPool(); // tech.addLoreTechToPool();
tech.junkChance = 0;
tech.extraMaxHealth = 0; tech.extraMaxHealth = 0;
tech.totalCount = 0; tech.totalCount = 0;
tech.junkCount = 0 //tech.countJunkTech();
simulation.updateTechHUD(); simulation.updateTechHUD();
simulation.updateGunHUD(); simulation.updateGunHUD();
}, },
@@ -63,7 +63,6 @@ const tech = {
tech.tech[index].remove(); tech.tech[index].remove();
tech.tech[index].count = 0; tech.tech[index].count = 0;
tech.totalCount -= totalRemoved tech.totalCount -= totalRemoved
tech.countJunkTech();
simulation.updateTechHUD(); simulation.updateTechHUD();
tech.tech[index].isLost = true tech.tech[index].isLost = true
simulation.updateTechHUD(); simulation.updateTechHUD();
@@ -82,36 +81,41 @@ const tech = {
// if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1) // 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 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 //make an array for possible junk tech to add
let options = []; // let options = [];
for (let i = 0; i < tech.tech.length; i++) { // 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 (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].isJunk) options.push(i);
} // }
if (options.length) { // if (options.length) {
let countNonJunk = 0 // count total non junk tech // let countNonJunk = 0 // count total non junk tech
for (let i = 0, len = tech.tech.length; i < len; i++) { // 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 // 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 // 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 // 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(`<span class='color-var'>tech</span>.tech.push(${num.toFixed(0)} <span class='color-text'>JUNK</span>)`) // simulation.makeTextLog(`<span class='color-var'>tech</span>.tech.push(${num.toFixed(0)} <span class='color-text'>JUNK</span>)`)
return num // return num
} else { // } else {
return 0 // return 0
} // }
}, },
removeJunkTechFromPool(num = 1) { removeJunkTechFromPool(percent) {
for (let j = 0; j < num; j++) { // for (let j = 0; j < num; j++) {
for (let i = 0; i < tech.tech.length; i++) { // 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) { // if (tech.tech[i].isJunk && tech.tech[i].frequency > 0 && tech.tech[i].count < tech.tech[i].maxCount) {
tech.tech[i].frequency-- // tech.tech[i].frequency--
break // 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() { giveRandomJUNK() {
const list = [] const list = []
@@ -123,6 +127,10 @@ const tech = {
simulation.makeTextLog(`<span class='color-var'>tech</span>.giveTech("<span class='color-text'>${name}</span>")<em>`); simulation.makeTextLog(`<span class='color-var'>tech</span>.giveTech("<span class='color-text'>${name}</span>")<em>`);
}, },
giveTech(index = 'random') { giveTech(index = 'random') {
// if (Math.random() < tech.junkChance) {
// tech.giveRandomJUNK();
// return
// }
if (index === 'random') { if (index === 'random') {
let options = []; let options = [];
for (let i = 0; i < tech.tech.length; i++) { 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 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].effect(); //give specific tech
tech.tech[index].count++ tech.tech[index].count++
// tech.tech[index].cycle = m.cycle
console.log(tech.tech[index].cycle)
tech.totalCount++ //used in power up randomization 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(); 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() { setCheating() {
if (!simulation.isCheating) { if (!simulation.isCheating) {
simulation.isCheating = true; simulation.isCheating = true;
@@ -261,7 +262,7 @@ const tech = {
if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3; 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.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.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 return dmg
}, },
duplicationChance() { duplicationChance() {
@@ -536,7 +537,9 @@ const tech = {
name: "depolarization", name: "depolarization",
descriptionFunction() { descriptionFunction() {
// return `<strong>+300%</strong> <strong class='color-d'>damage</strong> or <strong>-50%</strong> <strong class='color-d'>damage</strong><br>if a mob has <strong>died</strong> in the last <strong>5 seconds</strong>` // return `<strong>+300%</strong> <strong class='color-d'>damage</strong> or <strong>-50%</strong> <strong class='color-d'>damage</strong><br>if a mob has <strong>died</strong> in the last <strong>5 seconds</strong>`
return `<span style = 'font-size:88%;'><strong>+333%</strong> <strong class='color-d'>damage</strong> if <strong>no</strong> mobs <strong>died</strong> in the last <strong>${(tech.isDamageCooldownTime / 60).toFixed(0)} seconds</strong><br><strong>-55%</strong> <strong class='color-d'>damage</strong> if a mob <strong>died</strong> in the last <strong>${(tech.isDamageCooldownTime / 60).toFixed(0)} seconds</strong></span > ` // return `<span style = 'font-size:88%;'><strong>+333%</strong> <strong class='color-d'>damage</strong> if <strong>no</strong> mobs <strong>died</strong> in the last <strong>${(tech.isDamageCooldownTime / 60).toFixed(1)} seconds</strong><br><strong>-55%</strong> <strong class='color-d'>damage</strong> if a mob <strong>died</strong> in the last <strong>${(tech.isDamageCooldownTime / 60).toFixed(0)} seconds</strong></span> `
// return `<span style = 'font-size:90%;'><strong>-55%</strong> <strong class='color-d'>damage</strong> if a mob <strong>died</strong> in the last <strong>${(tech.isDamageCooldownTime / 60).toFixed(1)} seconds</strong><br>otherwise do <strong>+333%</strong> <strong class='color-d'>damage</strong></span>`
return `<span style = 'font-size:95%;'><strong>-55%</strong> <strong class='color-d'>damage</strong> for <strong>${(tech.isDamageCooldownTime / 60).toFixed(1)} seconds</strong> after a mob <strong>dies</strong><br><strong>+333%</strong> <strong class='color-d'>damage</strong> otherwise</span>`
}, },
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -559,7 +562,7 @@ const tech = {
{ {
name: "hyperpolarization", name: "hyperpolarization",
descriptionFunction() { descriptionFunction() {
return `the <strong class= 'color-d'> damage</strong> from <strong> depolarization</strong> <br>resets <strong>1 second</strong> sooner after a mob has <strong>died</strong>` return `the <strong class= 'color-d'> damage</strong> from <strong> depolarization</strong> <br>resets <strong>1.25 seconds</strong> sooner after a mob <strong>dies</strong>`
}, },
maxCount: 3, maxCount: 3,
count: 0, count: 0,
@@ -570,7 +573,7 @@ const tech = {
}, },
requires: "depolarization", requires: "depolarization",
effect() { effect() {
tech.isDamageCooldownTime -= 60 tech.isDamageCooldownTime -= 75
}, },
remove() { remove() {
tech.isDamageCooldownTime = 240 tech.isDamageCooldownTime = 240
@@ -661,7 +664,7 @@ const tech = {
}, },
{ {
name: "ordnance", name: "ordnance",
description: "<strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-g'>gun</strong><strong class='color-m'>tech</strong><br>spawn a <strong class='color-g'>gun</strong> and <strong>+7%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool", description: "<strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-g'>gun</strong><strong class='color-m'>tech</strong><br>spawn a <strong class='color-g'>gun</strong> and <strong>+6%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -675,7 +678,7 @@ const tech = {
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2 if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2
} }
this.refundAmount += tech.addJunkTechToPool(0.07) this.refundAmount += tech.addJunkTechToPool(0.06)
}, },
refundAmount: 0, refundAmount: 0,
remove() { remove() {
@@ -2915,7 +2918,7 @@ const tech = {
}, },
{ {
name: "overcharge", name: "overcharge",
description: "<strong>+66</strong> maximum <strong class='color-f'>energy</strong><br><strong>+5%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool", description: "<strong>+88</strong> maximum <strong class='color-f'>energy</strong><br><strong>+5%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3942,7 +3945,7 @@ const tech = {
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed() { allowed() {
return tech.junkCount > 0 return tech.junkChance > 0
}, },
requires: "some JUNK tech", requires: "some JUNK tech",
effect() { effect() {
@@ -3954,7 +3957,7 @@ const tech = {
}, },
{ {
name: "dark patterns", name: "dark patterns",
description: "<strong>+22%</strong> <strong class='color-d'>damage</strong><br><strong>+22%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool", description: "<strong>+22%</strong> <strong class='color-d'>damage</strong><br><strong>+11%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3966,7 +3969,7 @@ const tech = {
damage: 1.22, damage: 1.22,
effect() { effect() {
tech.damage *= this.damage tech.damage *= this.damage
this.refundAmount += tech.addJunkTechToPool(0.22) this.refundAmount += tech.addJunkTechToPool(0.11)
}, },
refundAmount: 0, refundAmount: 0,
remove() { remove() {
@@ -3979,29 +3982,21 @@ const tech = {
{ {
name: "junk DNA", name: "junk DNA",
descriptionFunction() { descriptionFunction() {
// return ` <strong>+100%</strong> ${b.guns[6].nameString()} <strong class='color-d'>damage</strong> per <strong class='color-junk'>JUNK</strong><strong class='color-m'>tech</strong> <em>(${(100 * tech.junkCount).toFixed(0)}%)</em><br><strong>+33%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool` return `increase <strong class='color-d'>damage</strong> by twice the<br><strong class='color-junk'>JUNK</strong> <strong class='color-m'>tech</strong> pool percent <em>(${(200 * tech.junkChance).toFixed(0)}%)</em>`
return `<strong class='color-d'>damage</strong> scales with <strong class='color-junk'>JUNK</strong> <strong class='color-m'>tech</strong> pool percent`
}, },
// isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed() { allowed() {
return tech.junkPoolPercent > 0 return tech.junkChance > 0
}, },
requires: "JUNK in tech pool", requires: "JUNK in tech pool",
effect() { effect() {
tech.isJunkDNA = true tech.isJunkDNA = true
// this.refundAmount += tech.addJunkTechToPool(0.20)
}, },
// refundAmount: 0,
remove() { remove() {
tech.isJunkDNA = false 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", name: "residual dipolar coupling",
descriptionFunction() { descriptionFunction() {
// return `clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns ${powerUps.orb.coupling(5)}that each give <strong>+0.1</strong> <strong class='color-coupling'>coupling</strong>`//<br>${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per <strong class='color-coupling'>coupling</strong>"} // return `clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>spawns ${powerUps.orb.coupling(5)}that each give <strong>+0.1</strong> <strong class='color-coupling'>coupling</strong>`//<br>${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per <strong class='color-coupling'>coupling</strong>"}
return `clicking <strong class='color-cancel'>cancel</strong> spawns ${powerUps.orb.coupling(6)}<br><em>${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)}</em>` return `clicking <strong class='color-cancel'>cancel</strong> spawns ${powerUps.orb.coupling(8)}<br><em>${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)}</em>`
}, },
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -4304,7 +4299,7 @@ const tech = {
}, },
{ {
name: "futures exchange", name: "futures exchange",
description: "clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+4.7%</strong> power up <strong class='color-dup'>duplication</strong> chance", description: "clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+5%</strong> power up <strong class='color-dup'>duplication</strong> chance",
// descriptionFunction() { // descriptionFunction() {
// return `clicking <strong style = 'font-size:150%;'>×</strong> to <strong>cancel</strong> a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+${4.9 - 0.15*simulation.difficultyMode}%</strong> power up <strong class='color-dup'>duplication</strong> chance` // return `clicking <strong style = 'font-size:150%;'>×</strong> to <strong>cancel</strong> a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+${4.9 - 0.15*simulation.difficultyMode}%</strong> power up <strong class='color-dup'>duplication</strong> chance`
// }, // },
@@ -4327,7 +4322,7 @@ const tech = {
}, },
{ {
name: "replication", name: "replication",
description: "<strong>+10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+33%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool", description: "<strong>+10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+22%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -4339,8 +4334,8 @@ const tech = {
effect() { effect() {
tech.duplicateChance += 0.1 tech.duplicateChance += 0.1
powerUps.setPowerUpMode(); //needed after adjusting duplication chance powerUps.setPowerUpMode(); //needed after adjusting duplication chance
if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11); if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.1);
this.refundAmount += tech.addJunkTechToPool(0.33) this.refundAmount += tech.addJunkTechToPool(0.22)
}, },
refundAmount: 0, refundAmount: 0,
remove() { remove() {
@@ -4677,30 +4672,6 @@ const tech = {
}, },
remove() { } remove() { }
}, },
{
name: "reinforcement learning",
description: "increase the <strong class='flicker'>frequency</strong> of finding copies of<br>your current <strong class='color-m'>tech</strong> by <strong>1000%</strong>",
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", // name: "backward induction",
// descriptionFunction() { // descriptionFunction() {
@@ -6230,10 +6201,7 @@ const tech = {
requires: "mines", requires: "mines",
effect() { effect() {
tech.isMineDrop = true; tech.isMineDrop = true;
if (tech.isMineDrop) b.mine(m.pos, { if (tech.isMineDrop) b.mine(m.pos, { x: 0, y: 0 }, 0)
x: 0,
y: 0
}, 0)
this.refundAmount += tech.addJunkTechToPool(0.30) this.refundAmount += tech.addJunkTechToPool(0.30)
}, },
refundAmount: 0, refundAmount: 0,
@@ -9057,7 +9025,7 @@ const tech = {
}, },
{ {
name: "reel", name: "reel",
description: "<strong>+400%</strong> <strong class='color-block'>block</strong> collision <strong class='color-d'>damage</strong><br>up to <strong>+75</strong> <strong class='color-f'>energy</strong> after reeling in <strong class='color-block'>blocks</strong>", description: "<strong>+400%</strong> <strong class='color-block'>block</strong> collision <strong class='color-d'>damage</strong><br>up to <strong>+100</strong> <strong class='color-f'>energy</strong> after reeling in <strong class='color-block'>blocks</strong>",
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -9549,6 +9517,30 @@ const tech = {
}, },
remove() { } remove() { }
}, },
{
name: "reinforcement learning",
description: "<strong>+1000%</strong> <strong class='flicker'>frequency</strong> of finding copies of current <strong class='color-m'>tech</strong><br>",
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", name: "startle response",
description: `if a threat is nearby, activate a ${powerUps.orb.boost(1)}<br>and lock your mouse until you press escape`, description: `if a threat is nearby, activate a ${powerUps.orb.boost(1)}<br>and lock your mouse until you press escape`,
@@ -10228,6 +10220,25 @@ const tech = {
}, },
remove() { } remove() { }
}, },
{
name: "what the block?",
description: "throwing a <strong class='color-block'>block</strong> throws <strong>you</strong> 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", name: "spinor",
description: "the direction you aim is determined by your position", description: "the direction you aim is determined by your position",
@@ -10599,9 +10610,7 @@ const tech = {
}, },
requires: "", requires: "",
effect() { effect() {
for (let i = tech.tech.length - 1; i > 0; i--) { tech.junkChance = 0;
if (tech.tech[i].isJunk) tech.tech[i].frequency = 0
}
}, },
remove() { } remove() { }
}, },
@@ -11592,6 +11601,26 @@ const tech = {
}, },
remove() { } remove() { }
}, },
{
name: "beforeunload",
description: "<strong>75%</strong> of the time when you attempt to <strong>exit</strong> n-gon<br>you are prompted to <strong>cancel</strong> or continue.<br>Each time you <strong>cancel</strong> gain <strong>+25%</strong> <strong class='color-d'>damage</strong>.",
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", name: "planetesimals",
description: `play <strong>planetesimals</strong> <em style = 'font-size:80%;'>(an asteroids-like game)</em><br>clear <strong>levels</strong> in <strong>planetesimals</strong> to spawn <strong class='color-m'>tech</strong><br>if you <strong style="color:red;">die</strong> in <strong>planetesimals</strong> you <strong style="color:red;">die</strong> in <strong>n-gon</strong>`, description: `play <strong>planetesimals</strong> <em style = 'font-size:80%;'>(an asteroids-like game)</em><br>clear <strong>levels</strong> in <strong>planetesimals</strong> to spawn <strong class='color-m'>tech</strong><br>if you <strong style="color:red;">die</strong> in <strong>planetesimals</strong> you <strong style="color:red;">die</strong> in <strong>n-gon</strong>`,
@@ -12189,4 +12218,5 @@ const tech = {
isDamageCooldown: null, isDamageCooldown: null,
isDamageCooldownTime: null, isDamageCooldownTime: null,
isPowerUpDamage: null, isPowerUpDamage: null,
isExitPrompt: null,
} }

View File

@@ -1,19 +1,41 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
laserLayerBoss - sends lasers to player's location new tech are sorted to the top of the tech list
snakes bosses - after you kill a tail piece the rest of the tails lose 5% life pause menu tech list matches the tech list in game
this makes targeting any part of the tail a viable strategy 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 JUNK tech chance is a raw percent chance to display a random JUNK
requires accretion it was previously a specific JUNK tech directly added to the pool
unified field theory has buttons to cycle field forwards or backwards when paused this might cause bugs
iceIX range and damage increased 15% 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
electric tech in labs level is finally nerfed JUNK tech: what the block? - trying to throw a block, throws you instead
drains energy, but doesn't do damage reinforcement learning converted into a JUNK tech
pushes player away 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 ***************************************************** *********************************************************** 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 boss - tracks the position, velocity, angle of power ups, blocks, and bullets it fires
reactor only? reactor only?
will rewind time will rewind time
@@ -32,7 +54,7 @@ button/switch input ideas from Cocoon game
draw field effect draw field effect
make it still functional without the field button 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? or a field?
can these guntech tech be converted into a player choice? 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 tech: after a needle hits a mobs
the needle splits into 3 needles? the needle splits into 3 needles?
reset your fire CD? reset your fire CD?
fire again for zero ammo
2x damage for each consecutive mob hit? 2x damage for each consecutive mob hit?
mob non-combat behaviors, like Rain World 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 or toggle other power ups
health/ammo health/ammo
JUNK: what the golf?
trying to throw a block throws you instead
complete blowSuckBoss... or don't complete blowSuckBoss... or don't
tech: laser reflections increase damage tech: laser reflections increase damage
@@ -1136,6 +1156,7 @@ possible names for tech
Unruh effect - accelerating makes heat/thermal particles Unruh effect - accelerating makes heat/thermal particles
configuration space - holds the position of everything configuration space - holds the position of everything
stressenergy tensor stressenergy tensor
radioisotope thermoelectric generator -
******************************************************** CARS IMAGES ******************************************************** ******************************************************** CARS IMAGES ********************************************************