diff --git a/mods/chalcopyrite.js b/mods/chalcopyrite.js index 8d038076..b36d45b8 100644 --- a/mods/chalcopyrite.js +++ b/mods/chalcopyrite.js @@ -6,6 +6,7 @@ elements.chalcopyrite_ore = { steel: { "elem1": "chalcopyrite_dust", "elem2": "steel" }, }, tempHigh: 950, + breakInto: "chalcopyrite_dust", stateHigh: "magma", category: "refining", state: "solid", diff --git a/mods/color_tools.js b/mods/color_tools.js index 465084f3..94a8d7eb 100644 --- a/mods/color_tools.js +++ b/mods/color_tools.js @@ -3,19 +3,34 @@ var libraryMod = "mods/code_library.js"; if(enabledMods.includes(libraryMod)) { var colorToolCounter = 0; - var saturationAmount = 1; - var saturationOp = "add"; - var luminanceAmount = 1; - var luminanceOp = "add"; - var hueAmount = 1; - var hueOp = "add"; + saturationAmount = 1; + saturationOp = "add"; + luminanceAmount = 1; + luminanceOp = "add"; + hueAmount = 1; + hueOp = "add"; + colorToolElementFilter = "none"; var ops = ["add","subtract","multiply","divide","set","min","max","+","-","*","x","×","/","÷","=",">",">=","<","<="]; + function colorToolFilterPrompt() { + var preElement = prompt("Enter the elements you want to limit it to\nSeparate multiple elements with commas\nType \"none\" for no filter"); + if(preElement === null) { + return false; + }; + if(preElement.includes(",")) { + preElement = preElement.split(","); + colorToolElementFilter = preElement; + return colorToolElementFilter; + }; + colorToolElementFilter = preElement; + return colorToolElementFilter; + }; + function saturationPrompt() { var preSaturation = prompt("Enter the value you want to use"); var preSatOp = prompt(`Enter the operation ("add", "subtract", "multiply", or "divide", or "set")`); - + //value check if(isNaN(parseFloat(preSaturation))) { if(preSaturation === "" || preSaturation === null) { @@ -109,174 +124,310 @@ if(enabledMods.includes(libraryMod)) { return [preHue, preHueOp]; }; - /*function colorToolCounterIncrement() { - if(typeof(colorToolCounter) === "undefined") { - colorToolCounter = 0; - }; - colorToolCounter++; - }; - colorToolCounterInterval = setInterval(colorToolCounterIncrement, 50);*/ - colorToolCounterInterval = 0; - elements.multiply_color = { color: ["#c27070","#c29c70","#c2c270","#70c270","#70c2c2","#7070c2","#c270c2"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = multiplyColors(pixel.color,currentColor,"rgb"); - colorToolCounter = 0; }; }, customColor: true, cooldown: 3, category: "color tools", //the toolbar is getting cluttered excludeRandom: true, //the toolbar is getting cluttered + desc: "Click here to configure the element filter (applies to all color tools).", } - elements.divide_color = { //can't get it to work how I want it to work + elements.divide_color = { color: ["#c27070","#c29c70","#c2c270","#70c270","#70c2c2","#7070c2","#c270c2"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = divideColors(pixel.color,currentColor,"rgb"); - colorToolCounter = 0; }; }, customColor: true, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } elements.add_color = { color: ["#c27070","#c29c70","#c2c270","#70c270","#70c2c2","#7070c2","#c270c2"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = addColors(pixel.color,currentColor,"rgb"); - colorToolCounter = 0; }; }, customColor: true, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } elements.subtract_color = { color: ["#c27070","#c29c70","#c2c270","#70c270","#70c2c2","#7070c2","#c270c2"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = subtractColors(pixel.color,currentColor,"rgb"); - colorToolCounter = 0; }; }, customColor: true, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } elements.hue = { color: ["#ff0000","#ccff00","#00ff66","#0066ff","#cc00ff","#ff0000"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = changeHue(pixel.color,hueAmount,hueOp,"rgb"); - colorToolCounter = 0; }; }, cooldown: 3, category: "color tools", excludeRandom: true, - desc: "Click here to configure the tool." - } + desc: "Click here to configure the tool.
Click here to configure the element filter (applies to all color tools).", + }; elements.saturation = { color: ["#808080","#996666","#b34d4d","#cc3333","#e61919","#ff0000"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = changeSaturation(pixel.color,saturationAmount,saturationOp,"rgb"); - colorToolCounter = 0; }; }, cooldown: 3, category: "color tools", excludeRandom: true, - desc: "Click here to configure the tool." + desc: "Click here to configure the tool.
Click here to configure the element filter (applies to all color tools)." } elements.luminance = { color: ["#000000","#333333","#666666","#999999","#cccccc","#ffffff"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { pixel.color = changeLuminance(pixel.color,luminanceAmount,luminanceOp,"rgb"); - colorToolCounter = 0; }; }, cooldown: 3, category: "color tools", excludeRandom: true, - desc: "Click here to configure the tool." + desc: "Click here to configure the tool.
Click here to configure the element filter (applies to all color tools)." } elements.grayscale = { color: ["#7f7f7f"], tool: function(pixel) { - // convert the hex of currentColor to rgb and set it as a string - var oldColor = hexToRGB(rgbToHex(pixel.color)) - var lightness = Math.round((oldColor.r * 0.299) + (oldColor.g * 0.587) + (oldColor.b * 0.114)) - var finalColor = [lightness, lightness, lightness] - pixel.color = "rgb(" + finalColor.join(",") + ")" + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { + var oldColor = convertColorFormats(pixel.color,"json"); + var lightness = Math.round((oldColor.r * 0.299) + (oldColor.g * 0.587) + (oldColor.b * 0.114)) + var finalColor = [lightness, lightness, lightness] + pixel.color = "rgb(" + finalColor.join(",") + ")" + }; }, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } elements.invert = { color: ["#ff0000", "#00ffff"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { - // convert the hex of currentColor to rgb and set it as a string - var oldColor = hexToRGB(rgbToHex(pixel.color)) - var finalColor = [(255 - oldColor.r), (255 - oldColor.g), (255 - oldColor.b)] - pixel.color = "rgb(" + finalColor.join(",") + ")" - colorToolCounter = 0; - }; + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { + var oldColor = convertColorFormats(pixel.color,"json"); + var finalColor = [(255 - oldColor.r), (255 - oldColor.g), (255 - oldColor.b)] + pixel.color = "rgb(" + finalColor.join(",") + ")" + }; }, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } elements.reverse_R_G_B = { color: ["#7f7f7f"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { - // convert the hex of currentColor to rgb and set it as a string - var oldColor = hexToRGB(rgbToHex(pixel.color)) - var finalColor = [oldColor.b, oldColor.g, oldColor.r] - pixel.color = "rgb(" + finalColor.join(",") + ")" - colorToolCounter = 0; - }; + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { + var oldColor = convertColorFormats(pixel.color,"json"); + var finalColor = [oldColor.b, oldColor.g, oldColor.r] + pixel.color = "rgb(" + finalColor.join(",") + ")" + }; }, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } elements.shift_R_G_B = { color: ["#7f7f7f"], tool: function(pixel) { - if(colorToolCounter % 3 == 0) { - // convert the hex of currentColor to rgb and set it as a string - var oldColor = hexToRGB(rgbToHex(pixel.color)) - var finalColor = [oldColor.g, oldColor.b, oldColor.r] - pixel.color = "rgb(" + finalColor.join(",") + ")" - colorToolCounter = 0; - }; + var element = pixel.element; + if( colorToolElementFilter === "none" || ( (typeof(colorToolElementFilter) === "string" && element === colorToolElementFilter) || (Array.isArray(colorToolElementFilter) && colorToolElementFilter.includes(element)) ) ) { + var oldColor = convertColorFormats(pixel.color,"json"); + var finalColor = [oldColor.g, oldColor.b, oldColor.r] + pixel.color = "rgb(" + finalColor.join(",") + ")" + }; }, cooldown: 3, category: "color tools", excludeRandom: true, + desc: "Click here to configure the element filter (applies to all color tools).", } + + //do cooldown for mouse size > 1 + function mouse1Action(e,mouseX=undefined,mouseY=undefined,startPos) { + if (currentElement == "erase") { mouse2Action(e,mouseX,mouseY); return; } + else if (currentElement == "pick") { mouseMiddleAction(e,mouseX,mouseY); return; } + // If x and y are undefined, get the mouse position + if (mouseX == undefined && mouseY == undefined) { + var canvas = document.getElementById("game"); + var ctx = canvas.getContext("2d"); + lastPos = mousePos; + mousePos = getMousePos(canvas, e); + var mouseX = mousePos.x; + var mouseY = mousePos.y; + } + if (currentElement == "lookup") { + if (!isEmpty(mouseX,mouseY,true)) { + showInfo(pixelMap[mouseX][mouseY].element); + } + return; + } + var cooldowned = false; + if (elements[currentElement].cooldown) { + if (pixelTicks-lastPlace < elements[currentElement].cooldown) { + return; + } + cooldowned = true; + } + lastPlace = pixelTicks; + startPos = startPos || lastPos + if (!(isMobile || (cooldowned && startPos.x===lastPos.x && startPos.y===lastPos.y) || elements[currentElement].tool || elements[currentElement].category==="tools")) { + var coords = lineCoords(startPos.x,startPos.y,mouseX,mouseY); + } + else { var coords = mouseRange(mouseX,mouseY); } + var element = elements[currentElement]; + var mixList = []; + // For each x,y in coords + for (var i = 0; i < coords.length; i++) { + var x = coords[i][0]; + var y = coords[i][1]; + + // If element name is heat or cool + if (currentElement === "heat" || currentElement === "cool") { + if (!isEmpty(x,y,false)) { + if (outOfBounds(x,y)) { + continue; + } + var pixel = pixelMap[x][y]; + if (shiftDown) {pixel.temp += element.temp+(Math.random()*element.temp*1.5)*20;} + else {pixel.temp += element.temp+(Math.random()*element.temp*1.5);} + pixelTempCheck(pixel); + } + } + else if (currentElement === "mix") { + if (!isEmpty(x,y,true)) { + var pixel = pixelMap[x][y]; + if ((pixel.element != "fire" && pixel.element != "smoke") || shiftDown) { + mixList.push(pixel); + } + } + } + else if (currentElement === "shock") { + if (!isEmpty(x,y,true)) { + // One loop that repeats 5 times if shiftDown else 1 time + for (var j = 0; j < (shiftDown ? 5 : 1); j++) { + var pixel = pixelMap[x][y]; + var con = elements[pixel.element].conduct; + if (con == undefined) {continue} + if (Math.random() < con) { // If random number is less than conductivity + if (!pixel.charge && !pixel.chargeCD) { + pixel.charge = 1; + if (elements[pixel.element].colorOn) { + pixel.color = pixelColorPick(pixel); + } + } + } + else if (elements[pixel.element].insulate != true) { // Otherwise heat the pixel (Resistance simulation) + pixel.temp += 0.25; + pixelTempCheck(pixel); + } + } + } + } + else if (currentElement === "random" && isEmpty(x, y)) { + // create pixel with random element from "randomChoices" array + currentPixels.push(new Pixel(x, y, randomChoices[Math.floor(Math.random() * randomChoices.length)])); + } + else if (elements[currentElement].tool) { + // run the tool function on the pixel + if (!isEmpty(x,y,true)) { + var pixel = pixelMap[x][y]; + // if the current element has an ignore property and the pixel's element is in the ignore property, don't do anything + if (elements[currentElement].ignore && elements[currentElement].ignore.indexOf(pixel.element) != -1) { + continue; + } + elements[currentElement].tool(pixel); + } + } + else if (mode === "replace") { + if (outOfBounds(x,y)) { + continue; + } + // Remove pixel at position from currentPixels + var index = currentPixels.indexOf(pixelMap[x][y]); + if (index > -1) { + currentPixels.splice(index, 1); + } + if (currentElement == "random") { + currentPixels.push(new Pixel(x, y, randomChoices[Math.floor(Math.random() * randomChoices.length)])); + } + else { + currentPixels.push(new Pixel(x, y, currentElement)); + } + if (elements[currentElement].customColor) { + pixelMap[x][y].color = pixelColorPick(currentElement,currentColor); + } + } + else if (isEmpty(x, y)) { + currentPixels.push(new Pixel(x, y, currentElement)); + if (elements[currentElement].customColor) { + pixelMap[x][y].color = pixelColorPick(currentElement,currentColor); + } + } + } + if (currentElement == "mix") { + // 1. repeat for each pixel in mixList + // 2. choose 2 random pixels and swap their x and y + // 3. remove pixel from mixList + for (var i = 0; i < mixList.length; i++) { + var pixel1 = mixList[Math.floor(Math.random()*mixList.length)]; + var pixel2 = mixList[Math.floor(Math.random()*mixList.length)]; + swapPixels(pixel1,pixel2); + mixList.splice(mixList.indexOf(pixel1),1); + mixList.splice(mixList.indexOf(pixel2),1); + } + } + }; + //do cooldown for mouse size > 1 + } else { alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`) enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) diff --git a/mods/save_loading.js b/mods/save_loading.js new file mode 100644 index 00000000..b31c28c2 --- /dev/null +++ b/mods/save_loading.js @@ -0,0 +1,232 @@ +var modName = "mods/save_loading.js"; + +function getSimulationState() { + var simulationState = { + //currentPixels: currentPixels, + pixelMap: pixelMap, + width: width, + height: height, + pixelSize: pixelSize, + settings: settings, + version: 0, + enabledMods: localStorage.enabledMods, + }; + return simulationState; +}; + +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 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 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; + 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"); + }; + }; + + 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; +}; + +var saveLoaderDescription = `
+Download simulation + +No file loader status +One file, please: + + +No size setter status +Pixel size (rendering only): (Use if the save looks cut off) + +
`; + +elements.save_loader = { + behavior: behaviors.SELFDELETE, + excludeRandom: true, + color: "#FFFFFF", + desc: saveLoaderDescription, +};