From 4bbd0ee223382397f69ed56614319b11ef247743 Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Sun, 16 Apr 2023 19:48:09 -0400 Subject: [PATCH 01/15] thanks, i hate debugging from an xbox --- mods/save_loading.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mods/save_loading.js b/mods/save_loading.js index 8896c030..4736b8bf 100644 --- a/mods/save_loading.js +++ b/mods/save_loading.js @@ -1,5 +1,5 @@ var modName = "mods/save_loading.js"; - +try { function zeroToNull(val) { if(val === 0) { return null }; return val; @@ -325,3 +325,6 @@ elements.save_loader = { color: "#FFFFFF", desc: saveLoaderDescription, }; +} catch (error) { + alert(`save_loading error: ${error.message}`); +}; From e3a934524c2d97fb50280ce4f4e829264377a3a9 Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Sun, 16 Apr 2023 19:54:37 -0400 Subject: [PATCH 02/15] try to fix --- mods/save_loading.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mods/save_loading.js b/mods/save_loading.js index 4736b8bf..4e9cf76d 100644 --- a/mods/save_loading.js +++ b/mods/save_loading.js @@ -319,12 +319,14 @@ Pixel size (rendering only): (Use if the save looks cut o `; -elements.save_loader = { - behavior: behaviors.SELFDELETE, - excludeRandom: true, - color: "#FFFFFF", - desc: saveLoaderDescription, -}; +runAfterLoad(function() { //somehow it gets defined before elements on xbox + elements.save_loader = { + behavior: behaviors.SELFDELETE, + excludeRandom: true, + color: "#FFFFFF", + desc: saveLoaderDescription, + }; +}); } catch (error) { alert(`save_loading error: ${error.message}`); }; From 79cd8a57c1e3dae7ec94ae4d5e4d9dcee5128ada Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Sun, 16 Apr 2023 19:57:43 -0400 Subject: [PATCH 03/15] Illogic at it again? --- mods/save_loading.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/save_loading.js b/mods/save_loading.js index 4e9cf76d..aa22a0a0 100644 --- a/mods/save_loading.js +++ b/mods/save_loading.js @@ -320,6 +320,7 @@ Pixel size (rendering only): (Use if the save looks cut o `; runAfterLoad(function() { //somehow it gets defined before elements on xbox + elements ??= {}; elements.save_loader = { behavior: behaviors.SELFDELETE, excludeRandom: true, From 7d0c00bc4551bcb600a31fe558be58d40c7c8012 Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 17 Apr 2023 13:09:55 -0400 Subject: [PATCH 04/15] test: skip undefined colors --- mods/generative_mods.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mods/generative_mods.js b/mods/generative_mods.js index 5f679f4f..ba0c3de2 100644 --- a/mods/generative_mods.js +++ b/mods/generative_mods.js @@ -1352,6 +1352,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(explodeAtPlu var returns = []; for(aaf = 0; aaf < bombElements.length; aaf++) { var elementOfBomb = bombElements[aaf]; + if(!(elements[elementOfBomb]?.color)) { continue }; var startColor; var randomExcl = 0; //console.log(elementOfBomb); @@ -1504,6 +1505,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(explodeAtPlu var returns = []; for(aaf = 0; aaf < cloudElements.length; aaf++) { var elementOfCloud = cloudElements[aaf]; + if(!(elements[elementOfCloud]?.color)) { continue }; var startColor; var randomExcl = 0; //console.log("randomExcl set") @@ -1710,6 +1712,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(explodeAtPlu var returns = []; for(aaf = 0; aaf < creeperElements.length; aaf++) { var elementOfCreeper = creeperElements[aaf]; + if(!(elements[elementOfCreeper]?.color)) { continue }; var startColor; var randomExcl = 0; //console.log("randomExcl set") @@ -1938,6 +1941,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(explodeAtPlu var returns = []; for(aaf = 0; aaf < fairyElements.length; aaf++) { var elementOfFairy = fairyElements[aaf]; + if(!(elements[elementOfFairy]?.color)) { continue }; var startColor; var randomExcl = 0; var isNocheer = 0; @@ -2125,6 +2129,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(explodeAtPlu var returns = []; for(aaf = 0; aaf < spoutElements.length; aaf++) { var elementOfSpout = spoutElements[aaf]; + if(!(elements[elementOfSpout]?.color)) { continue }; var startColor; var randomExcl = 0; var isNocheer = 0; From f37ed945d24655b29424725b09581886538fa4b0 Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 17 Apr 2023 13:10:44 -0400 Subject: [PATCH 05/15] // a log --- mods/hot_rocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/hot_rocks.js b/mods/hot_rocks.js index c101b82e..d11a71f0 100644 --- a/mods/hot_rocks.js +++ b/mods/hot_rocks.js @@ -49,7 +49,7 @@ if(enabledMods.includes(groundMod) && enabledMods.includes(libraryMod)) { } ); - console.log(igneousRocksAndSands); + //console.log(igneousRocksAndSands); function hotData2Switch(data2) { switch(data2) { From 36653836e24fde94ec44bdc6d31897758f064097 Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:18:41 -0400 Subject: [PATCH 06/15] *-ray-centric mod --- mods/rays.js | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 mods/rays.js diff --git a/mods/rays.js b/mods/rays.js new file mode 100644 index 00000000..bb689b33 --- /dev/null +++ b/mods/rays.js @@ -0,0 +1,254 @@ +var modName = "mods/rays.js"; +var runAfterAutogenMod = "mods/runAfterAutogen and onload restructure.js"; +var libraryMod = "mods/code_library.js"; + +if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) { + runAfterAutogen(function() { + snowAndIceCache = Object.keys(elements).filter(function(name) { + return name.endsWith("snow") || name.endsWith("ice") + }) + }); + lightlikes = ["light","flash","laser","radiation","insulate_flash"]; + grbBreakIntos = Object.keys(elements).filter(function(elemName) { + return elements[elemName].breakInto && elements[elemName].breakInto.includes("gamma_ray_burst"); + }); + + elements.insulate_flash = { + color: "#fffdcf", + tick: function(pixel) { + if (Math.random() < 0.75 && pixelTicks - pixel.start > 1) { + deletePixel(pixel.x, pixel.y) + } + }, + reactions: { + "blood": { elem1:"pointer" }, + "molten_stained_glass": { elem1:"rainbow" }, + "gray_goo": { elem1:"static" } + }, + category: "energy", + temp: 40, + state: "gas", + density: 1, + tempLow: -270, + stateLow: "light", + hidden: true, + noMix: true, + insulate: true + }; + + elements.heat_ray.tick = function(pixel) { + var x = pixel.x; + for (var y = pixel.y; y < height; y++) { + if (outOfBounds(x, y)) { + break; + } + if (isEmpty(x, y)) { + if (Math.random() > 0.025) { continue } + createPixel("insulate_flash", x, y); + pixelMap[x][y].color = "#ff0000"; + } + else { + if (elements[pixelMap[x][y].element].isGas) { pixelMap[x][y].temp -= 50; continue; } + if (elements[pixelMap[x][y].element].id === elements.heat_ray.id) { break } + pixelMap[x][y].temp += 100; + break; + } + } + deletePixel(pixel.x, pixel.y); + }; + + elements.sun.isSun = true; + if(elements.nellsun) { elements.nellsun.isSun = true }; + if(elements.rainbow_sun) { elements.rainbow_sun.isSun = true }; + + elements.cool_ray = { + color: ["#00ffae","#00ffff"], + tick: function(pixel) { + var x = pixel.x; + for (var y = pixel.y; y < height; y++) { + if (outOfBounds(x, y)) { + break; + } + if (isEmpty(x, y)) { + if (Math.random() > 0.05) { continue } + createPixel("insulate_flash", x, y); + pixelMap[x][y].color = "#00ffff"; + } + else { + if (elements[pixelMap[x][y].element].isGas) { + if(elements[pixelMap[x][y].element].isSun) { + pixelMap[x][y].temp -= 0.5; + } else { + pixelMap[x][y].temp -= 50; + }; + continue; + }; + if (elements[pixelMap[x][y].element].id === elements.cool_ray.id) { break } + pixelMap[x][y].temp -= 150; + break; + } + } + deletePixel(pixel.x, pixel.y); + }, + temp: -200, + category: "energy", + state: "gas", + excludeRandom: true, + noMix: true + }; + + elements.freeze_ray = { + color: ["#7fbfff","#bfffff"], + tick: function(pixel) { + var x = pixel.x; + for (var y = pixel.y; y < height; y++) { + if (outOfBounds(x, y)) { + break; + } + if (isEmpty(x, y)) { + if (Math.random() > 0.02) { continue } + createPixel("insulate_flash", x, y); + pixelMap[x][y].color = "#e1f8fc"; + } + else { + var otherPixel = pixelMap[x][y]; + var otherInfo = elements[otherPixel.element]; + //Gas: Freeze chance, cool, always penetrate + if (otherInfo.isGas) { + if(Math.random() < 0.05 && otherInfo.stateLow) { + if(otherInfo.stateLow.includes("supernova") || otherInfo.stateLow.includes("gamma_ray_burst")) { + //do nothing + } else { + freezePixel(otherPixel) + }; + }; + if(elements[otherPixel.element].isSun) { + otherPixel.temp -= 0.5; + } else { + otherPixel.temp -= 50; + }; + continue; + }; + + //Self: Break + if (otherInfo.id === elements.freeze_ray.id) { break } + + //Non-gas, Freeze chance, cool more, half penetrate + if(Math.random() < 0.05 && otherInfo.stateLow) { + if(otherInfo.stateLow.includes("supernova") || otherInfo.stateLow.includes("gamma_ray_burst")) { + //do nothing + } else { + freezePixel(otherPixel) + }; + }; + pixelMap[x][y].temp -= 150; + + if(Math.random() < 0.05) { + + if(!isEmpty(x,y-1,false)) { + if(pixelMap[x]?.[y-1]?.element && lightlikes.includes(pixelMap[x][y-1].element)) { + deletePixel(x,y-1); + }; + }; + var newSnow = tryCreatePixelReturn("snow",x,y-1); + if(newSnow) { newSnow.temp = -100 }; + }; + + //Penetrate snow and ice + if(snowAndIceCache && snowAndIceCache.includes(otherPixel.element)) { + continue; + }; + + if(Math.random() < 0.7) { //thanks, I hate random continue + continue; + }; + break; + } + } + deletePixel(pixel.x, pixel.y); + }, + temp: -200, + category: "energy", + state: "gas", + excludeRandom: true, + noMix: true + }; + + var hasVelocity = enabledMods.includes("mods/velocity.js"); + + elements.smash_ray = { + color: ["#ff9999", "#8c8279"], + tick: function(pixel) { + var x = pixel.x; + for (var y = pixel.y; y < height; y++) { + if (outOfBounds(x, y)) { + break; + } + if (isEmpty(x, y)) { + if (Math.random() > 0.05) { continue } + createPixel("flash", x, y); + pixelMap[x][y].color = "#edd0c5"; + } + else { + var otherPixel = pixelMap[x][y] + var otherInfo = elements[otherPixel.element]; + if (!(grbBreakIntos.includes(otherPixel.element))) { + if (otherInfo.isGas) { + if(Math.random() > ((otherInfo.hardness ?? 0) ** 2)) { breakPixel(otherPixel,false,false) }; + if(hasVelocity && otherPixel && !(lightlikes.includes(otherPixel.element))) { + var vels = [randomIntegerBetweenTwoValues(-7,7),randomIntegerBetweenTwoValues(-7,7)]; + otherPixel.vx = vels[0]; + otherPixel.vy = vels[1]; + }; + continue; + + }; + if (otherInfo.id === elements.heat_ray.id) { break } + if(Math.random() > ((otherInfo.hardness ?? 0) ** 2)) { breakPixel(otherPixel,false,false) }; + if(hasVelocity && otherPixel) { + var vels = [randomIntegerBetweenTwoValues(-7,7),randomIntegerBetweenTwoValues(-5,0)]; + otherPixel.vx = vels[0]; + otherPixel.vy = vels[1]; + }; + if(Math.random() < Math.max(0.8,0.3 + ((1 - (otherInfo.hardness ?? 0)) / 2))) { //thanks, I hate random continue + continue; + }; + break; + } + } + } + deletePixel(pixel.x, pixel.y); + }, + temp: -200, + category: "energy", + state: "gas", + excludeRandom: true, + noMix: true + }; + + //bless falls within god ray + elements.bless.reactions.dry_dirt = { elem2: "dirt" }; + elements.bless.reactions.dead_cum = { elem2: "cum" }; + elements.bless.reactions.dead_cum_water = { elem2: "cum_water" }; + elements.bless.reactions.dead_cum_ice = { elem2: "cum_ice" }; + elements.bless.reactions.dead_cum_water_ice = { elem2: "cum_water_ice" }; + elements.bless.reactions.dead_cum_snow = { elem2: "cum_snow" }; + elements.bless.reactions.dead_cummy_mud = { elem2: "cummy_mud" }; + elements.bless.reactions.dead_cummy_sand = { elem2: "cummy_sand" }; + elements.bless.reactions.dead_cummy_permafrost = { elem2: "cummy_permafrost" }; + elements.bless.reactions.burnt_cum = { elem2: null }; + elements.bless.reactions.poop = { elem2: null }; + elements.bless.reactions.dried_poop = { elem2: null }; + elements.bless.reactions.shit = { elem2: null }; + elements.bless.reactions.dried_shit = { elem2: null }; + elements.bless.reactions.frozen_shit = { elem2: null }; + elements.bless.reactions.diarrhea = { elem2: null }; + elements.bless.reactions.frozen_diarrhea = { elem2: null }; + elements.bless.reactions.piss = { elem2: null }; + elements.bless.reactions.vomit = { elem2: null }; +} else { + if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) }; + if(!enabledMods.includes(runAfterAutogenMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,runAfterAutogenMod) }; + localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); + alert(`The "${runAfterAutogenMod}" and "${libraryMod}" mods are required and have been automatically inserted (reload for this to take effect).`); +}; \ No newline at end of file From d99c2d40fb2e6fc008441cf1003d5004bf8da65e Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:19:32 -0400 Subject: [PATCH 07/15] hide element --- mods/rays.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/rays.js b/mods/rays.js index bb689b33..d9b50e89 100644 --- a/mods/rays.js +++ b/mods/rays.js @@ -14,6 +14,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) }); elements.insulate_flash = { + hidden: true, color: "#fffdcf", tick: function(pixel) { if (Math.random() < 0.75 && pixelTicks - pixel.start > 1) { @@ -251,4 +252,4 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) if(!enabledMods.includes(runAfterAutogenMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,runAfterAutogenMod) }; localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); alert(`The "${runAfterAutogenMod}" and "${libraryMod}" mods are required and have been automatically inserted (reload for this to take effect).`); -}; \ No newline at end of file +}; From 5ad73d9efebdbe321e3028dc3179a4976c82d2ab Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:23:17 -0400 Subject: [PATCH 08/15] ren elem --- mods/rays.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/rays.js b/mods/rays.js index d9b50e89..9dbd4904 100644 --- a/mods/rays.js +++ b/mods/rays.js @@ -62,7 +62,7 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) if(elements.nellsun) { elements.nellsun.isSun = true }; if(elements.rainbow_sun) { elements.rainbow_sun.isSun = true }; - elements.cool_ray = { + elements.cold_ray = { color: ["#00ffae","#00ffff"], tick: function(pixel) { var x = pixel.x; From fe729f26227b153677e583fa03d1590260343aca Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:44:19 -0400 Subject: [PATCH 09/15] fucking hell --- mods/save_loading.js | 688 +++++++++++++++++++++++++------------------ 1 file changed, 403 insertions(+), 285 deletions(-) diff --git a/mods/save_loading.js b/mods/save_loading.js index aa22a0a0..8ccd1af2 100644 --- a/mods/save_loading.js +++ b/mods/save_loading.js @@ -1,333 +1,451 @@ var modName = "mods/save_loading.js"; + try { -function zeroToNull(val) { - if(val === 0) { return null }; - return val; -}; + //https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API + function storageAvailable(type) { + let storage; + try { + storage = window[type]; + const x = "__storage_test__"; + storage.setItem(x, x); + storage.removeItem(x); + return true; + } catch (e) { + return ( + e instanceof DOMException && + // everything except Firefox + (e.code === 22 || + // Firefox + e.code === 1014 || + // test name field too, because code might not be present + // everything except Firefox + e.name === "QuotaExceededError" || + // Firefox + e.name === "NS_ERROR_DOM_QUOTA_REACHED") && + // acknowledge QuotaExceededError only if there's something already stored + storage && + storage.length !== 0 + ); + } + } -if(!localStorage.slSaveSettings) { - localStorage.setItem("slSaveSettings", '{"roundTemps":true}'); -}; - -slSaveSettings = JSON.parse(localStorage.slSaveSettings); - -function epsilonRound(num,precision) { - return Math.round((num + Number.EPSILON) * (10 ** precision)) / (10 ** precision); -}; - -function getSimulationState() { - var simulationState = { - //currentPixels: currentPixels, - pixelMap: structuredClone ? structuredClone(pixelMap) : JSON.parse(JSON.stringify(pixelMap)), - width: width, - height: height, - pixelSize: pixelSize, - settings: settings, - version: 1, - enabledMods: localStorage.enabledMods, + function zeroToNull(val) { + if(val === 0) { return null }; + return val; }; - for(i = 0; i < simulationState.pixelMap.length; i++) { - var column = simulationState.pixelMap[i]; - for(j = 0; j < column.length; j++) { - if(column[j] === null || typeof(column[j]) === "undefined") { - column[j] = 0; - }; + + if(!localStorage.slSaveSettings) { + localStorage.setItem("slSaveSettings", '{"roundTemps":true}'); + }; + + slSaveSettings = JSON.parse(localStorage.slSaveSettings); + + function epsilonRound(num,precision) { + return Math.round((num + Number.EPSILON) * (10 ** precision)) / (10 ** precision); + }; + + function getSimulationState() { + var simulationState = { + //currentPixels: currentPixels, + pixelMap: structuredClone ? structuredClone(pixelMap) : JSON.parse(JSON.stringify(pixelMap)), + width: width, + height: height, + pixelSize: pixelSize, + settings: settings, + version: 1, + enabledMods: localStorage.enabledMods, }; - }; - if(slSaveSettings.roundTemps) { for(i = 0; i < simulationState.pixelMap.length; i++) { var column = simulationState.pixelMap[i]; for(j = 0; j < column.length; j++) { - var pixel = column[j]; - if(pixel?.temp) { - pixel.temp = epsilonRound(pixel.temp,3); + if(column[j] === null || typeof(column[j]) === "undefined") { + column[j] = 0; }; }; }; - }; - return simulationState; -}; - -//https://stackoverflow.com/a/46118025 -function copyToClipboard(text) { - var dummy = document.createElement("textarea"); - // to avoid breaking orgain page when copying more words - // cant copy when adding below this code - // dummy.style.display = 'none' - document.body.appendChild(dummy); - //Be careful if you use textarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard - dummy.value = text; - dummy.select(); - document.execCommand("copy"); - document.body.removeChild(dummy); -} - -const saveTemplateAsFile = (filename, dataObjToWrite) => { //from https://stackoverflow.com/a/65939108 - const blob = new Blob([JSON.stringify(dataObjToWrite)], { type: "text/json" }); - const link = document.createElement("a"); - - link.download = filename; - link.href = window.URL.createObjectURL(blob); - link.dataset.downloadurl = ["text/json", link.download, link.href].join(":"); - - const evt = new MouseEvent("click", { - view: window, - bubbles: true, - cancelable: true, - }); - - link.dispatchEvent(evt); - link.remove() -}; - -function formatCurrentDate() { //derived from https://gist.github.com/Ivlyth/c4921735812dd2c0217a - var d = new Date(); - var year = d.getFullYear().toString(); - - var month = (d.getMonth()+1).toString(); - if(month.length == 1) { month = "0" + month }; - - var day = d.getDate().toString(); - if(day.length == 1) { day = "0" + day }; - - var hour = d.getHours().toString(); - if(hour.length == 1) { hour = "0" + hour }; - - var minute = d.getMinutes().toString(); - if(minute.length == 1) { minute = "0" + minute }; - - var second = d.getSeconds().toString(); - if(second.length == 1) { second = "0" + second }; - - var date_format_str = `${year}-${month}-${day} ${hour}-${minute}-${second}`; - return date_format_str; -}; - -function savePrompt() { - var filename = prompt("Please enter the desired filename, without the .json (defaults to current date)"); - if(filename === null) { - return false; - }; - if(filename === "") { - filename = `Sandboxels save ${formatCurrentDate()}`; - }; - filename += ".json"; - downloadSave(filename) -}; - -function downloadSave(filename=null) { - if(filename === null) { - filename = `Sandboxels save ${formatCurrentDate()}.json`; - }; - saveTemplateAsFile(filename, getSimulationState()); -}; - -function copySaveJSON(doAlert=true) { - copyToClipboard(JSON.stringify(getSimulationState())); - if(doAlert) { alert("Save copied as JSON") }; -}; - -function loadFile() { - //Initialize - var json; - - //load JSON - var file = document.getElementById('myfile').files[0]; - if(file === undefined) { - if(document.getElementById("fileFormStatus") !== "null") { - document.getElementById("fileFormStatus").style.color = "red"; - document.getElementById("fileFormStatus").innerHTML = "No file was uploaded!"; + if(slSaveSettings.roundTemps) { + for(i = 0; i < simulationState.pixelMap.length; i++) { + var column = simulationState.pixelMap[i]; + for(j = 0; j < column.length; j++) { + var pixel = column[j]; + if(pixel?.temp) { + pixel.temp = epsilonRound(pixel.temp,3); + }; + }; + }; }; - throw new Error("No file was uploaded"); + return simulationState; }; - var reader = new FileReader(); - reader.readAsText(file, 'UTF-8'); - //after loading - reader.onload = function(evt) { - json = evt.target.result; + + //https://stackoverflow.com/a/46118025 + function copyToClipboard(text) { + var dummy = document.createElement("textarea"); + // to avoid breaking orgain page when copying more words + // cant copy when adding below this code + // dummy.style.display = 'none' + document.body.appendChild(dummy); + //Be careful if you use textarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard + dummy.value = text; + dummy.select(); + document.execCommand("copy"); + document.body.removeChild(dummy); + } + + const saveTemplateAsFile = (filename, dataObjToWrite) => { //from https://stackoverflow.com/a/65939108 + const blob = new Blob([JSON.stringify(dataObjToWrite)], { type: "text/json" }); + const link = document.createElement("a"); + + link.download = filename; + link.href = window.URL.createObjectURL(blob); + link.dataset.downloadurl = ["text/json", link.download, link.href].join(":"); + + const evt = new MouseEvent("click", { + view: window, + bubbles: true, + cancelable: true, + }); + + link.dispatchEvent(evt); + link.remove() + }; + + function formatCurrentDate() { //derived from https://gist.github.com/Ivlyth/c4921735812dd2c0217a + var d = new Date(); + var year = d.getFullYear().toString(); + + var month = (d.getMonth()+1).toString(); + if(month.length == 1) { month = "0" + month }; + + var day = d.getDate().toString(); + if(day.length == 1) { day = "0" + day }; + + var hour = d.getHours().toString(); + if(hour.length == 1) { hour = "0" + hour }; + + var minute = d.getMinutes().toString(); + if(minute.length == 1) { minute = "0" + minute }; + + var second = d.getSeconds().toString(); + if(second.length == 1) { second = "0" + second }; + + var date_format_str = `${year}-${month}-${day} ${hour}-${minute}-${second}`; + return date_format_str; + }; + + function savePrompt() { + var filename = prompt("Please enter the desired filename, without the .json (defaults to current date)"); + if(filename === null) { + return false; + }; + if(filename === "") { + filename = `Sandboxels save ${formatCurrentDate()}`; + }; + filename += ".json"; + downloadSave(filename) + }; + + function downloadSave(filename=null) { + if(filename === null) { + filename = `Sandboxels save ${formatCurrentDate()}.json`; + }; + saveTemplateAsFile(filename, getSimulationState()); + }; + + rebuildCurrentPixels ??= function() { + var currPix = []; //rebuild currentPixels from pixelMap to try to fix bug + for(pmi = 0; pmi < pixelMap.length; pmi++) { + var pixelMapPart = pixelMap[pmi]; + for(pmj = 0; pmj < pixelMapPart.length; pmj++) { + var pixelMapUnit = pixelMapPart[pmj]; + if(typeof(pixelMapUnit) === "object") { + if(pixelMapUnit !== null) { + currPix.push(pixelMapUnit); + }; + }; + }; + }; + currentPixels = currPix; + }; + + function quicksave(doSuccessAlert=true,doFailAlert=true) { + if(storageAvailable("localStorage")) { + rebuildCurrentPixels(); + localStorage.setItem("quicksave",JSON.stringify(getSimulationState())); + if(doSuccessAlert) { alert("Quicksave saved") }; + return true; + } else { + if(doFailAlert) { alert("Could not save quicksave in localStorage") }; + throw new Error("Could not save quicksave in localStorage"); + }; + }; + + function quickload(pause=true,doSuccessAlert=true,doFailAlert=true) { + clearAll(); + rebuildCurrentPixels(); + var save = localStorage.getItem("quicksave"); + if(!save) { + if(doFailAlert) { alert("No save exists") }; + return false; + } else { + importJsonState(JSON.parse(save)); + if(doSuccessAlert) { alert("Quicksave loaded") }; + if(pause) { + paused = true; + document.getElementById("pauseButton").setAttribute("on","true"); + }; + return true; + }; + rebuildCurrentPixels(); + }; + + function copySaveJSON(doAlert=true) { + copyToClipboard(JSON.stringify(getSimulationState())); + if(doAlert) { alert("Save copied as JSON") }; + }; + + function loadFile() { + //Initialize + var json; + + //load JSON + var file = document.getElementById('myfile').files[0]; + if(file === undefined) { + if(document.getElementById("fileFormStatus") !== null) { + document.getElementById("fileFormStatus").style.color = "red"; + document.getElementById("fileFormStatus").innerHTML = "No file was uploaded!"; + }; + throw new Error("No file was uploaded"); + }; + var reader = new FileReader(); + reader.readAsText(file, 'UTF-8'); + //after loading + reader.onload = function(evt) { + json = evt.target.result; + + //validate + try { + json = JSON.parse(json); + } catch (error) { + if(document.getElementById("fileFormStatus") !== null) { + document.getElementById("fileFormStatus").style.color = "red"; + document.getElementById("fileFormStatus").innerHTML = "The file wasn't valid JSON!"; + }; + throw error; + }; + + if(document.getElementById("fileFormStatus") !== null) { + document.getElementById("fileFormStatus").style.color = "yellow"; + document.getElementById("fileFormStatus").innerHTML = "JSON was parsed successfully"; + }; + + //return json; + return importJsonState(json); + }; + }; + + function loadText() { + //Initialize + var json; + + //load JSON + var json = document.getElementById('mytext').value; + if(json === "") { + if(document.getElementById("textFormStatus") !== null) { + document.getElementById("textFormStatus").style.color = "red"; + document.getElementById("textFormStatus").innerHTML = "No text was present!"; + }; + throw new Error("No text was present"); + }; //validate try { json = JSON.parse(json); } catch (error) { - if(document.getElementById("fileFormStatus") !== "null") { - document.getElementById("fileFormStatus").style.color = "red"; - document.getElementById("fileFormStatus").innerHTML = "The file wasn't valid JSON!"; + if(document.getElementById("textFormStatus") !== null) { + document.getElementById("textFormStatus").style.color = "red"; + document.getElementById("textFormStatus").innerHTML = "The text wasn't valid JSON!"; }; throw error; }; - if(document.getElementById("fileFormStatus") !== "null") { - document.getElementById("fileFormStatus").style.color = "yellow"; - document.getElementById("fileFormStatus").innerHTML = "JSON was parsed successfully"; + if(document.getElementById("textFormStatus") !== null) { + document.getElementById("textFormStatus").style.color = "yellow"; + document.getElementById("textFormStatus").innerHTML = "JSON was parsed successfully"; }; //return json; return importJsonState(json); }; -}; -function loadText() { - //Initialize - var json; - - //load JSON - var json = document.getElementById('mytext').value; - if(json === "") { - if(document.getElementById("textFormStatus") !== "null") { - document.getElementById("textFormStatus").style.color = "red"; - document.getElementById("textFormStatus").innerHTML = "No text was present!"; - }; - throw new Error("No text was present"); - }; - - //validate - try { - json = JSON.parse(json); - } catch (error) { - if(document.getElementById("textFormStatus") !== "null") { - document.getElementById("textFormStatus").style.color = "red"; - document.getElementById("textFormStatus").innerHTML = "The text wasn't valid JSON!"; - }; - throw error; - }; - - if(document.getElementById("textFormStatus") !== "null") { - document.getElementById("textFormStatus").style.color = "yellow"; - document.getElementById("textFormStatus").innerHTML = "JSON was parsed successfully"; - }; - - //return json; - return importJsonState(json); -}; - -function importJsonState(json) { - //check keys - var jsonKeys = Object.keys(json); - var requiredKeys = [/*"currentPixels", */"pixelMap", "width", "height", "pixelSize"]; - var hasrequiredKeys = true; - for(i = 0; i < requiredKeys.length; i++) { - var key = requiredKeys[i]; - if(!jsonKeys.includes(key)) { - hasrequiredKeys = false; - break; - }; - }; - if(!hasrequiredKeys) { - if(document.getElementById("fileFormStatus") !== "null") { - document.getElementById("fileFormStatus").style.color = "red"; - document.getElementById("fileFormStatus").innerHTML = "JSON is not a valid save!"; - }; - throw new Error("JSON is missing required keys!"); - }; - - //Set values - width = json.width; - height = json.height; - pixelSize = json.pixelSize; - //currentPixels = json.currentPixels; - for(i = 0; i < json.pixelMap.length; i++) { - json.pixelMap[i] = json.pixelMap[i].map(x => zeroToNull(x)); - }; - pixelMap = json.pixelMap; - if(json.settings) { - settings = json.settings; - }; - - //enabledMods handling { - var enMods = "[]"; - if(typeof(json.enabledMods) !== "undefined") { - enMods = json.enabledMods; - }; - enMods = JSON.parse(enMods); - //console.log(enMods); - - var currentEnmods = JSON.parse(localStorage.enabledMods); //should already exist if you're using this mod in the first place - for(emi = 0; emi < enMods.length; emi++) { //load mods additively to prevent self-disabling and the inconvenience of having to readd your mod list when you get bored - var mod = enMods[emi]; - if(!currentEnmods.includes(mod)) { - currentEnmods.push(mod); + function importJsonState(json) { + //check keys + var jsonKeys = Object.keys(json); + var requiredKeys = [/*"currentPixels", */"pixelMap", "width", "height", "pixelSize"]; + var hasrequiredKeys = true; + for(i = 0; i < requiredKeys.length; i++) { + var key = requiredKeys[i]; + if(!jsonKeys.includes(key)) { + hasrequiredKeys = false; + break; }; }; - localStorage.setItem("enabledMods",JSON.stringify(currentEnmods)); - if((enMods.length > 0 && enMods[0] !== modName) || enMods.length > 1) { - alert("Saves with other mods might require a reload (and then importing the save file again).\nIf you see a blank screen, try refreshing and loading the file again before you panic."); + if(!hasrequiredKeys) { + if(document.getElementById("fileFormStatus") !== null) { + document.getElementById("fileFormStatus").style.color = "red"; + document.getElementById("fileFormStatus").innerHTML = "JSON is not a valid save!"; + }; + throw new Error("JSON is missing required keys!"); }; - //} - - var currPix = []; //rebuild currentPixels from pixelMap to try to fix bug - for(pmi = 0; pmi < pixelMap.length; pmi++) { - var pixelMapPart = pixelMap[pmi]; - for(pmj = 0; pmj < pixelMapPart.length; pmj++) { - var pixelMapUnit = pixelMapPart[pmj]; - if(typeof(pixelMapUnit) === "object") { - if(pixelMapUnit !== null) { - currPix.push(pixelMapUnit); + + //Set values + width = json.width; + height = json.height; + pixelSize = json.pixelSize; + //currentPixels = json.currentPixels; + for(i = 0; i < json.pixelMap.length; i++) { + json.pixelMap[i] = json.pixelMap[i].map(x => zeroToNull(x)); + }; + pixelMap = json.pixelMap; + if(json.settings) { + settings = json.settings; + }; + + //enabledMods handling { + var enMods = "[]"; + if(typeof(json.enabledMods) !== "undefined") { + enMods = json.enabledMods; + }; + enMods = JSON.parse(enMods); + //console.log(enMods); + + var currentEnmods = JSON.parse(localStorage.enabledMods); //should already exist if you're using this mod in the first place + for(emi = 0; emi < enMods.length; emi++) { //load mods additively to prevent self-disabling and the inconvenience of having to readd your mod list when you get bored + var mod = enMods[emi]; + if(!currentEnmods.includes(mod)) { + currentEnmods.push(mod); + }; + }; + localStorage.setItem("enabledMods",JSON.stringify(currentEnmods)); + if((enMods.length > 0 && enMods[0] !== modName) || enMods.length > 1) { + alert("Saves with other mods might require a reload (and then importing the save file again).\nIf you see a blank screen, try refreshing and loading the file again before you panic."); + }; + //} + + var currPix = []; //rebuild currentPixels from pixelMap to try to fix bug + for(pmi = 0; pmi < pixelMap.length; pmi++) { + var pixelMapPart = pixelMap[pmi]; + for(pmj = 0; pmj < pixelMapPart.length; pmj++) { + var pixelMapUnit = pixelMapPart[pmj]; + if(typeof(pixelMapUnit) === "object") { + if(pixelMapUnit !== null) { + currPix.push(pixelMapUnit); + }; }; }; }; - }; - currentPixels = currPix; - - if(document.getElementById("fileFormStatus") !== "null") { - document.getElementById("fileFormStatus").style.color = "green"; - document.getElementById("fileFormStatus").innerHTML = "JSON was loaded successfully."; - }; - return true; -}; - -function setPixelSize(size=null) { - if(size === null) { - if(document.getElementById("pixelSize") !== "null") { - size = document.getElementById("pixelSize").value; - } else { - throw new Error("No size could be read"); + currentPixels = currPix; + + if(document.getElementById("fileFormStatus") !== null) { + document.getElementById("fileFormStatus").style.color = "green"; + document.getElementById("fileFormStatus").innerHTML = "JSON was loaded successfully."; }; + return true; }; - size = parseFloat(size); - if(isNaN(size) || size <= 0) { //NaN check - if(document.getElementById("pixelSizeStatus") !== "null") { - document.getElementById("pixelSizeStatus").style.color = "red"; - document.getElementById("pixelSizeStatus").innerHTML = "Pixel size is empty or invalid"; + function setPixelSize(size=null) { + if(size === null) { + if(document.getElementById("pixelSize") !== null) { + size = document.getElementById("pixelSize").value; + } else { + throw new Error("No size could be read"); + }; }; - throw new Error("NaN or negative size"); + + size = parseFloat(size); + if(isNaN(size) || size <= 0) { //NaN check + if(document.getElementById("pixelSizeStatus") !== null) { + document.getElementById("pixelSizeStatus").style.color = "red"; + document.getElementById("pixelSizeStatus").innerHTML = "Pixel size is empty or invalid"; + }; + throw new Error("NaN or negative size"); + }; + + if(document.getElementById("pixelSizeStatus") !== null) { + document.getElementById("pixelSizeStatus").style.color = "green"; + document.getElementById("pixelSizeStatus").innerHTML = "Pixel size set successfully"; + }; + pixelSize = size; + return true; }; - - if(document.getElementById("pixelSizeStatus") !== "null") { - document.getElementById("pixelSizeStatus").style.color = "green"; - document.getElementById("pixelSizeStatus").innerHTML = "Pixel size set successfully"; - }; - pixelSize = size; - return true; -}; -var saveLoaderDescription = `