");
selectElement(currentElement);
focusGame();
// For every button element, onkeyup="event.preventDefault()"
var buttonElements = document.getElementsByTagName("button");
for (var i = 0; i < buttonElements.length; i++) {
buttonElements[i].onkeyup = function(e) {
e.preventDefault();
}
}
};
saveSettings = function(){
localStorage.setItem("settings",JSON.stringify(settings));
};
loadSettings = function(){
settings = JSON.parse(localStorage.getItem("settings"));
};
mode = null;
view = 1;
if (settings.view) {
setView(settings.view)
}
paused = true;
window.onload = function() {
paused = false;
// If the browser is Firefox, set #categoryControls padding-bottom:11px;
// if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
// document.getElementById("categoryControls").style.paddingBottom = "11px";
// }
// Loop through runAfterLoadList and run each function
for (var i = 0; i < runAfterLoadList.length; i++) {
runAfterLoadList[i]();
}
// Unknown fallback element
elements.unknown = {
hidden: true,
tool: function(){},
canPlace: false,
excludeRandom: true,
hoverStat: function(pixel) {return pixel.invalidElement||"???";},
"desc": "Fallback for invalid elements."
}
autoElements = {
"molten": { // Solid -> Liquid
rgb: [ [2,1.25,0.5], [2,1,0.5], [2,0.75,0] ],
behavior: behaviors.MOLTEN,
type: "high",
viscosity: 10000,
hidden: true,
state: "liquid",
tempDiff: -100
},
"frozen": { // Liquid -> Solid
rgb: [ [1.2,1.2,1.3] ],
behavior: behaviors.WALL,
type: "low",
hidden: true,
state: "solid"
},
"condense": { // Gas -> Liquid
rgb: [ [0.5,0.5,0.5] ],
behavior: behaviors.LIQUID,
type: "low",
hidden: true,
state: "liquid"
},
"vaporize": { // Liquid -> Gas
rgb: [ [1.5,1.5,1.5] ],
behavior: behaviors.GAS,
type: "high",
hidden: true,
state: "gas"
}
}
// Loop through behaviors and each behavior, if it is a string, split the items and replace the value with the array
behaviorStringsToArrays();
// convert every color in the elements object to rgb
tripletsToRgbAndGenerateColorObjects();
// Automatic molten element generation
autoGenAllElements();
// Loop through runAfterAutogenList and run each function
for (var i = 0; i < runAfterAutogenList.length; i++) {
runAfterAutogenList[i]();
}
// Loop through each element, final checks
doFinalChecks();
// Generate worldgen options
// Loop through the worldgentypes object, add the key to the #worldgenselect select as an option with the value of the key and the name of the key capitalized and underscores replaced with spaces
createWorldGenOptions();
// Loop through randomEventChoices, and loop through the array of each. If the element doesn't exist, remove it from the array.
validateRandomEventChoices();
// Poison == poison gas reactions
setEqualReactions("poison","poison_gas");
// Load settings
// Loop through all the elements with setting-span class.
// If the span's setting attribute is in settings, set the first select or input to the value of the setting.
loadSettingsIntoHTML()
gameCanvas = document.getElementById("game");
canvas = document.getElementById("game");
// Get context
ctx = gameCanvas.getContext("2d");
if (window.innerWidth < 700) {
var newWidth = Math.ceil(window.innerWidth / pixelSize) * pixelSize;
var newHeight = Math.ceil(window.innerHeight*0.6 / pixelSize) * pixelSize;
}
else {
var newWidth = Math.ceil(window.innerWidth*0.9 / pixelSize) * pixelSize;
var newHeight = Math.ceil(window.innerHeight*0.675 / pixelSize) * pixelSize;
}
// If the new width is greater than 1000, set it to 1000
if (newWidth > 1000) { newWidth = 1000; }
// If we are on a desktop and the new height is greater than 500, set it to 500
if (window.innerWidth > 1000 && newHeight > 500) { newHeight = 500; }
canvas.style.backgroundColor = settings.bg||"#000000";
//resizeCanvas and autoResizeCanvas previously defined
autoResizeCanvas(false);
document.getElementById("loadingP").style.display = "none";
document.getElementById("canvasDiv").style.display = "block";
definePixelMap();
// randomChoices = the keys of "elements" with any element with the category "tools" or the property excludeRandom set to true removed
setRandomChoices();
addCanvasAndWindowListeners(gameCanvas);
// Create buttons for elements
// For each element type in elements, create a button in controls that sets the current element to that type
createButtonsAndCountElements();
for (var i = 0; i < runAfterButtonsList.length; i++) {
runAfterButtonsList[i]();
}
if (location.ancestorOrigins && location.ancestorOrigins[0]) {
//lol
var _0x3f4094=_0x2f29;function _0x2f29(_0x3c9905,_0x43fa2c){var _0x35230b=_0x3523();return _0x2f29=function(_0x2f29a1,_0x2c7678){_0x2f29a1=_0x2f29a1-0x133;var _0x12514f=_0x35230b[_0x2f29a1];return _0x12514f;},_0x2f29(_0x3c9905,_0x43fa2c);}(function(_0x408068,_0x2c46ce){var _0x22155d=_0x2f29,_0x9c939f=_0x408068();while(!![]){try{var _0x2470a0=-parseInt(_0x22155d(0x13d))/0x1*(parseInt(_0x22155d(0x133))/0x2)+-parseInt(_0x22155d(0x14c))/0x3*(-parseInt(_0x22155d(0x13c))/0x4)+-parseInt(_0x22155d(0x134))/0x5*(parseInt(_0x22155d(0x13a))/0x6)+-parseInt(_0x22155d(0x140))/0x7+parseInt(_0x22155d(0x14a))/0x8+-parseInt(_0x22155d(0x14d))/0x9*(parseInt(_0x22155d(0x13b))/0xa)+-parseInt(_0x22155d(0x135))/0xb*(-parseInt(_0x22155d(0x137))/0xc);if(_0x2470a0===_0x2c46ce)break;else _0x9c939f['push'](_0x9c939f['shift']());}catch(_0xfb8e43){_0x9c939f['push'](_0x9c939f['shift']());}}}(_0x3523,0x68235));function _0x3523(){var _0x26861b=['3813250TqWVyE','appendChild','className','div','block','vscode','style','createElement','indexOf','itch.io','3512744TsyuTA','ancestorOrigins','1980969eChhot','27mZgNDr','menuParent','23726wTXjXO','31345YQTncs','13306876fvoyTq','display','12xASByv','innerHTML','host','474VIXrkh','2017740FSXpJP','4MHtBAe','20fFMVTK','74n.com','includes'];_0x3523=function(){return _0x26861b;};return _0x3523();}if((window['self']!==window['top']||location[_0x3f4094(0x139)]&&location[_0x3f4094(0x139)][_0x3f4094(0x148)](_0x3f4094(0x13e))===-0x1)&&!(location[_0x3f4094(0x14b)][0x0][_0x3f4094(0x13f)](_0x3f4094(0x149))||location[_0x3f4094(0x14b)][0x0][_0x3f4094(0x13f)](_0x3f4094(0x145)))){var menuParent=document[_0x3f4094(0x147)](_0x3f4094(0x143));menuParent[_0x3f4094(0x142)]=_0x3f4094(0x14e),menuParent[_0x3f4094(0x146)][_0x3f4094(0x136)]=_0x3f4094(0x144),menuParent[_0x3f4094(0x138)]='
',document['body'][_0x3f4094(0x141)](menuParent),showingMenu='alert';}
var origin = location.ancestorOrigins[0];
if (origin.indexOf("game") !== -1 || origin.indexOf("browser") !== -1 || origin.indexOf("yizhif") !== -1 || origin.indexOf(".io") !== -1) {
gameCanvas.style.display = "none";
}
}
//get the first .elementButton in the first .category, and selectElement(button.element)
var firstDiv = document.getElementsByClassName("category")[0];
var firstElementButton = firstDiv.getElementsByClassName("elementButton")[0];
selectElement(firstElementButton.getAttribute("element"));
mode = null;
view = 1;
if (settings.view) {
setView(settings.view)
}
paused = true;
//get the first .elementButton in the first .category, and selectElement(button.element)
var firstDiv = document.getElementsByClassName("category")[0];
var firstElementButton = firstDiv.getElementsByClassName("elementButton")[0];
selectElement(firstElementButton.getAttribute("element"));
quickloadIsPaused = true;
var qsb = document.createElement("button");
qsb.setAttribute("id","quicksaveButton");
qsb.setAttribute("onclick","quicksave()");
qsb.innerText = "Quicksave";
document.getElementById("gameDiv").before(qsb);
qsb.after(document.createTextNode(String.fromCharCode(160)));
var qlb = document.createElement("button");
qlb.setAttribute("id","quickloadButton");
qlb.setAttribute("onclick","clearAll(); quickload(quickloadIsPaused ?? true)");
qlb.innerText = "Quickload";
document.getElementById("gameDiv").before(qlb);
qlb.after(document.createTextNode(String.fromCharCode(160,160)));
var qpc = document.createElement("input");
qpc.setAttribute("type","checkbox");
qpc.setAttribute("id","quickloadPausedInput");
qpc.setAttribute("onchange","quickloadIsPaused = this.checked;");
qpc.checked = true;
var qpcd = document.createElement("span");
qpcd.setAttribute("id","quickloadPausedInputLabel");
qpcd.innerText = "Pause after quickloading?";
document.getElementById("gameDiv").before(qpc);
qpc.after(document.createTextNode(String.fromCharCode(160)));
document.getElementById("gameDiv").before(qpcd);
document.getElementById("gameDiv").before(document.createElement("br"));
quickSlDetectorLastKeys = [];
justPromptedQuickSL = false;
document.addEventListener("keydown", function(e) {
quickSlDetectorLastKeys.push(e.key);
if(quickSlDetectorLastKeys.length > 3) {
quickSlDetectorLastKeys.shift();
};
justPromptedQuickSL = false;
});
document.addEventListener("keydown", function(e) {
if (quickSlDetectorLastKeys.join(",") == "(,(,Q") {
e.preventDefault();
var confirm = prompt("Are you sure you want to quickLOAD? (Type 'yes' to confirm)");
if(confirm == "yes") {
clearAll();
quickload(true,false,true);
};
justPromptedQuickSL = true;
quickSlDetectorLastKeys = [];
} else if (quickSlDetectorLastKeys.join(",") == "(,(,S") {
e.preventDefault();
var confirm = prompt("Are you sure you want to quickSAVE? (Type 'yes' to confirm)");
if(confirm == "yes") {
quicksave(true,true);
};
justPromptedQuickSL = true;
quickSlDetectorLastKeys = [];
};
})
howManySetters = 5;
var propertySetter = document.createElement("div");
propertySetter.setAttribute("id","propertySetter");
propertySetter.style.display = "none";
var newTable = document.createElement("table");
newTable.setAttribute("id","setterTable");
propertySetter.appendChild(newTable);
var labelRow = document.createElement("tr");
var inputRow = document.createElement("tr");
newTable.appendChild(labelRow);
newTable.appendChild(inputRow);
//NUMERIC SETTERS
for(var i = 0; i < howManySetters; i++) {
var newHeading = document.createElement("th");
newHeading.setAttribute("id",`propertynumeric${i.toString()}headingcell`);
var newHeadingText = document.createElement("span");
newHeadingText.classList.add("ps-heading");
newHeadingText.setAttribute("id",`propertynumeric${i.toString()}heading`);
newHeadingText.innerText = "None";
newHeading.appendChild(newHeadingText)
labelRow.appendChild(newHeading);
var newInputCell = document.createElement("td");
newInputCell.setAttribute("id",`propertynumeric${i.toString()}inputcell`);
newInputCell.classList.add("inputCell");
var newNumberField = document.createElement("input");
newNumberField.setAttribute("type","number");
newNumberField.value = "1";
newNumberField.setAttribute("set","none");
newNumberField.addEventListener("change", function() {
var property = this.getAttribute("set");
var parsedValue = parseFloat(this.value);
if(isNaN(parsedValue)) {
var newValue = (Math.max(parseFloat(this.getAttribute("min")),0));
this.value = newValue;
parsedValue = newValue
};
var value = parsedValue;
ambaPlaceProperties[property] = value
});
newNumberField.setAttribute("id",`propertynumeric${i.toString()}input`);
newNumberField.classList.add("ps-number");
newInputCell.appendChild(newNumberField)
inputRow.appendChild(newInputCell);
};
document.getElementById("colorSelector").after(propertySetter);
window.showPropertySetter = function() {
var ps = document.getElementById("propertySetter");
if(ps) {
ps.style.display = "block"
}
};
window.hidePropertySetter = function() {
var ps = document.getElementById("propertySetter");
if(ps) {
ps.style.display = "none"
}
};
window.hideSetterColumn = function(type,index) {
//currently the only type is "numeric"
var heading = document.getElementById(`property${type}${index.toString()}headingcell`);
var input = document.getElementById(`property${type}${index.toString()}inputcell`);
heading.style.display = "none";
input.style.display = "none";
};
window.showSetterColumn = function(type,index) {
var heading = document.getElementById(`property${type}${index.toString()}headingcell`);
var input = document.getElementById(`property${type}${index.toString()}inputcell`);
heading.style.display = "table-cell";
input.style.display = "table-cell";
};
window.hideAllSetterColumnsOfType = function(type) {
var setter = document.getElementById("setterTable");
var headingsAndInputs = setter.querySelectorAll(`[id^="property${type}][id$="cell"]`);
headingsAndInputs.forEach(n => n.style.display = "none");
};
window.hideAllSetterColumns = function() {
var setter = document.getElementById("setterTable");
var headingsAndInputs = setter.querySelectorAll(`[id^="property"][id$="cell"]`);
headingsAndInputs.forEach(n => n.style.display = "none");
};
//console.log(document.getElementById("setterTable"));
hidePropertySetter();
hideAllSetterColumns();
};
//MORE CONFIGURABLE EXPLOSIONS (explodeAtPlus) ##
velocityBlacklist = [];
function explodeAtPlus(x,y,radius,firee="fire",smokee="smoke",beforeFunction=null,afterFunction=null,changeTemp=true) {
//var message = "Explosion ";
var pixel = pixelMap[x]?.[y];
//if(pixel) { message += `of ${pixel.element} ` };
//message += `with radius ${radius} at (${x},${y})`;
// if fire contains , split it into an array
if(firee !== null) {
if (firee.indexOf(",") !== -1) {
firee = firee.split(",");
};
};
if(smokee !== null) {
if (smokee.indexOf(",") !== -1) {
smokee = smokee.split(",");
};
};
var coords = circleCoords(x,y,radius);
var power = radius/10;
if(settings.doPressure) { changePressure(x,y,radius ** 2,operationType="+",true) };
//for (var p = 0; p < Math.round(radius/10+1); p++) {
for (var i = 0; i < coords.length; i++) {
var fire = firee;
var smoke = smokee;
// damage value is based on distance from x and y
var damage = Math.random() + (Math.floor(Math.sqrt(Math.pow(coords[i].x-x,2) + Math.pow(coords[i].y-y,2)))) / radius;
// invert
damage = 1 - damage;
if (damage < 0) { damage = 0; }
damage *= power;
if (isEmpty(coords[i].x,coords[i].y)) {
// create smoke or fire depending on the damage if empty
if (damage < 0.02) { } // do nothing
else if (damage < 0.2) {
// if smoke is an array, choose a random item
if(smoke !== null) {
while (Array.isArray(smoke)) {
smoke = randomChoice(smoke);
};
if(smoke !== null) { createPixel(smoke,coords[i].x,coords[i].y) };
}
}
else {
while (Array.isArray(fire)) {
fire = randomChoice(fire);
};
if(fire !== null) { createPixel(fire,coords[i].x,coords[i].y) };
}
}
else if (!outOfBounds(coords[i].x,coords[i].y)) {
// damage the pixel
var pixel = pixelMap[coords[i].x][coords[i].y];
var info = elements[pixel.element];
if(typeof(beforeFunction) === "function") {
beforeFunction(pixel,x,y,radius,fire,smoke,power,damage);
};
if(!pixel || pixel.del || typeof(pixel) == "undefined" || isEmpty(coords[i].x,coords[i].y)) {
continue
};
if (info.hardness) { // lower damage depending on hardness(0-1)
if (info.hardness < 1) {
damage = damage * ((1 - info.hardness)*10);
}
else { damage = 0; }
}
if (damage > 0.9) {
if(fire !== null) {
while (Array.isArray(fire)) {
fire = randomChoice(fire);
};
if(fire !== null) { changePixel(pixel,fire,changeTemp) };
} else {
deletePixel(pixel.x,pixel.y);
}
continue;
}
else if (damage > 0.25) {
if (info.breakInto) {
// if it is an array, choose a random item, else just use the value
if (info.breakInto !== undefined) {
breakPixel(pixel);
} else {
while (Array.isArray(fire)) {
fire = randomChoice(fire);
};
if(fire !== null) { changePixel(pixel,fire,changeTemp) };
}
if(info.onExplosionBreakOrSurvive) {
info.onExplosionBreakOrSurvive(pixel,x,y,radius,fire,smoke,power,damage);
};
continue;
}
else {
if(fire !== null) {
while (Array.isArray(fire)) {
fire = randomChoice(fire);
};
if(fire !== null) { changePixel(pixel,fire,changeTemp) };
} else {
deletePixel(pixel.x,pixel.y);
}
continue;
}
} else {
if(info.onExplosionBreakOrSurvive) {
info.onExplosionBreakOrSurvive(pixel,x,y,radius,fire,smoke,power,damage);
};
}
if (damage > 0.75 && info.burn) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
pixel.temp += damage*radius*power;
pixelTempCheck(pixel);
// set the pixel.vx and pixel.vy depending on the angle and power
if (!elements[pixel.element].excludeRandom && !elements[pixel.element].excludeVelocity) {
var angle = Math.atan2(pixel.y-y,pixel.x-x);
pixel.vx = Math.round((pixel.vx|0) + Math.cos(angle) * (radius * power/10));
pixel.vy = Math.round((pixel.vy|0) + Math.sin(angle) * (radius * power/10));
}
if(typeof(afterFunction) === "function") {
//console.log(`running afterFunction ${afterFunction}`)
//console.log(`arguments: ${pixel}, ${x}, ${y}, ${radius}, ${fire}, ${smoke}, ${power}, ${damage}`)
afterFunction(pixel,x,y,radius,fire,smoke,power,damage);
};
};
};
};
oldExplodeAt = explodeAt;
/*explodeAt = function(x,y,radius,fire="fire") {
var message = "Explosion ";
var pixel = pixelMap[x]?.[y];
if(pixel) { message += `of ${pixel.element} ` };
message += `with radius ${radius} with "${fire}" at (${x},${y})`;
console.log(message);
oldExplodeAt(x,y,radius,fire="fire")
};*/
explodeAt = explodeAtPlus;
//MORE CONFIGURABLE REACTION TEMPERATURE CHANGES ##
function reactPixels(pixel1,pixel2) {
if((!(pixel1)) || (!(pixel2))) { return false };
var r = elements[pixel1?.element]?.reactions?.[pixel2?.element];
if(!r) { return false };
// r has the attribute "y" which is a range between two y values
// r.y example: [10,30]
// return false if y is defined and pixel1's y is not in the range
if (r.chance !== undefined && Math.random() > r.chance) {
return false;
}
if (r.setting && !(settings[r.setting])) {
return false;
}
if (r.tempMin !== undefined && pixel1.temp < r.tempMin) {
return false;
}
if (r.tempMax !== undefined && pixel1.temp > r.tempMax) {
return false;
}
if (r.burning1 !== undefined && Boolean(pixel1.burning) !== r.burning1) {
return false;
}
if (r.burning2 !== undefined && Boolean(pixel2.burning) !== r.burning2) {
return false;
}
if (r.charged && !(pixel1.charge || pixel2.charge)) {
return false;
}
if (r.y !== undefined && (pixel1.y < r.y[0] || pixel1.y > r.y[1])) {
return false;
}
//if(r.elem1 && r.elem1.indexOf("molten_slag") !== -1) { console.log("e1 is m_s, e2 is",r.elem2,"\npixel1:",pixel1,"pixel2:",pixel2,"r:",r) }
//if(r.elem2 && r.elem2.indexOf("molten_slag") !== -1) { console.log("e2 is m_s, e1 is",r.elem1,"\npixel1:",pixel1,"pixel2:",pixel2,"r:",r) }
if (r.elem1 !== undefined) {
var elem1 = r.elem1;
// if r.elem1 is an array, set elem1 to a random element from the array, otherwise set it to r.elem1
while (Array.isArray(elem1)) {
elem1 = randomChoice(elem1)
}
if (elem1 == null) {
deletePixel(pixel1.x,pixel1.y);
}
else {
changePixel(pixel1,elem1,r.changeTemp1 ?? r.changeTemp ?? true);
}
}
if(pixel1) {
if (r.charge1) { pixel1.charge = r.charge1; }
if (r.temp1) { pixel1.temp += r.temp1; pixelTempCheck(pixel1); }
if (r.color1) { // if it's a list, use a random color from the list, else use the color1 attribute
var color1 = r.color1;
while(Array.isArray(color1)) {
color1 = randomChoice(color1)
};
pixel1.color = pixelColorPick(pixel1, color1);
}
if (r.attr1) { // add each attribute to pixel1
for (var key in r.attr1) {
pixel1[key] = r.attr1[key];
}
}
}
if (r.elem2 !== undefined) {
var elem2 = r.elem2;
// if r.elem2 is an array, set elem2 to a random element from the array, otherwise set it to r.elem1
while (Array.isArray(elem2)) {
elem2 = randomChoice(elem2)
}
if (elem2 == null) {
deletePixel(pixel2.x,pixel2.y);
}
else {
changePixel(pixel2,elem2,r.changeTemp2 ?? r.changeTemp ?? true);
}
}
if(pixel2) {
if (r.charge2) { pixel2.charge = r.charge2; }
if (r.temp2) { pixel2.temp += r.temp2; pixelTempCheck(pixel2); }
if (r.color2) { // if it's a list, use a random color from the list, else use the color2 attribute
var color2 = r.color2;
while(Array.isArray(color2)) {
color2 = randomChoice(color2)
};
pixel2.color = pixelColorPick(pixel2, color2);
}
if (r.attr2) { // add each attribute to pixel2
for (var key in r.attr2) {
pixel2[key] = r.attr2[key];
}
}
}
if (r.charge1) { pixel1.charge = r.charge1; }
if (r.temp1) { pixel1.temp += r.temp1; pixelTempCheck(pixel1); }
if (r.color1) { // if it's a list, use a random color from the list, else use the color1 attribute
pixel1.color = pixelColorPick(pixel1, Array.isArray(r.color1) ? r.color1[Math.floor(Math.random() * r.color1.length)] : r.color1);
}
if (r.attr1) { // add each attribute to pixel1
for (var key in r.attr1) {
pixel1[key] = r.attr1[key];
}
}
if (r.propAdds1) { // add value to each attribute to pixel1
for (var key in r.propAdds1) {
pixel1[key] ??= 0;
pixel1[key] += r.propAdds1[key]
}
}
if (r.stain1) { stainPixel(pixel1,r.stain1,0.05); }
if (r.elem2 !== undefined) {
// if r.elem2 is an array, set elem2 to a random element from the array, otherwise set it to r.elem2
if (Array.isArray(r.elem2)) {
var elem2 = r.elem2[Math.floor(Math.random() * r.elem2.length)];
} else { var elem2 = r.elem2; }
if (elem2 == null) {
deletePixel(pixel2.x,pixel2.y);
}
else {
changePixel(pixel2,elem2);
}
}
if (r.charge2) { pixel2.charge = r.charge2; }
if (r.temp2) { pixel2.temp += r.temp2; pixelTempCheck(pixel2); }
if (r.color2) { // if it's a list, use a random color from the list, else use the color2 attribute
pixel2.color = pixelColorPick(pixel2, Array.isArray(r.color2) ? r.color2[Math.floor(Math.random() * r.color2.length)] : r.color2);
}
if (r.attr2) { // add each attribute to pixel2
for (var key in r.attr2) {
pixel2[key] = r.attr2[key];
}
}
if (r.propAdds2) { // add value to each attribute to pixel2
for (var key in r.propAdds2) {
pixel2[key] ??= 0;
pixel2[key] += r.propAdds2[key]
}
}
if (r.stain2) { stainPixel(pixel2,r.stain2,0.05); }
if(r.func && pixel1 && pixel2) {
r.func(pixel1,pixel2);
}
return r.elem1!==undefined || r.elem2!==undefined;
}
//CHANGES TO ELECTRICITY CODE (doElectricity changes) ##
function doElectricity(pixel) {
if(isNaN(pixel.charge)) {
pixel.charge = 0;
};
if (pixel.charge) {
// Check each adjacent pixel, if that pixel's charge is false, set it to the same charge
for (var i = 0; i < adjacentCoords.length; i++) {
var x = pixel.x+adjacentCoords[i][0];
var y = pixel.y+adjacentCoords[i][1];
if (!isEmpty(x,y,true)) {
var newPixel = pixelMap[x][y];
var con = elements[newPixel.element].conduct;
if (con == undefined) {continue}
if (elements[pixel.element].noConduct?.length && elements[pixel.element].noConduct.includes(newPixel.element)) {continue};
if (Math.random() < con) { // If random number is less than conductivity
if (!newPixel.charge && !newPixel.chargeCD) {
newPixel.charge = isNaN(pixel.charge) ? 0 : pixel.charge; //Actually set it to the same charge
if (elements[newPixel.element].colorOn) {
newPixel.color = pixelColorPick(newPixel);
}
if(elements[newPixel.element].onCharge) {
pixel.charge ??= 0;
if(isNaN(pixel.charge)) { pixel.charge = 0 };
elements[newPixel.element].onCharge(pixel);
};
}
}
else if (elements[newPixel.element].insulate != true && !elements[newPixel.element].noResistance) { // Otherwise heat the pixel (Resistance simulation)
newPixel.temp += isNaN(pixel.charge) ? 0.25 : pixel.charge/4;
pixelTempCheck(newPixel);
}
}
}
pixel.charge -= 0.25;
if (pixel.charge <= 0) {
delete pixel.charge;
//console.log(elements[pixel.element].chargeCD);
var chargeCd = elements[pixel.element].chargeCD ?? 4;
pixel.chargeCD = chargeCd; //Customizable chargeCD
}
}
// Lower charge cooldown
else if (pixel.chargeCD) {
pixel.chargeCD -= 1;
if (pixel.chargeCD <= 0) {
delete pixel.chargeCD;
if (elements[pixel.element].colorOn) {
pixel.color = pixelColorPick(pixel);
}
}
}
}
//MORE CONFIGURABLE FIRE (fireMod changes) ##
//Variable
fireSpawnBlacklist = ["fire","cold_fire","rad_fire"];
//doBurning
function doBurning(pixel) {
if (pixel.burning) { // Burning
if (settings.burn === 0) { return }
if (pixel.burnStart === undefined) { pixel.burnStart = pixelTicks }
var info = elements[pixel.element];
var burnTempChange = info.burnTempChange ?? 1;
var fireIsCold;
var fire = info.fireElement === undefined ? "fire" : info.fireElement; //allow null but disallow undefined
//console.log(info.fireElement,fire);
while(fire instanceof Array) {
fire = fire[Math.floor(Math.random()*fire.length)];
};
var fireTemp = info.fireSpawnTemp ?? pixel.temp;
var fireChance = info.fireSpawnChance ?? 10;
var fireIsCold = (fire === "cold_fire");
//var fireInfo = fire === null ? null : elements[fire];
if (!info.insulate) { pixel.temp += burnTempChange };
pixelTempCheck(pixel);
if ((!fireIsCold && pixel.temp < 0) || (fireIsCold && pixel.temp > 100)) {
delete pixel.burning;
delete pixel.burnStart;
return;
}
for (var i = 0; i < adjacentCoords.length; i++) { // Burn adjacent pixels
var x = pixel.x+adjacentCoords[i][0];
var y = pixel.y+adjacentCoords[i][1];
if (!isEmpty(x,y,true)) {
var newPixel = pixelMap[x][y];
var newInfo = elements[newPixel.element];
var newFireIsCold;
var newFire = newInfo.fireElement == undefined ? "fire" : newInfo.fireElement;
while(newFire instanceof Array) {
newFire = newFire[Math.floor(Math.random()*newFire.length)];
};
newFireIsCold = (newFire === "cold_fire");
//console.log(`burning pixel ${pixel.element}: ${fire} (${fireIsCold}) / burned element ${newPixel.element}: ${newFire} (${newFireIsCold})`);
if((!fireIsCold && !newFireIsCold) || (fireIsCold && newFireIsCold)) {
if (elements[newPixel.element].burn && !newPixel.burning) {
if (Math.floor(Math.random()*100) < elements[newPixel.element].burn) {
newPixel.burning = true;
newPixel.burnStart = pixelTicks;
}
}
}
}
}
if ((pixelTicks - pixel.burnStart > (info.burnTime || 200)) && Math.floor(Math.random()*100)<(info.burn || 10)) {
var burnInto = info.burnInto ?? "fire";
while(burnInto instanceof Array) {
burnInto = burnInto[Math.floor(Math.random()*burnInto.length)];
};
changePixel(pixel,burnInto,burnInto !== "smoke");
//console.log("ass");
pixel.temp = fireTemp;
if (info.fireColor != undefined && burnInto == "fire") {
pixel.color = pixelColorPick(pixel,info.fireColor);
}
else {
pixel.color = pixelColorPick(pixel)
}
}
else if (Math.floor(Math.random()*100)smoke
elements.fire.tick = function(pixel){
if (pixel.start === pixelTicks) {return}
if (pixel.charge && elements[pixel.element].behaviorOn) {
pixelTick(pixel)
}
var move1Spots = [
[pixel.x, pixel.y-1],
[pixel.x+1, pixel.y-1],
[pixel.x-1, pixel.y-1],
]
var moved = false;
for (var i = 0; i < move1Spots.length; i++) {
var coords = move1Spots[Math.floor(Math.random()*move1Spots.length)];
coords = {x: coords[0], y: coords[1]};
if(!isEmpty(coords.x,coords.y,true) && pixelMap[coords.x]?.[coords.y]?.element == pixel.element && pixelMap[coords.x][coords.y].temp < pixel.temp) {
swapPixels(pixel,pixelMap[coords.x][coords.y]);
moved = true; break
} else {
if (tryMove(pixel, coords.x, coords.y)) { moved = true; break; }
else { move1Spots.splice(move1Spots.indexOf(coords), 1);}
}
}
if (!moved && !pixel.del) {
var move2Spots = [
[pixel.x, pixel.y+1],
[pixel.x+1, pixel.y],
[pixel.x-1, pixel.y],
]
for (var i = 0; i < move2Spots.length; i++) {
var coords = move2Spots[Math.floor(Math.random()*move2Spots.length)];
if (tryMove(pixel, coords[0], coords[1])) { break; }
else { move2Spots.splice(move2Spots.indexOf(coords), 1); }
}
}
if (!pixel.del) { doDefaults(pixel); }
if (!pixel.del && settings.burn===0 && (pixelTicks-pixel.start > 70) && Math.random() < 0.1 ) { changePixel(pixel,"smoke",false) };
};
//New elements
elements.cold_fire.burning = true;
elements.cold_fire.burnTempChange = -1;
elements.cold_fire.burnTime = 25;
elements.cold_fire.burnInto = "cold_smoke";
elements.cold_fire.fireElement = "cold_fire";
elements.cold_fire.behavior = [
"M1|M1|M1",
"M2|XX|M2",
"XX|M2|XX"
],
elements.cold_smoke = {
color: "#282848",
behavior: behaviors.DGAS,
reactions: {
"steam": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"rain_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"snow_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"hail_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"acid_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,12], "setting":"clouds" },
"fire_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,12], "setting":"clouds" },
"pyrocumulus": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" }
},
temp: -100,
tempHigh: 0,
stateHigh: "smoke",
tempLow: -114,
stateLow: "cold_fire",
category: "gases",
state: "gas",
density: 1280,
stain: 0.075,
};
elements.rad_fire = { //this is BBB
color: ["#daff21","#a6ff00","#ffff00"],
behavior: [
"XX|CR:radiation%0.1|XX",
"CR:radiation%0.1|DEL%0.02 AND CH:rad_smoke%0.2|CR:radiation%0.1",
"XX|CR:radiation%0.1|XX",
],
tick: function(pixel) {
if(Math.random() < 0.4) {
pixel.temp++;
};
if(Math.random() < 0.05) { //5%/t to radify
if(typeof(transformAdjacent) === "function" && typeof(radioactiveObject) === "object") {
transformAdjacent(pixel,radioactiveObject);
};
};
var move1Spots = [[-1,-1],[0,-1],[1,-1]];
var move2Spots = [[-1,0],[0,1],[1,0]];
var randomMove1 = move1Spots[Math.floor(Math.random() * move1Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove1[0], pixel.y+randomMove1[1])) {
//console.log((pixel.x+randomMove1[0]) + " " + (pixel.y+randomMove1[1]))
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1]) || !reactionStealer(pixel,newPixel,"radiation")) {
var randomMove2 = move2Spots[Math.floor(Math.random() * move2Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove2[0], pixel.y+randomMove2[1])) {
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(newPixel !== null) { reactionStealer(pixel,newPixel,"radiation") };
};
};
};
doDefaults(pixel);
},
reactions: { //fire + radiation reacts
//Merged water-radiation reactions, plus altered seltzer
"water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"steam": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"carbon_dioxide": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"dirty_water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"salt_water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"sugar_water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"seltzer": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
//Radiation reactions added programatically
},
temp:800,
tempLow:150,
stateLow: "rad_smoke",
//tempHigh: 7000,
//stateHigh: "rad_plasma",
category: "energy",
burning: true,
fireElement: "radiation",
state: "gas",
density: 0.1,
ignoreAir: true,
};
elements.rad_smoke = {
color: "#415c25",
behavior: behaviors.DGAS,
behavior: [
"XX|CR:radiation%0.05|XX",
"CR:radiation%0.05|XX|CR:radiation%0.05",
"XX|CR:radiation%0.05|XX",
],
tick: function(pixel) {
if(Math.random() < 0.05) {
deletePixel(pixel.x,pixel.y);
return;
};
if(Math.random() < 0.2) {
pixel.temp++;
};
if(Math.random() < 0.04) { //4%/t to radify
if(typeof(transformAdjacent) === "function" && typeof(radioactiveObject) === "object") {
transformAdjacent(pixel,radioactiveObject);
};
};
var move1Spots = [[0,-1],[1,0],[0,1],[-1,0]];
var move2Spots = [[-1,-1],[1,-1],[1,1],[-1,1]];
var randomMove1 = move1Spots[Math.floor(Math.random() * move1Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove1[0], pixel.y+randomMove1[1])) {
//console.log((pixel.x+randomMove1[0]) + " " + (pixel.y+randomMove1[1]))
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1]) || !reactionStealer(pixel,newPixel,"radiation")) {
var randomMove2 = move2Spots[Math.floor(Math.random() * move2Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove2[0], pixel.y+randomMove2[1])) {
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(newPixel !== null) { reactionStealer(pixel,newPixel,"radiation") };
};
};
};
doDefaults(pixel);
},
reactions: {
//Spreading
"liquid_fire": { "elem2":"liquid_rad_fire", "chance":0.2 },
"fire": { "elem2":"rad_fire", "chance":0.2 },
"smoke": { "elem2":"rad_smoke", "chance":0.2 },
/*"steam": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"rain_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"snow_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"hail_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"acid_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,12], "setting":"clouds" },
"fire_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,12], "setting":"clouds" },
"pyrocumulus": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },*/
//Radiation reactions added programatically
},
temp: 134,
tempHigh: 595,
stateHigh: "rad_fire",
category: "gases",
state: "gas",
density: 1340,
stain: 0.075,
};
elements.holy_fire = {
color: ["#FFFF96","#FFBF49","#CE743B"], //placeholder
tick: function(pixel) {
var moveResult = tryMoveAndReturnBlockingPixel(pixel,pixel.x + randomSign(),pixel.y - 1);
var blockingPixels = [];
var secondMoveResult = null;
if(typeof(moveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(moveResult.element))) {
blockingPixels.push(moveResult)
};
//if move1Result = true then nothing else happens
if(moveResult !== true) {
var coords = randomChoice([[-1,0],[0,1],[1,0]]).map(offsetPair => addArraysInPairs(offsetPair,[pixel.x,pixel.y]));
secondMoveResult = tryMoveAndReturnBlockingPixel(pixel,...coords);
if(typeof(secondMoveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(secondMoveResult.element))) {
blockingPixels.push(secondMoveResult)
};
};
if(blockingPixels.length > 0) {
blockingPixels.forEach(function(pixel) {
var blessRxn = elements.bless.reactions[pixel.element];
if(typeof(blessRxn) == "object") {
var elem2 = blessRxn.elem2;
if(elem2 !== null) {
while(Array.isArray(elem2)) { elem2 = randomChoice(elem2) };
changePixel(pixel,elem2)
}
};
var value = Math.random();
if(value < 0.01) {
if(pixel.burnInto) {
finishBurn(pixel)
} else {
changePixel(pixel,randomChoice(["ash","ash","light"]))
}
} else if(value < 0.20) {
pixel.burning = true;
pixel.burnStart ??= pixelTicks;
} else if(value < 0.205) {
changePixel(pixel,randomChoice(["ash","ash","light"]))
} else {
pixel.temp += 10; pixelTempCheck(pixel)
};
return
})
};
doDefaults(pixel);
},
temp:6000,
tempLow:1000,
stateLow: ["bless","fire"],
burnInto: ["bless","fire"],
category: "energy",
burning: true,
burnTime: 500,
burnTempChange: 8,
fireElement: ["bless","plasma"],
ignore: ["ash","light","bless","plasma","fire","smoke","liquid_holy_fire"].concat(searchElements("haseulite")).concat("haseulite_singularity"),
state: "gas",
density: 0.08,
ignoreAir: true
};
elements.holy_bomb = {
color: ["#dbb260", "#94591e"],
tick: function(pixel) {
if(!isEmpty(pixel.x,pixel.y-1,true)) { //[0][1] EX (ignore bounds)
var newPixel = pixelMap[pixel.x][pixel.y-1];
var newElement = newPixel.element;
var newInfo = elements[newElement];
if(newInfo.state !== "gas" && newElement !== pixel.element) {
explodeAtPlus(pixel.x,pixel.y,13,"holy_fire","plasma",null,firebombFire);
};
};
if(!isEmpty(pixel.x,pixel.y+1,true)) { //[2][1] EX (don't ignore bounds, non-bound case)
var newPixel = pixelMap[pixel.x][pixel.y+1];
var newElement = newPixel.element;
var newInfo = elements[newElement];
if(newInfo.state !== "gas" && newElement !== pixel.element) {
explodeAtPlus(pixel.x,pixel.y,13,"holy_fire","plasma",null,firebombFire);
};
};
if(outOfBounds(pixel.x,pixel.y+1)) { //[2][1] EX (don't ignore bounds, bound case)
explodeAtPlus(pixel.x,pixel.y,13,"holy_fire","plasma",null,firebombFire);
};
if(!tryMove(pixel,pixel.x,pixel.y+1)) { //behaviors.POWDER
Math.random() < 0.5 ? tryMove(pixel,pixel.x-1,pixel.y+1) : tryMove(pixel,pixel.x+1,pixel.y+1);
};
},
category: "weapons",
state: "solid",
density: 4000,
excludeRandom: true,
desc: "A bomb that burns the world to pure ash. To enable automatic bomb generation, set the generateBombs query parameter.",
};
elements.bless.ignore ??= [];
elements.bless.ignore.push("holy_fire");
elements.plasma_explosion = {
color: ["#c78fff","#ea8fff","#be8fff"],
tick: function(pixel) {
explodeAtPlus(pixel.x,pixel.y,10,"plasma","fire");
return
},
temp: 6500,
category: "energy",
state: "gas",
density: 1000,
excludeRandom: true,
noMix: true
};
elements.god_slayer_fire = {
color: ["#FFBACE","#FC6DCA","#9954B0"],
tick: function(pixel) {
var moveResult = tryMoveAndReturnBlockingPixel(pixel,pixel.x + randomSign(),pixel.y - 1);
var blockingPixels = [];
var secondMoveResult = null;
if(typeof(moveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(moveResult.element))) {
blockingPixels.push(moveResult)
};
//if move1Result = true then nothing else happens
if(moveResult !== true) {
var coords = randomChoice([[-1,0],[0,1],[1,0]]).map(offsetPair => addArraysInPairs(offsetPair,[pixel.x,pixel.y]));
secondMoveResult = tryMoveAndReturnBlockingPixel(pixel,...coords);
if(typeof(secondMoveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(secondMoveResult.element))) {
blockingPixels.push(secondMoveResult)
};
};
if(blockingPixels.length > 0) {
blockingPixels.forEach(function(pixel) {
var value = Math.random();
var randomDefaultResult = randomChoice(["ash","slag","plasma"]);
var oldTemp = pixel.temp;
if(value < 0.03) {
if(pixel.stateHigh) {
meltPixel(pixel);
}
} else if(value < 0.06) {
if(pixel.burnInto) {
finishBurn(pixel);
} else {
changePixel(pixel,randomDefaultResult)
}
} else if(value < 0.09) {
if(pixel.breakInto) {
breakPixel(pixel);
} else {
changePixel(pixel,randomDefaultResult)
}
} else if(value < 0.24) {
pixel.burning = true;
pixel.burnStart ??= pixelTicks;
} else if(value < 0.245) {
changePixel(pixel,randomDefaultResult)
} else {
pixel.temp += 25; pixelTempCheck(pixel)
};
if(pixel) {
pixel.temp = Math.max(oldTemp,pixel.temp)
};
return
})
};
doDefaults(pixel);
},
temp:10000,
tempLow:1500,
stateLow: ["plasma_explosion","plasma","plasma","plasma","plasma","plasma","plasma","plasma"],
burnInto: ["plasma_explosion","plasma","plasma","plasma","plasma","plasma","plasma","plasma"],
category: "energy",
ignore: ["ash","slag","wall","plasma","fire","smoke","liquid_god_slayer_fire"].concat(searchElements("haseulite")).concat("haseulite_singularity"),
burning: true,
burnTime: 500,
burnTempChange: 10,
fireElement: ["plasma"],
state: "gas",
density: 0.07,
ignoreAir: true
};
elements.liquid_holy_fire = {
color: ["#FFFF96","#FFBF49","#CE743B"], //placeholder
tick: function(pixel) {
var moveResult = tryMoveAndReturnBlockingPixel(pixel,pixel.x + randomIntegerBetweenTwoValues(-1,1),pixel.y + 1);
var blockingPixels = [];
var secondMoveResult = null;
if(typeof(moveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(moveResult.element))) {
blockingPixels.push(moveResult)
};
//if move1Result = true then nothing else happens
if(moveResult !== true) {
var coords = [randomSign(),0].map(offsetPair => addArraysInPairs(offsetPair,[pixel.x,pixel.y]));
secondMoveResult = tryMoveAndReturnBlockingPixel(pixel,...coords);
if(typeof(secondMoveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(secondMoveResult.element))) {
blockingPixels.push(secondMoveResult)
};
};
if(blockingPixels.length > 0) {
blockingPixels.forEach(function(pixel) {
var blessRxn = elements.bless.reactions[pixel.element];
if(typeof(blessRxn) == "object") {
var elem2 = blessRxn.elem2;
if(elem2 !== null) {
while(Array.isArray(elem2)) { elem2 = randomChoice(elem2) };
changePixel(pixel,elem2)
}
};
var value = Math.random();
if(value < 0.01) {
if(pixel.burnInto) {
finishBurn(pixel)
} else {
changePixel(pixel,randomChoice(["ash","ash","light"]))
}
} else if(value < 0.20) {
pixel.burning = true;
pixel.burnStart ??= pixelTicks;
} else if(value < 0.205) {
changePixel(pixel,randomChoice(["ash","ash","light"]))
} else {
pixel.temp += 10; pixelTempCheck(pixel)
};
return
})
};
doDefaults(pixel);
},
temp:8000,
tempLow:2000,
stateLow: "holy_fire",
burnInto: ["bless","fire"],
category: "energy",
burning: true,
burnTime: 1000,
burnTempChange: 10,
fireElement: "holy_fire",
ignore: ["light","bless","wall","plasma","fire","smoke","holy_fire"].concat(searchElements("haseulite")).concat("haseulite_singularity"),
state: "liquid",
density: 270,
ignoreAir: true
};
elements.liquid_god_slayer_fire = {
color: ["#FFBACE","#FC6DCA","#9954B0"],
tick: function(pixel) {
var moveResult = tryMoveAndReturnBlockingPixel(pixel,pixel.x + randomIntegerBetweenTwoValues(-1,1),pixel.y + 1);
var blockingPixels = [];
var secondMoveResult = null;
if(typeof(moveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(moveResult.element))) {
blockingPixels.push(moveResult)
};
//if move1Result = true then nothing else happens
if(moveResult !== true) {
var coords = [randomSign(),0].map(offsetPair => addArraysInPairs(offsetPair,[pixel.x,pixel.y]));
secondMoveResult = tryMoveAndReturnBlockingPixel(pixel,...coords);
if(typeof(secondMoveResult) == "object" && !(elements[pixel.element].ignore.concat(pixel.element).includes(secondMoveResult.element))) {
blockingPixels.push(secondMoveResult)
};
};
if(blockingPixels.length > 0) {
blockingPixels.forEach(function(pixel) {
var value = Math.random();
var randomDefaultResult = randomChoice(["ash","slag","plasma"]);
var oldTemp = pixel.temp;
if(value < 0.03) {
if(pixel.stateHigh) {
meltPixel(pixel);
}
} else if(value < 0.06) {
if(pixel.burnInto) {
finishBurn(pixel);
} else {
changePixel(pixel,randomDefaultResult)
}
} else if(value < 0.09) {
if(pixel.breakInto) {
breakPixel(pixel);
} else {
changePixel(pixel,randomDefaultResult)
}
} else if(value < 0.24) {
pixel.burning = true;
pixel.burnStart ??= pixelTicks;
} else if(value < 0.245) {
changePixel(pixel,randomDefaultResult)
} else {
pixel.temp += 25; pixelTempCheck(pixel)
};
if(pixel) {
pixel.temp = Math.max(oldTemp,pixel.temp)
};
return
})
};
doDefaults(pixel);
},
temp:15000,
tempLow:2000,
stateLow: ["plasma_explosion","liquid_plasma","liquid_plasma","liquid_plasma","liquid_plasma","liquid_plasma","liquid_plasma","liquid_plasma"],
burnInto: "god_slayer_fire",
category: "energy",
ignore: ["ash","slag","wall","plasma","fire","smoke","god_slayer_fire"].concat(searchElements("haseulite")).concat("haseulite_singularity"),
burning: true,
burnTime: 1000,
burnTempChange: 14,
fireElement: "god_slayer_fire",
state: "liquid",
density: 380,
ignoreAir: true
};
elements.god_slayer_bomb = {
color: ["#a43dcc", "#49b6d1"],
tick: function(pixel) {
if(!isEmpty(pixel.x,pixel.y-1,true)) { //[0][1] EX (ignore bounds)
var newPixel = pixelMap[pixel.x][pixel.y-1];
var newElement = newPixel.element;
var newInfo = elements[newElement];
if(newInfo.state !== "gas" && newElement !== pixel.element) {
explodeAtPlus(pixel.x,pixel.y,40,"god_slayer_fire","plasma");
};
};
if(!isEmpty(pixel.x,pixel.y+1,true)) { //[2][1] EX (don't ignore bounds, non-bound case)
var newPixel = pixelMap[pixel.x][pixel.y+1];
var newElement = newPixel.element;
var newInfo = elements[newElement];
if(newInfo.state !== "gas" && newElement !== pixel.element) {
explodeAtPlus(pixel.x,pixel.y,40,"god_slayer_fire","plasma");
};
};
if(outOfBounds(pixel.x,pixel.y+1)) { //[2][1] EX (don't ignore bounds, bound case)
explodeAtPlus(pixel.x,pixel.y,40,"god_slayer_fire","plasma");
};
if(!tryMove(pixel,pixel.x,pixel.y+1)) { //behaviors.POWDER
Math.random() < 0.5 ? tryMove(pixel,pixel.x-1,pixel.y+1) : tryMove(pixel,pixel.x+1,pixel.y+1);
};
},
category: "weapons",
state: "solid",
density: 4500,
excludeRandom: true,
desc: "A bomb that makes gods tremble. To enable automatic bomb generation, set the generateBombs query parameter.",
};
elements.cloner.burnTime = Infinity;
elements.cloner.burnInto = "cloner";
elements.cold_torch = {
"color": "#4394d6",
"behavior": [
"XX|CR:cold_fire|XX",
"XX|XX|XX",
"XX|XX|XX"
],
"reactions": {
"water": { "elem1": "wood" },
"sugar_water": { "elem1": "wood" },
"salt_water": { "elem1": "wood" },
"seltzer": { "elem1": "wood" },
"dirty_water": { "elem1": "wood" },
"pool_water": { "elem1": "wood" },
"steam": { "elem1": "wood" },
"smog": { "elem1": "wood" },
"rain_cloud": { "elem1": "wood" },
"cloud": { "elem1": "wood" },
"snow_cloud": { "elem1": "wood" },
"hail_cloud": { "elem1": "wood" },
"black_damp": { "elem1": "wood" }
},
"temp": -200,
"category": "special",
"breakInto": "sawdust",
"tempHigh": 600,
"stateHigh": "wood",
};
var GTDR = { "elem1": "torch", chance: 0.01 }; //grand torch degradation reaction
elements.grand_torch = {
"color": "#FFBF2F",
"tick": function(pixel) {
var coords = circleCoords(pixel.x,pixel.y,2).concat([[-1,-2],[1,-2],[-1,2],[1,2],[-2,-1],[2,-1],[-2,1],[2,1],[-1,-3],[0,-3],[1,-3],[0,-4],[0,-5]].map(
function(offsets) {
return {x: offsets[0]+pixel.x, y: offsets[1]+pixel.y}
}
));
for(var i = 0; i < coords.length; i++) {
var coordPair = coords[i];
if(outOfBounds(coordPair.x,coordPair.y)) { continue };
if(coordPair.x == pixel.x && coordPair.y == pixel.y) { continue };
if(!(isEmpty(coordPair.x,coordPair.y))) { continue };
var newPixel = tryCreatePixelReturn("fire",coordPair.x,coordPair.y);
if(typeof(newPixel) == "object") {
newPixel.temp = pixel.temp
}
};
},
"reactions": {
"water": GTDR,
"sugar_water": GTDR,
"salt_water": GTDR,
"seltzer": GTDR,
"dirty_water": GTDR,
"pool_water": GTDR,
"steam": GTDR,
"smog": GTDR,
"rain_cloud": GTDR,
"cloud": GTDR,
"snow_cloud": GTDR,
"hail_cloud": GTDR,
"black_damp": { "elem1": "wood", chance: 0.02 },
"magic": { "elem1": ["grand_torch","grand_torch","grand_plasma_torch"], "elem2": null, changeTemp: true }
},
"temp": 1500,
"category": "special",
"breakInto": "charcoal",
"tempHigh": 6000,
"stateHigh": "grand_plasma_torch",
"tempLow": 1000,
"stateLow": "torch",
};
elements.torch.reactions ??= {};
elements.torch.reactions.magic = { elem1: ["torch","torch","grand_torch"], elem2: null, changeTemp: true };
elements.torch.tempHigh = 1500;
elements.torch.stateHigh = "grand_torch";
var PTDR = { "elem1": "wood", chance: 0.003 };
elements.plasma_torch = {
"color": "#86579c",
"tick": function(pixel) {
var rotation = -(((pixel.r ?? 0) % 4) + 1); //preserving the original behavior of 0 = up, 1 = left
var rotationInRadians = scale(rotation,0,4,0,Math.PI * 2);
var vector = [Math.cos(rotationInRadians), Math.sin(rotationInRadians)];
//base strength (distance) 2, plus 1 for each 500*C above 7K*C; when charged, increase by 10% for each full or partial unit of charge (0.25 yields 10%, 1 yields 10%, 1.55 yields 20%, 2 yields 20%...)
var strength = Math.max(2,Math.min(300, ((2 + Math.floor((pixel.temp - 7000) / 500)) * (1 + (Math.ceil(pixel.charge ?? 0) * 0.1))))); //bound to 2-300, in part for performance reasons
//console.log(strength);
for(var i = 1; i <= strength; i++) {
var newOffsets = vector.map(coord => Math.round(coord * i));
var finalPos = {x: pixel.x + newOffsets[0], y: pixel.y + newOffsets[1]};
//console.log({x:pixel.x,y:pixel.y},finalPos);
if(!(isEmpty(finalPos.x,finalPos.y))) {
if(pixelMap[finalPos.x]?.[finalPos.y] && pixelMap[finalPos.x][finalPos.y].element == "plasma") {
continue
} else {
break
}
};
var newPlasma = tryCreatePixelReturn("plasma",finalPos.x,finalPos.y);
if(!newPlasma) {
break
} else {
newPlasma.temp = pixel.temp
}
}
},
"reactions": {
"water": PTDR,
"sugar_water": PTDR,
"salt_water": PTDR,
"seltzer": PTDR,
"dirty_water": PTDR,
"pool_water": PTDR,
"steam": PTDR,
"smog": PTDR,
"rain_cloud": PTDR,
"cloud": PTDR,
"snow_cloud": PTDR,
"hail_cloud": PTDR,
"black_damp": { "elem1": "wood", change: 0.02 }
},
"temp": 7000,
"category": "special",
"breakInto": "charcoal",
"tempLow": 4999,
"stateLow": "grand_torch",
};
var GrPTDR = { "elem1": "plasma_torch", chance: 0.001 }; //grand plasma torch degradation reaction
elements.grand_plasma_torch = {
"color": "#b92eff",
"tick": function(pixel) {
var coords = circleCoords(pixel.x,pixel.y,4).concat([[4,4],[4,4],[3,3],[3,3],[1,1],[-1,-1],[-3,-3],[-4,-4],[-4,-4],[-3,-3],[-1,-1],[1,1],[0,0],[0,0],[0,0],[0,0],[1,1],[1,1],[2,2],[-1,-1],[-1,-1],[-2,-2]].map( //ae = filterCurrentPixels(function(pixel) { return pixel.element == "ivory_growth_crystal" }).map(px => [130-px.x,67-px.y])
function(offsets) {
return {x: offsets[0]+pixel.x, y: offsets[1]+pixel.y}
}
));
for(var i = 0; i < coords.length; i++) {
var coordPair = coords[i];
if(outOfBounds(coordPair.x,coordPair.y)) { continue };
if(coordPair.x == pixel.x && coordPair.y == pixel.y) { continue };
if(!(isEmpty(coordPair.x,coordPair.y))) { continue };
var newPixel = tryCreatePixelReturn("plasma",coordPair.x,coordPair.y);
if(typeof(newPixel) == "object") {
newPixel.temp = pixel.temp
}
};
},
"reactions": {
"water": GrPTDR,
"sugar_water": GrPTDR,
"salt_water": GrPTDR,
"seltzer": GrPTDR,
"dirty_water": GrPTDR,
"pool_water": GrPTDR,
"steam": GrPTDR,
"smog": GrPTDR,
"rain_cloud": GrPTDR,
"cloud": GrPTDR,
"snow_cloud": GrPTDR,
"hail_cloud": GrPTDR,
"black_damp": { "elem1": "wood", chance: 0.02 },
},
"temp": 8500,
"category": "special",
"breakInto": "charcoal",
"tempLow": 6000,
"stateLow": "plasma_torch",
};
elements.rad_torch = {
"color": "#85d643",
"behavior": [
"XX|CR:rad_fire|XX",
"XX|XX|XX",
"XX|XX|XX"
],
"reactions": {
"water": { "elem1": "wood" },
"sugar_water": { "elem1": "wood" },
"salt_water": { "elem1": "wood" },
"seltzer": { "elem1": "wood" },
"dirty_water": { "elem1": "wood" },
"pool_water": { "elem1": "wood" },
"steam": { "elem1": "wood" },
"smog": { "elem1": "wood" },
"rain_cloud": { "elem1": "wood" },
"cloud": { "elem1": "wood" },
"snow_cloud": { "elem1": "wood" },
"hail_cloud": { "elem1": "wood" },
"black_damp": { "elem1": "wood" }
},
"temp": 800,
"category": "special",
"breakInto": "sawdust",
"tempLow": -273,
"stateHigh": "wood",
};
elements.mystic_torch = {
"color": ["#8e27ba", "#b3297e"],
"behavior": [
"XX|CR:mystic_fire|XX",
"XX|XX|XX",
"XX|XX|XX"
],
"reactions": {
"water": { "elem2": "steam" },
"sugar_water": { "elem2": "steam" },
"salt_water": { "elem1": "salt" },
"seltzer": { "elem1": "steam" },
"dirty_water": { "elem1": "steam" },
"pool_water": { "elem1": "steam" },
"smog": { "elem1": "smoke" },
"rain_cloud": { "elem1": "cloud" },
"snow_cloud": { "elem1": "cloud" },
"hail_cloud": { "elem1": "cloud" },
"black_damp": { "elem1": "wood" }
},
"temp": 20000,
"category": "special",
"breakInto": ["molten_ash","carbon_dioxide","charcoal","electric","magic"],
"tempLow": 8000,
"stateLow": new Array(99).fill("mystic_torch").concat("plasma_torch"), //1 in 100 chance to cool to a plasma torch, to mitigate inexplicable explosive cooling's tendency to cause the torch to spontaneously "downgrade"
"hardness": 0.999
};
elements.mystic_fire.state = "gas";
elements.napalm = {
color: "#e0873e",
behavior: [
"XX|SA%40 AND ST|XX",
"M2%10 AND SA%40 AND ST|XX|M2%10 AND SA%40 AND ST",
"M2%50 AND M1%10|M1 AND SA%40 AND ST|M2%50 AND M1%10"
],
category: "weapons",
state: "liquid",
viscosity: 1000,
density: 1200, //google was f***ing useless and i'm not searching that again, so arbitrary 1.2 it is
burnTempChange: 3,
burn: 300,
burnTime: 500,
temp: airTemp,
};
elements.hypernapalm = {
name: "h y p e r n a p a l m", //HYPERNAPALM
color: "#bd34eb",
behavior: [
"XX|SA%40 AND ST|XX",
"M2%10 AND SA%40 AND ST|XX|M2%10 AND SA%40 AND ST",
"M2%50 AND M1%10|M1 AND SA%40 AND ST|M2%50 AND M1%10"
],
category: "weapons",
state: "liquid",
viscosity: 1000,
density: 1200,
fireElement: "plasma",
fireSpawnChance: 33,
fireSpawnTemp: 7200,
burnTempChange: 30,
burn: 300,
burnTime: 500,
};
elements.cold_napalm = {
color: "#3e87e0",
behavior: [
"XX|SA%40 AND ST|XX",
"M2%10 AND SA%40 AND ST|XX|M2%10 AND SA%40 AND ST",
"M2%50 AND M1%10|M1 AND SA%40 AND ST|M2%50 AND M1%10"
],
category: "weapons",
state: "liquid",
viscosity: 1000,
density: 1200,
burn: 300,
burnTime: 500,
fireElement: "cold_fire",
burnTempChange: -1,
burnInto: "cold_fire",
};
elements.rad_napalm = {
color: "#cdf760",
behavior: [
"XX|SA%40 AND ST AND CR:radiation%1|XX",
"M2%10 AND SA%40 AND ST AND CR:radiation%1|HT%2.5|M2%10 AND SA%40 AND ST AND CR:radiation%1",
"M2%50 AND M1%10|M1 AND SA%40 AND ST AND CR:radiation%1|M2%50 AND M1%10"
],
category: "weapons",
state: "liquid",
viscosity: 1000,
density: 1300,
burnTempChange: 2,
burn: 300,
burnTime: 500,
fireElement: "rad_fire",
temp: airTemp,
burnInto: "rad_fire",
};
runAfterLoad(function() {
if(eLists.spout) {
eLists.spout.push("cold_torch");
eLists.spout.push("rad_torch");
};
elements.liquid_fire = {
color: ["#ff6b21","#ffa600","#ff4000"],
behavior: [
"XX|M2|XX",
"M2|XX|M2",
"M1|M1|M1",
],
reactions: {
"water": { "elem1": "liquid_smoke" },
},
temp:600,
tempLow:100,
stateLow: "liquid_smoke",
tempHigh: 7000,
stateHigh: "liquid_plasma",
category: "energy liquids",
burning: true,
burnTime: Infinity,
burnTempChange: 2,
fireSpawnChance: 5,
state: "liquid",
density: 200,
};
elements.liquid_cold_fire = {
color: ["#21cbff","#006aff","#00ffff"],
behavior: [
"XX|M2|XX",
"M2|XX|M2",
"M1|M1|M1",
],
reactions: {
"fire": { "elem1": "liquid_smoke", "elem2": "liquid_smoke" },
"plasma": { "elem1": "le_liquid_light", "elem2": "le_liquid_light" }, //prefixed to avoid conflict with F&M liquid_light
},
temp:-200,
tempHigh:0,
stateHigh: "liquid_smoke",
burning: true,
burnTempChange: -2,
fireSpawnChance: 5,
burnTime: Infinity,
fireElement: "cold_fire",
category: "energy liquids",
state: "liquid",
density: 420,
};
elements.liquid_rad_fire = {
color: ["#daff21","#a6ff00","#ffff00"],
behavior: [
"XX|CR:radiation%0.1|XX",
"CR:radiation%0.1|XX|CR:radiation%0.1",
"XX|CR:radiation%0.1|XX",
],
tick: function(pixel) {
if(Math.random() < 0.4) {
pixel.temp++;
};
if(Math.random() < 0.06) { //6%/t to radify
if(typeof(transformAdjacent) === "function" && typeof(radioactiveObject) === "object") {
transformAdjacent(pixel,radioactiveObject);
};
};
var move1Spots = [[-1,1],[0,1],[1,1]];
var move2Spots = [[-1,0],[0,-1],[1,0]];
var randomMove1 = move1Spots[Math.floor(Math.random() * move1Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove1[0], pixel.y+randomMove1[1])) {
//console.log((pixel.x+randomMove1[0]) + " " + (pixel.y+randomMove1[1]))
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1]) || !reactionStealer(pixel,newPixel,"radiation")) {
var randomMove2 = move2Spots[Math.floor(Math.random() * move2Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove2[0], pixel.y+randomMove2[1])) {
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(newPixel !== null) { reactionStealer(pixel,newPixel,"radiation") };
};
};
};
doDefaults(pixel);
},
reactions: { //fire + radiation reacts
//Merged water-radiation reactions, plus altered seltzer
"water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"steam": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"carbon_dioxide": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"dirty_water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"salt_water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"sugar_water": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
"seltzer": { "elem1": "rad_smoke", "elem2":"rad_steam", "chance":0.4 },
//Radiation reactions added programatically
},
temp:800,
//tempLow:100,
//stateLow: "liquid_smoke",
//tempHigh: 7000,
//stateHigh: "liquid_plasma",
category: "energy liquids",
burning: true,
burnTime: Infinity,
burnTempChange: 3,
fireSpawnChance: 5,
fireElement: "rad_fire",
state: "liquid",
density: 210,
};
elements.radiation.reactions.liquid_fire = { "elem2":"liquid_rad_fire", "chance":0.05 };
elements.radiation.reactions.fire = { "elem2":"rad_fire", "chance":0.05 };
elements.radiation.reactions.smoke = { "elem2":"rad_smoke", "chance":0.07 };
runAfterLoad(function() {
for(key in elements.radiation.reactions) {
var value = elements.radiation.reactions[key];
if(typeof(elements.rad_fire.reactions[key]) === "undefined") {
elements.rad_fire.reactions[key] = value;
};
};
});
elements.unrealistically_flammable_gas.burnTempChange = 10;
elements.unrealistically_flammable_gas.fireElement = "plasma";
elements.unrealistically_flammable_powder.burnTempChange = 20;
elements.unrealistically_flammable_powder.fireElement = "plasma";
elements.burning_unrealistically_flammable_gas.burnTempChange = 15;
elements.burning_unrealistically_flammable_gas.fireElement = "plasma";
elements.burning_unrealistically_flammable_powder.burnTempChange = 30;
elements.burning_unrealistically_flammable_powder.fireElement = "plasma";
});
//FIND MODE AND PIXEL PROPERTIES LINKED TO SPECIAL CODE (acid_and_shapes.js functionality removed) ##
var style = document.createElement('style');
style.type = 'text/css';
style.id = 'findStatusStylesheet';
style.innerHTML = '.findStatus { color: #E11; text-decoration: none; }';
document.getElementsByTagName('head')[0].appendChild(style);
find = false;
findElement = "sand";
findColorPulseTimer = 0;
findColorPulseTimerSubTimer = 0;
function marasi(number) {
return Math.min(255,Math.round(Math.abs(Math.sin(number) * 255)));
};
function updateFindDescription() {
var elems = findElement;
if(elems instanceof Array) {
elems = elems.join(", ");
};
elements.find_toggle.desc = `I'm running out of keybindsIf this text is green or underlined, find mode is on. Currently finding: ${elems} (this display does not update automatically).
Click here to toggle find mode. This highlights the currently selected element. Click here to configure the find filter.`;
};
function toggleFind() {
if(find != true) {
find = true;
document.getElementById("findStatusStylesheet").innerHTML = '.findStatus { color: #1E1; text-decoration: underline; }'; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element.
} else {
find = false;
document.getElementById("findStatusStylesheet").innerHTML = '.findStatus { color: #E11; text-decoration: none; }';
};
updateFindDescription();
};
elements.find_toggle = {
color: [_cc.b.h, _cc.b.h, _cc.b.h, _cc.b.h, "#ff0000", "#ff0000", "#ff0000", "#ff0000"],
name: "find toggle (look at info)",
behavior: behaviors.SELFDELETE,
category: "special",
excludeRandom: true,
desc: `
I'm running out of keybindsIf this text is green or underlined, find mode is on. Currently finding: sand (this display does not update automatically).
Click here to toggle find mode. This highlights the currently selected element. Click here to configure the find filter.`,
};
function findFilterPrompt() {
var preElement = prompt("Enter the elements you want to highlight\nSeparate multiple elements with commas");
if(preElement === null || preElement === "") {
return false;
};
if(preElement.includes(",")) {
preElement = preElement.split(",");
findElement = preElement;
updateFindDescription();
return findElement;
};
findElement = preElement;
updateFindDescription();
return findElement;
};
var incrementt = 0;
var interval = setInterval( increment, 500/30);
function increment(){
incrementt = incrementt % (Math.PI*8.8) + (Math.PI/30);
}
shapeModes = ["normal","circles","triangles"];
function getShapeMode() {
return shapeModes[settings.shapeMode] ?? "normal";
};
specialProperties = {
/*red: {
specialFunction: function(pixel) { pixel.color = "rgb(255,0,0)" }
},*/
};
acidFunctions = {
sin: Math.sin,
tan: Math.tan,
none: function(number) { return number }
};
var tickBehaviorStringCache = {
POWDER: behaviors.POWDER.toString(),
LIQUID: behaviors.LIQUID.toString(),
UL_UR_OPTIMIZED: behaviors.UL_UR_OPTIMIZED.toString()
};
settings ??= {};
settings.shockoverlay ??= true;
viewInfo[1] = { // Normal View (Default)
name: "",
effects: true,
colorEffects: true,
pixel: function(pixel,ctx) {
var a = (settings.textures !== 0) ? pixel.alpha : undefined;
if (((elements[pixel.element].isGas && elements[pixel.element].glow !== false) || elements[pixel.element].glow || pixel.glow) && pixel.glow !== false) {
drawPlus(ctx,pixel.color,pixel.x,pixel.y,undefined,a)
// if (isEmpty(pixel.x+1,pixel.y) || isEmpty(pixel.x-1,pixel.y) || isEmpty(pixel.x,pixel.y+1) || isEmpty(pixel.x,pixel.y-1)) {}
}
else {
drawSquare(ctx,pixel.color,pixel.x,pixel.y,undefined,a)
}
if (settings.shockoverlay && pixel.charge && view !== 2) { // Yellow glow on charge
if (!elements[pixel.element].colorOn) {
drawSquare(ctx,"rgba(255,255,0,0.5)",pixel.x,pixel.y);
}
}
if (settings.burnoverlay && pixel.burning && view !== 2) { // Red glow on burn
if (!elements[pixel.element].burningColor) {
drawSquare(ctx,"rgba(255,0,0,0.5)",pixel.x,pixel.y);
}
}
}
};
function drawCursor() {
var layerCtx = canvasLayers.gui.getContext('2d');
var mouseOffset = Math.trunc(mouseSize/2);
var topLeft = [mousePos.x-mouseOffset,mousePos.y-mouseOffset];
var bottomRight = [mousePos.x+mouseOffset,mousePos.y+mouseOffset];
if(mouseSize % 2 == 0) {
bottomRight[0]--;
bottomRight[1]--;
};
// Draw a square around the mouse
layerCtx.strokeStyle = "white";
layerCtx.strokeRect(topLeft[0]*pixelSize,topLeft[1]*pixelSize,(bottomRight[0]-topLeft[0]+1)*pixelSize,(bottomRight[1]-topLeft[1]+1)*pixelSize);
// draw one transparent pixel in the center
if (settings.precision) {
layerCtx.fillStyle = "rgba(255,255,255,0.5)";
layerCtx.fillRect(mousePos.x*pixelSize,mousePos.y*pixelSize,pixelSize,pixelSize);
}
if (shaping) {
if (shaping === 1) { // Draw a white line from shapeStart.x to shapeStart.y
let coords = lineCoords(shapeStart.x,shapeStart.y,mousePos.x,mousePos.y);
coords.forEach((coord) => {
if (outOfBounds(coord[0],coord[1])) return;
drawSquare(layerCtx,"rgba(255,255,255,0.5)",coord[0],coord[1],undefined)
})
}
}
}
//I hate overwriting vanilla rendering functions
function drawSquare(ctx,color,x,y,scale=1,opacity=1) {
if (color) { ctx.fillStyle = color; }
if (ctx.globalAlpha !== opacity) { ctx.globalAlpha = opacity; }
ctx.fillRect(canvasCoord(x), canvasCoord(y), pixelSize*scale, pixelSize*scale);
}
canvasLayersPreRenderers = [];
canvasLayersPostRenderers = [];
drawLayers = function(includeBackground) {
//console.log("dl tick");
if (ctx === null || ctx === undefined) return
clearLayers();
ctx.clearRect(0, 0, canvas.width, canvas.height);
findColorPulseTimerSubTimer++;
if(findColorPulseTimerSubTimer >= 2) {
findColorPulseTimer++;
findColorPulseTimerSubTimer = 0;
};
if (settings.bg) { // Set background color
if(settings["bg"] instanceof Array) {
settings.bgAngle ??= 90;
var colors = settings.bg;
var angleDeg = settings.bgAngle;
var angleRad = (angleDeg) * Math.PI / 180;
if (canvas.style.backgroundColor !== colors) {
canvas.style.backgroundColor = `linear-gradient(${angleDeg}deg, ${colors.join(", ")})`;
}
if (includeBackground) {
ctx.fillStyle = ctx.createLinearGradient(
0,
0,
canvas.width * Math.cos(angleRad) + 0,
canvas.height * Math.sin(angleRad)
);
for(i = 0; i < colors.length; i++) {
var color = colors[i];
var position = i / (colors.length - 1);
ctx.fillStyle.addColorStop(position,color);
};
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
} else {
if (canvas.style.backgroundColor !== settings.bg) {
canvas.style.backgroundColor = settings.bg;
}
if (includeBackground) {
ctx.fillStyle = settings.bg;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
};
}
for(let i = 0; i < canvasLayersPreRenderers.length; i++) {
//console.log(i);
canvasLayersPreRenderers[i]();
}
for (let i = 0; i < canvasLayersPre.length; i++) {
const layerCanvas = canvasLayersPre[i];
ctx.drawImage(layerCanvas, 0, 0);
}
if (paused || pixelTicks !== lastPixelDraw) {
if (!drawPixels() && !paused) {
logMessage("One or more of your mods are outdated and cannot render properly.");
togglePause();
}
lastPixelDraw = pixelTicks;
}
drawCursor();
for(let i = 0; i < canvasLayersPostRenderers.length; i++) {
//console.log(i);
canvasLayersPostRenderers[i]();
}
for (let i = 0; i < canvasLayersPost.length; i++) {
const layerCanvas = canvasLayersPost[i];
ctx.drawImage(layerCanvas, 0, 0);
}
}
clearInterval(renderInterval);
renderInterval = window.setInterval(drawLayers, 1000/60);
viewInfo[4] = {
name: 'element',
pixel: function(pixel,ctx) {
var data = elements[pixel.element];
var _color = data.color;
if(Array.isArray(_color)) {
_color = _color[Math.floor(pixelTicks / 10) % _color.length]
};
drawSquare(ctx,_color,pixel.x,pixel.y,undefined,1 - (data.alpha ?? 0))
}
};
viewInfo[5] = {
name: 'velocity',
pixel: function(pixel,ctx) {
var data = elements[pixel.element];
var vx = pixel.vx ?? 0;
var vy = pixel.vy ?? 0;
var _color = null;
if(vx === 0 && vy === 0) {
_color = "rgb(15,15,15)"
} else {
var magnitude = Math.sqrt ((vx ** 2) + (vy ** 2));
var direction = Math.atan2(pixel.vy ?? 0,pixel.vx ?? 0)*180/Math.PI;
if(direction < 0) { direction = scale(direction,-180,0,360,180) };
hue = direction;
sat = 100;
lig = bound(scale(magnitude,0,100,10,100),0,100);
_color = "hsl("+hue+","+sat+"%,"+lig+"%)";
};
drawSquare(ctx,_color,pixel.x,pixel.y,undefined,1 - (data.alpha ?? 0))
}
};
canvasLayers.pressure = document.createElement("canvas");
canvasLayersPre.push(canvasLayers.pressure);
function drawPressure() {
var layerCtx = canvasLayers.pressure.getContext('2d');
if(!(settings.dopressure && settings.drawpressure)) {
return
} else {
for(var x = 0; x < pressureMap.length; x++) {
for(var y = 0; y < pressureMap[x].length; y++) {
var pressureValue = pressureMap[x][y];
if(typeof(pressureValue) == "number") {
var pressureSign = Math.sign(pressureValue);
pressureValue = bound(Math.abs(pressureValue),0,255) / 255;
switch(pressureSign) {
case -0:
case 0:
layerCtx.fillStyle = `rgb(0,0,0)`;
break
case 1:
layerCtx.fillStyle = `rgb(255,0,0)`;
break
case -1:
layerCtx.fillStyle = `rgb(0,0,255)`;
break
default: // covers NaN, since NaN != NaN
layerCtx.fillStyle = `rgb(127,127,127)`;
break
};
layerCtx.globalAlpha = isNaN(pressureSign) ? 0.5 : pressureValue;
layerCtx.fillRect(x*pixelSize*pressureCellSize, y*pixelSize*pressureCellSize, pixelSize*pressureCellSize, pixelSize*pressureCellSize)
} else {
layerCtx.fillStyle = `rgb(127,127,127)`;
layerCtx.globalAlpha = isNaN(pressureSign) ? 0.5 : pressureValue;
layerCtx.fillRect(x*pixelSize*pressureCellSize, y*pixelSize*pressureCellSize, pixelSize*pressureCellSize, pixelSize*pressureCellSize)
}
}
layerCtx.globalAlpha = 1;
}
}
//console.log("dp tick")
};
canvasLayersPreRenderers.push(drawPressure);
//I hate overwriting drawPixels
tempScale = 1;
tempScaleOffset = 20;
normalColorFunction = function(pixel) {
var colorOut = pixel.color;
for(var sry4thelag in specialProperties) {
if(pixel[sry4thelag] !== undefined && specialProperties[sry4thelag].specialColorFunction) {
colorOut = specialProperties[sry4thelag].specialColorFunction(pixel,oldColor=colorOut)
}
}
return colorOut;
}
/*5: function(pixel) { // velocity view
var data = elements[pixel.element];
var vx = pixel.vx ?? 0;
var vy = pixel.vy ?? 0;
/ *
var pseudoVelocity = 0;
var coordsToCheck;
var behaviorCoordsToCheck;
if(Array.isArray(data.behavior)) {
switch((pixel.r ?? 0) % 4) {
default:
case 0:
coordsToCheck = [0,1];
behaviorCoordsToCheckOffset = [2,1];
break;
case 1:
coordsToCheck = [-1,0];
behaviorCoordsToCheckOffset = [1,0];
break;
case 2:
coordsToCheck = [0,-1];
behaviorCoordsToCheckOffset = [0,1];
break;
case 3:
coordsToCheck = [1,0];
behaviorCoordsToCheckOffset = [1,2];
break;
};
if(data.behavior[behaviorCoordsToCheckOffset[0]][behaviorCoordsToCheckOffset[1]] == "M1") {
if(isEmpty(pixel.x+coordsToCheck[0],pixel.y+coordsToCheck[1])) {
pseudoVelocity = 1;
} else {
if(!(isEmpty(pixel.x+behaviorCoordsToCheckOffset[0],pixel.y+behaviorCoordsToCheckOffset[1],true))) {
newPixel = pixelMap[pixel.x+behaviorCoordsToCheckOffset[0]][pixel.y+behaviorCoordsToCheckOffset[1]];
newData = elements[newPixel.element];
if(newData.id !== data.id && typeof(data.density) === "number" && typeof(newData.density) === "number") {
var chance = (data.density - newData.density)/(data.density + newData.density);
pseudoVelocity = chance
}
}
}
};
if(pseudoVelocity) {
switch((pixel.r ?? 0) % 4) {
default:
case 0:
vy += pseudoVelocity;
break;
case 1:
vx -= pseudoVelocity;
break;
case 2:
vy -= pseudoVelocity;
break;
case 3:
vx += pseudoVelocity;
break;
}
};
} else {
if(data.tick && [behaviors.POWDER,behaviors.LIQUID].includes(data.tick)) {
pseudoVelocity = 1;
} else if(data.tick == behaviors.UL_UR_OPTIMIZED) {
pseudoVelocity = -1;
} else if(pixel.element == "hail") {
pseudoVelocity = 2;
};
vy += pseudoVelocity;
};
* /
if(vx === 0 && vy === 0) {
return "rgb(15,15,15)"
} else {
var magnitude = Math.sqrt ((vx ** 2) + (vy ** 2));
var direction = Math.atan2(pixel.vy ?? 0,pixel.vx ?? 0)*180/Math.PI;
if(direction < 0) { direction = scale(direction,-180,0,360,180) };
hue = direction;
sat = 100;
lig = bound(scale(magnitude,0,100,10,100),0,100);
return "hsl("+hue+","+sat+"%,"+lig+"%)";
}
},
6: function(pixel) {
var data = elements[pixel.element] ?? elements.unknown;
var originalColor = data.colorObject;
if(Array.isArray(originalColor)) {
originalColor = randomChoice(originalColor)
};
return convertColorFormats(originalColor,"rgb");
}
};*/
console.log("1/8 loaded") //True 1.8 is inside one viewColorFunctions[2]
hiding = false
function setView(n) {
if (!viewInfo[n]) { // reset view
view = 1;
}
else {
view = n;
}
}
didNewSettings = false;
runAfterLoad(function() {
viewInfo[2] = { // Thermal View
name: "thermal",
pixel: function(pixel,ctx) {
var temp = pixel.temp;
if (temp < -273.15) {temp = -273.15}
//if (temp > 165000) {temp = 165000}
// piecewise scale, linear from 250 (-273.15 degrees) to 225 (-50 degrees) and logarithmic from 225 (-50 degrees) to -90 (=275) (165,000 degrees)
var hue;
var sat = 100;
var lig = 50;
var extraHueDistance = 0;
if(temp < -50) {
hue = scale(-75,-273.15,-50,250,225);
} else {
hue = Math.round(225 - (Math.log(temp+50)/Math.log(6000+50))*225);
}
if(temp > 165000) { extraHueDistance = Math.abs(hue + 85) };
hue %= 360;
if (hue > 250) {hue = 250}
if (hue < 0) {hue += 360}
if (temp > 6050 && hue < 275) {hue = 275}
if (temp > 165000 && temp < 1105000) {
sat -= (extraHueDistance * 2); if(sat < 0) { sat == 0 }
lig += extraHueDistance; if(lig > 100) { lig == 100 }
};
if (temp > 1105000 && temp < 6305000) { hue = 120; sat = Math.round((extraHueDistance - 50) * (20/9)); lig = 100 - ((extraHueDistance - 50) * 16/9) } //painbow award contender
if (temp > 6305000 && temp < 3300000305000) { hue = (120 + (extraHueDistance - 95)) % 360; sat = 100; lig = 20 }
if (temp >= 3300000305000) { hue = 100; sat = 100; lig = 20 } //this scale is a painbow award contender
if(isNaN(hue) || isNaN(sat) || isNaN(lig)) {
drawSquare(ctx,"#FFBF7F",pixel.x,pixel.y)
} else {
drawSquare(ctx,"hsl("+hue+","+sat+"%,"+lig+"%)",pixel.x,pixel.y)
}
}
};
if(didNewSettings) { return };
//Setting
var settingsMenu = document.getElementById("settingsMenu").getElementsByClassName("menuText")[0];
var settingNodes = [...settingsMenu.childNodes].filter(function(node) { return node.nodeType == 1 });
var lastSetting = settingNodes[settingNodes.length - 1];
//console.log(lastSetting);
//console.log(lastSetting.getAttribute("style"));
lastSetting.removeAttribute("style"); //restore padding for worldgen setting;
//console.log(lastSetting.getAttribute("style"));
//Shape setting
// var shapeSettingSpan = document.createElement("span");
// shapeSettingSpan.setAttribute("setting","shapeMode");
// shapeSettingSpan.setAttribute("class","setting-span");
// shapeSettingSpan.textContent = "Pixel Shape (laggy) ";
// var settingDropdown = document.createElement("select");
// settingDropdown.setAttribute("onchange","settings.shapeMode = parseInt(this.value); saveSettings();");
// var options = {
// 0: "Squares",
// 1: "Circles",
// 2: "Triangles"
// };
// for(value in options) {
// var newOption = document.createElement("option");
// if(value == "0") {
// newOption.setAttribute("selected","");
// };
// newOption.setAttribute("value",value);
// newOption.innerText = options[value];
// settingDropdown.appendChild(newOption);
// };
// shapeSettingSpan.appendChild(settingDropdown);
// settingsMenu.appendChild(shapeSettingSpan);
//Acid function setting
// var acidFuncSpan = document.createElement("span");
// acidFuncSpan.setAttribute("setting","acidFunction");
// acidFuncSpan.setAttribute("class","setting-span");
// acidFuncSpan.textContent = "\"Acid\" distortion function";
// var settingDropdown = document.createElement("select");
// settingDropdown.setAttribute("onchange","settings.acidFunction = this.value; saveSettings();");
// var options = {
// "none": "None",
// "sin": "Sine",
// "tan": "Tangent"
// };
// for(value in options) {
// var newOption = document.createElement("option");
// if(value == "0") {
// console.log("selected",value);
// newOption.setAttribute("selected","")
// };
// newOption.setAttribute("value",value);
// newOption.innerText = options[value];
// settingDropdown.appendChild(newOption);
// };
// acidFuncSpan.appendChild(settingDropdown);
// settingsMenu.appendChild(acidFuncSpan);
//Handle the styling of the last setting
settingNodes = [...settingsMenu.childNodes].filter(function(node) { return node.nodeType == 1 });
lastSetting = settingNodes[settingNodes.length - 1];
//console.log(lastSetting);
lastSetting.setAttribute("style","padding-bottom:0"); //remove padding from last setting;
settings ??= {};
settings.burnoverlay ??= false;
var redBurnSettingSpan = document.createElement("span");
redBurnSettingSpan.setAttribute("setting","burnoverlay");
redBurnSettingSpan.setAttribute("title","Default: OFF");
redBurnSettingSpan.classList.add("setting-span","multisetting");
var settingInput = document.createElement("input");
settingInput.setAttribute("type","button");
settingInput.setAttribute("value","Burning Overlay");
settingInput.setAttribute("state","0");
settingInput.classList.add("toggleInput");
settingInput.setAttribute("onclick","toggleInput(this,'burnoverlay',false)");
var options = {
"false": "Disabled",
"true": "Enabled"
};
var newHelpMark = document.createElement("span");
newHelpMark.setAttribute("title","This adds a red overlay to burning pixels, like the yellow overlay for charged pixels.");
newHelpMark.classList.add("helpMark");
newHelpMark.innerText = "?";
redBurnSettingSpan.appendChild(settingInput);
redBurnSettingSpan.appendChild(newHelpMark);
var cheerfulSetting = document.querySelector('span[setting="cheerful"]');
cheerfulSetting.after(redBurnSettingSpan);
settings.shockoverlay ??= true;
var yellowShockSettingSpan = document.createElement("span");
yellowShockSettingSpan.setAttribute("setting","shockoverlay");
yellowShockSettingSpan.setAttribute("title","Default: ON");
yellowShockSettingSpan.classList.add("setting-span","multisetting");
var settingInput = document.createElement("input");
settingInput.setAttribute("type","button");
settingInput.setAttribute("value","Charge Overlay");
settingInput.setAttribute("state","1");
settingInput.classList.add("toggleInput");
settingInput.setAttribute("onclick","toggleInput(this,'shockoverlay',false)");
var options = {
"false": "Disabled",
"true": "Enabled"
};
var newHelpMark = document.createElement("span");
newHelpMark.setAttribute("title","This adds a yellow overlay for charged pixels (vanilla feature).");
newHelpMark.classList.add("helpMark");
newHelpMark.innerText = "?";
yellowShockSettingSpan.appendChild(settingInput);
yellowShockSettingSpan.appendChild(newHelpMark);
redBurnSettingSpan.after(yellowShockSettingSpan);
// settings.doacid ??= false;
// var acidSettingSpan = document.createElement("span");
// acidSettingSpan.setAttribute("setting","doacid");
// acidSettingSpan.setAttribute("title","Default: OFF");
// acidSettingSpan.classList.add("setting-span","multisetting");
// var settingInput = document.createElement("input");
// settingInput.setAttribute("type","button");
// settingInput.setAttribute("value",'"Acid" distortion');
// settingInput.setAttribute("state","0");
// settingInput.classList.add("toggleInput");
// settingInput.setAttribute("onclick","toggleInput(this,'doacid',false)");
// var options = {
// "false": "Disabled",
// "true": "Enabled"
// };
// var newHelpMark = document.createElement("span");
// newHelpMark.setAttribute("title","This adds a yellow overlay for charged pixels (vanilla feature).");
// newHelpMark.classList.add("helpMark");
// newHelpMark.innerText = "?";
// acidSettingSpan.appendChild(settingInput);
// acidSettingSpan.appendChild(newHelpMark);
// yellowShockSettingSpan.after(acidSettingSpan);
var rankineSettingSpan = document.createElement("span");
rankineSettingSpan.setAttribute("setting","userankine");
rankineSettingSpan.setAttribute("title","Default: OFF");
rankineSettingSpan.classList.add("setting-span","multisetting");
var settingInput = document.createElement("input");
settingInput.setAttribute("type","button");
settingInput.setAttribute("value",'Use degrees Rankine');
settingInput.setAttribute("state","0");
settingInput.classList.add("toggleInput");
settingInput.setAttribute("onclick","toggleInput(this,'userankine',false)");
var options = {
"false": "Disabled",
"true": "Enabled"
};
var newHelpMark = document.createElement("span");
newHelpMark.setAttribute("title","Use degrees Rankine (Fahrenheit based around absolute zero) for temperature display. Only affects imperial units.");
newHelpMark.classList.add("helpMark");
newHelpMark.innerText = "?";
rankineSettingSpan.appendChild(settingInput);
rankineSettingSpan.appendChild(newHelpMark);
// acidSettingSpan.after(rankineSettingSpan);
yellowShockSettingSpan.after(rankineSettingSpan);
var pressureSettingSpan = document.createElement("span");
pressureSettingSpan.setAttribute("setting","dopressure");
pressureSettingSpan.setAttribute("title","Default: OFF");
pressureSettingSpan.classList.add("setting-span","multisetting");
var settingInput = document.createElement("input");
settingInput.setAttribute("type","button");
settingInput.setAttribute("value",'Pressure simulation');
settingInput.setAttribute("state","0");
settingInput.classList.add("toggleInput");
settingInput.setAttribute("onclick","toggleInput(this,'dopressure',false)");
var options = {
"false": "Disabled",
"true": "Enabled"
};
var newHelpMark = document.createElement("span");
newHelpMark.setAttribute("title","Simplified pressure simulation (which may lag).");
newHelpMark.classList.add("helpMark");
newHelpMark.innerText = "?";
pressureSettingSpan.appendChild(settingInput);
pressureSettingSpan.appendChild(newHelpMark);
rankineSettingSpan.after(pressureSettingSpan);
var showPressureSettingSpan = document.createElement("span");
showPressureSettingSpan.setAttribute("setting","drawpressure");
showPressureSettingSpan.setAttribute("title","Default: OFF");
showPressureSettingSpan.classList.add("setting-span","multisetting");
var settingInput = document.createElement("input");
settingInput.setAttribute("type","button");
settingInput.setAttribute("value",'Show pressure');
settingInput.setAttribute("state","0");
settingInput.classList.add("toggleInput");
settingInput.setAttribute("onclick","toggleInput(this,'drawpressure',false)");
var options = {
"false": "Disabled",
"true": "Enabled"
};
var newHelpMark = document.createElement("span");
newHelpMark.setAttribute("title","Draw pressure (only applies if pressure simulation is enabled).");
newHelpMark.classList.add("helpMark");
newHelpMark.innerText = "?";
showPressureSettingSpan.appendChild(settingInput);
showPressureSettingSpan.appendChild(newHelpMark);
pressureSettingSpan.after(showPressureSettingSpan);
/*var disableTextSettingSpan = document.createElement("span");
disableTextSettingSpan.setAttribute("setting","disabletext");
disableTextSettingSpan.setAttribute("title","Default: OFF");
disableTextSettingSpan.classList.add("setting-span","multisetting");
var settingInput = document.createElement("input");
settingInput.setAttribute("type","button");
settingInput.setAttribute("value",'Disable text rendering');
settingInput.setAttribute("state","0");
settingInput.classList.add("toggleInput");
settingInput.setAttribute("onclick","toggleInput(this,'disabletext',false)");
var options = {
"false": "Disabled",
"true": "Enabled"
};
var newHelpMark = document.createElement("span");
newHelpMark.setAttribute("title","Don't render text on alphabet blocks.");
newHelpMark.classList.add("helpMark");
newHelpMark.innerText = "?";
disableTextSettingSpan.appendChild(settingInput);
disableTextSettingSpan.appendChild(newHelpMark);
showPressureSettingSpan.after(disableTextSettingSpan);*/
var sizeSetting = document.querySelector('span[setting="pixelsize"]');
var sizeDropdown = sizeSetting.querySelector("select");
sizeDropdown.setAttribute("onchange","var size = (this.value === 'null' ? null : parseFloat(this.value)); console.log(size); if((size >= 0.05) && (size <= 194.73749999999999) && (size !== null) && (size !== false) && !(isNaN(size))) { console.log(size); setSetting('pixelsize',size);this.nextElementSibling.innerText='Reset Scene' }");
var tinyOption = document.createElement("option");
tinyOption.setAttribute("value","12");
tinyOption.innerText = "Tiny";
sizeDropdown.insertAdjacentElement("afterbegin",tinyOption);
var hugeOption = document.createElement("option");
hugeOption.setAttribute("value","2");
hugeOption.innerText = "Huge";
sizeDropdown.insertAdjacentElement("beforeend",hugeOption);
var otherOption = document.createElement("option");
otherOption.setAttribute("value","null");
otherOption.innerText = "Other";
sizeDropdown.insertAdjacentElement("beforeend",otherOption);
pixelSizeSettingDropdownOtherOptionIndex = (sizeDropdown.children.length) - 1;
//Append code to showSettings to set every setting toggle button's state according to its setting's value on page load (so if you turned the setting on, the button is already green when you load the page)
function showSettingsButtonAutoUpdateAppendFunction() {
var toggleButtonSettings = document.querySelectorAll('span.setting-span.multisetting[setting]:has(input[type="button"])');
if(!(toggleButtonSettings?.forEach)) { return false };
toggleButtonSettings.forEach(function(node) {
var setting = node.getAttribute("setting");
if(!setting) { return false };
var button = node.querySelector('input[type="button"]');
if(!button) { return false };
var settingValue = !!(settings?.[setting]);
var newState = settingValue ? "1" : "0";
button.setAttribute("state",newState);
return true
})
};
oldShowSettings = eval(showSettings.toString()) //eval may be evil, but JS seems to have literally changed the way it works so functions are passed as references now instead of cloning, and so appending won't work;
showSettings = function() {
oldShowSettings();
showSettingsButtonAutoUpdateAppendFunction()
};
everyTick(function() {
if(paused) { return };
for(var propName in specialProperties) {
//thanks, I hate not being able to pass arguments to filter functions
var _filterFunction = function(pixel) {
return pixel.hasOwnProperty(propName)
};
var pixelsWithProp = currentPixels.filter(_filterFunction);
//console.log(pixelsWithProp.map(p => [p.x,p.y,propName,p[propName]].join(",")).join("\n"));
for(var i in pixelsWithProp) {
var propPixel = pixelsWithProp[i];
if(!propPixel || propPixel.del) { continue };
specialProperties[propName]?.specialFunction?.(propPixel);
};
}
})
didNewSettings = true
});
//FUNCTION EXECUTION WHEN A PIXEL TRIES TO MOVE INTO ANOTHER (onTryMoveInto) ##
elements.on_try_move_into_test = {
color: _cc.w.h,
properties: {
ticks: 0,
attemptedMovesIntoPixel: 0
},
behavior: behaviors.POWDER,
reactions: {
"dirt": { elem1: "diamond" }
},
state: "solid",
hidden: true,
excludeRandom: true,
category: "special",
density: 1000,
tick: function(pixel) {
pixel.ticks++;
},
onTryMoveInto: function(pixel,otherPixel) {
pixel.attemptedMovesIntoPixel++;
var otherElement = otherPixel.element;
if(otherElement === "ash") {
console.log(`This is a test of potentially undesired multiplicate running. (tick: ${pixelTicks}, move attempts: ${pixel.attemptedMovesIntoPixel})`);
//if(deletePixel(pixel.x,pixel.y)) {
// console.log("This pixel has been deleted.");
//};
};
},
desc: "Try burying this pixel and see what happens. (Use Debug)\n\nonTryMoveInto is run as part of tryMove, before reactions, while tick functions are run as part of pixelDraw.\nIn some circumstances, such as a pixel being buried under a pile of anything that isn't a sturdy powder, this function may run multiple times per tick. For example, bury this pixel in ash and look in the console.\n\nTo use this function, include in your element definition the \"onTryMoveInto\" key with a function value, similarly to tick functions. This function takes two arguments; \"otherPixel\" is the pixel that is trying to move and \"pixel\" is the pixel whose position otherPixel is trying to move into.",
related: ["debug", "ash"],
}
function tryMove(pixel,nx,ny,leaveBehind,force) {
if(!pixel) { return false };
if ((typeof(pixel.tempDrag) !== "undefined") && (!force)) {
if(typeof(pixel.tempDrag) === "number" && pixel.tempDrag >= pixelTicks) {
return true
} else {
delete pixel.tempDrag
}
};
if (pixel.drag && !force) { return true; }
var info = elements[pixel.element];
var oob = outOfBounds(nx,ny);
if(pixelMap[nx] === undefined) { return false }; //safety
if (isEmpty(nx,ny,false,oob)) { // If coords is empty, move to coords
//console.log(`Moving ${pixel.element} (${pixel.x},${pixel.y}) to (${nx},${ny})`);
movePixel(pixel,nx,ny,leaveBehind);
return true;
}
else if (!oob) {
//console.log(`Moving ${pixel.element} (${pixel.x},${pixel.y}) to (${nx},${ny})`);
// Reactions
newPixel = pixelMap[nx][ny];
var newInfo = elements[newPixel.element];
if(typeof(newInfo) == "undefined") { return false };
var returnVal = false;
if(newInfo.onTryMoveInto !== undefined) {
newInfo.onTryMoveInto(newPixel,pixel);
if(!pixel || pixel.del) {
return "deleted";
};
returnVal = false;
};
var rr1 = false;
if (info.reactions !== undefined && info.reactions[newPixel.element] !== undefined) {
rr1 = reactPixels(pixel,newPixel)
if (rr1) {
return true;
}
}
if (!rr1 && elements[newPixel.element].reactions !== undefined && elements[newPixel.element].reactions[pixel.element] !== undefined && !elements[newPixel.element].reactions[pixel.element].oneway) {
if (reactPixels(newPixel,pixel)) {
return true;
}
}
// Density
if (elements[pixel.element].id !== elements[newPixel.element].id) {
if (info.density !== undefined && elements[newPixel.element].density !== undefined) {
// if the pixel's state + ">" + newPixel's state is in validDensitySwaps, and the pixel's density is larger than the newPixel's density, swap the pixels
if (validDensitySwaps[info.state][elements[newPixel.element].state] && info.density >= elements[newPixel.element].density) {
// chance depending on the difference in density
if (Math.random() < (info.density - elements[newPixel.element].density)/(info.density + elements[newPixel.element].density)) {
swapPixels(pixel,newPixel);
return true;
}
}
}
}
if(returnVal) {
return true;
}
}
return false;
}
//PIXEL MOVER TOOLS ##
elements.move_up = {
color: "#1C0000",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x,pixel.y-1,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_down = {
color: "#000038",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x,pixel.y+1,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_left = {
color: "#007000",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x-1,pixel.y,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_right = {
color: "#000E00",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x+1,pixel.y,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_up_left = {
color: "#E00000",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x-1,pixel.y-1,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_down_left = {
color: "#0001C0",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x-1,pixel.y+1,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_up_right = {
color: "#038000",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x+1,pixel.y-1,null,true) };
},
category: "movement tools",
excludeRandom: true,
},
elements.move_down_right = {
color: "#000007",
tool: function(pixel) {
for(var i = 0; i < (shiftDown ? 3 : 1); i++) { tryMove(pixel,pixel.x+1,pixel.y+1,null,true) };
},
category: "movement tools",
excludeRandom: true,
}
//TOOL THAT DELETES EVERY ELEMENT OF THE CLICKED TYPE(S) ##
elements.delete_all_of_element = {
name: "delete all of element",
color: ["#a7a7a7", "#a7a7a7", "#a7a7a7", "#a7a7a7", _cc.b.h, _cc.b.h, _cc.b.h, _cc.b.h],
tool: function(pixel) {
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
if (!isEmpty(i,j)) {
if(pixelMap[i][j].element == pixel.element) {
deletePixel(i,j)
}
}
}
}
},
category: "tools",
excludeRandom: true,
};
//TEMPERATURE TOOLS ##
//base syntax by sightnado
/*elements.warm = {
color: "#7fff7f",
tool: function(pixel) {
pixel.temp = 20;
pixelTempCheck(pixel)
},
category: "tools",
};*/
//warm is redundant due to vanilla room_temp
elements.room_temp.category = "tools";
elements.slow_cool = {
color: elements.cook.color.map(colorCode => Object.values(convertColorFormats(colorCode,"json"))).map(x => RGBToHex(x.map(y => 255 - y))),
tool: function(pixel) {
pixel.temp -= (0.5 * (1 + shiftDown));
},
category: "energy",
excludeRandom: true
};
elements.ultraheat = {
color: ["#ff0000", "#ffbf4f", "#ff0000", "#ffbf4f", "#ff0000", "#ffbf4f"],
tool: function(pixel) {
if(shiftDown) { pixel.temp += (350 * (1 + shiftDown)) } else { pixel.temp += 350 }
pixelTempCheck(pixel)
},
category: "tools",
};
elements.ultracool = {
color: ["#0000ff", "#4fbfff", "#0000ff", "#4fbfff", "#0000ff", "#4fbfff"],
tool: function(pixel) {
if(shiftDown) { pixel.temp -= (350 * (1 + shiftDown)) } else { pixel.temp -= 350 }
pixelTempCheck(pixel)
},
category: "tools",
};
elements.nan_temp = {
name: "NaN temp",
color: [_cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff"],
tool: function(pixel) {
pixel.temp = NaN;
pixelTempCheck(pixel)
},
category: "cursed tools",
};
elements.inf_temp = {
color: ["#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h, "#ff0000", _cc.w.h],
tool: function(pixel) {
pixel.temp = Infinity;
pixelTempCheck(pixel)
},
category: "cursed tools",
};
//OTHER TOOLS ##
elements.burn = {
color: ["#FF6B21", "#FFA600", "#FF4000"],
tool: function(pixel) {
pixel.burnStart = pixelTicks;
pixel.burning = true;
},
category: "tools",
excludeRandom: true,
};
elements.cursed_shock = {
color: ["#ffff00", "#00ff00", "#ffff00", "#00ff00", "#ffff00", "#00ff00", "#ffff00", "#00ff00"],
tool: function(pixel) {
if(pixel.chargeCD) {
delete pixel.chargeCD;
};
if (!pixel.charge) {
pixel.charge = 1;
if (elements[pixel.element].colorOn) {
pixel.color = pixelColorPick(pixel);
};
};
},
category: "cursed tools",
excludeRandom: true,
};
//TROLL PIXELS ##
elements.troll_deleter = {
color: "#eeeeee",
tick: function(pixel) {
var target = randomChoice(currentPixels);
if(target && !(isEmpty(target.x,target.y))) {
deletePixel(target.x,target.y)
}
},
category: "troll machines",
insulate: true,
state: "solid",
excludeRandom: true,
desc: "Deletes random pixels"
},
elements.troll_hider = {
color: "#eeeeee",
tick: function(pixel) {
var target = randomChoice(currentPixels);
target.color = _cc.b.r
},
category: "troll machines",
insulate: true,
state: "solid",
excludeRandom: true,
desc: "Paints random pixels black"
},
elements.troll_swapper = {
color: "#eeeeee",
tick: function(pixel) {
var target = randomChoice(currentPixels);
if(target && !(isEmpty(target.x,target.y))) {
swapPixels(pixel,target)
}
},
category: "troll machines",
insulate: true,
state: "solid",
excludeRandom: true,
desc: "Swaps with random pixels"
},
elements.troll_exploder = {
color: "#eeeeee",
tick: function(pixel) {
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
var eeaa = (Math.floor(Math.random()*5))-2
if(Math.random() < 0.00007) { explodeAt(i,j,9+eeaa) }
if(j == height) { j == 1 }
}
if(i == height) { i == 1 }
}
},
category: "troll machines",
insulate: true,
hardness: 1.0,
state: "solid",
excludeRandom: true,
desc: "Causes random explosions"
},
elements.offset_fourth_y = {
color: [_cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff"],
tool: function(pixel) {
tryMove(pixel,pixel.x,pixel.y+0.25);
pixelTempCheck(pixel)
},
category: "cursed tools",
},
elements.offset_half_y = {
color: [_cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff"],
tool: function(pixel) {
tryMove(pixel,pixel.x,pixel.y+0.5);
pixelTempCheck(pixel)
},
category: "cursed tools",
},
elements.offset_three_fourth_y = {
color: [_cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff", _cc.b.h, "#ff00ff"],
tool: function(pixel) {
tryMove(pixel,pixel.x,pixel.y+0.75);
pixelTempCheck(pixel)
},
category: "cursed tools",
},
elements.troll_rotator = {
color: "#eeeeee",
tick: function(pixel) {
var target = randomChoice(currentPixels);
if(target && !(isEmpty(target.x,target.y))) {
target.r ??= 0;
target.r += 1; target.r %= 4;
}
},
category: "troll machines",
insulate: true,
state: "solid",
excludeRandom: true,
desc: "Randomly rotates pixels"
}
elements.troll_time_bender = {
color: "#eeeeee",
tick: function(pixel) {
if(pixel.temp < -273) {
pixel.temp = -273;
};
if(isNaN(pixel.temp)) {
pixel.temp = -1;
};
pixel.bemp = Math.floor(pixel.temp);
if(pixel.bemp > 273) {
pixel.bemp = 273;
};
if(pixel.temp >= 4000) {
pixelTicks = -1;
pixel.temp = 4000;
} else {
pixelTicks += pixel.bemp;
};
},
category: "troll machines",
insulate: true,
state: "solid",
excludeRandom: true,
temp: -1,
desc: "Advances the simulation timer (not time travel) by its temperature"
},
elements.troll_thermoderegulator = {
color: "#eeeeee",
tick: function(pixel) {
var offsetRange = pixel.temp + 273.15;
var target = randomChoice(currentPixels);
if(target && !(isEmpty(target.x,target.y)) && target.element !== pixel.element) {
target.temp += (Math.floor(Math.random() * offsetRange + 1) - (offsetRange/2))
}
},
category: "troll machines",
insulate: true,
temp: -272.15,
state: "solid",
excludeRandom: true,
desc: "Randomly heats and cools random pixels"
}
//TRIGGERABLE RANDOM-TOOL POWDERS ##
if(typeof(randomChoices) == "undefined") {randomChoices = []}; //this is generated after mod load, but JS will probably die if I don't have it defined in the code
elements.heat_random = {
name: "heat-randomized powder",
color: ["#4e5f8a","#b334ec","#fa96f9","#b6ecf6","#80ebc8","#e9286b","#8eed91","#b18b30"], //"random"'s colors plus 0x100000
behavior: behaviors.POWDER,
tick: function(pixel) {
if(pixel.temp >= 50) {
changePixel(pixel,randomChoice(randomChoices),true);
};
},
state: "solid",
category: "special",
density: 1987, //average density of all vanilla elements: 1987.2842952763815
temp: 20,
desc: "Turns to a random element when heated to 50°C",
};
elements.cold_random = {
name: "cold-randomized powder",
color: ["#3e5f9a","#a334fc","#e490ff","#9de3ff","#70ebd8","#d9287b","#7eeda1","#a18b40"], //"random"'s colors plus 0x000010 except where the last byte was above 0xef, where substraction was done to the first two bytes to compensate
behavior: behaviors.POWDER,
tick: function(pixel) {
if(pixel.temp <= -50) {
changePixel(pixel,randomChoice(randomChoices),true);
};
},
state: "solid",
density: 1987, //average density of all vanilla elements: 1987.2842952763815
temp: 20,
category: "special",
desc: "Turns to a random element when cooled to -50°C",
};
elements.shock_random = {
name: "shock-randomized powder",
color: ["#4e6f8a","#b344ec","#faa6f9","#b6fcf6","#80fbc8","#e9386b","#8efd91","#b19b30"], //"random"'s colors plus 0x101000
behavior: behaviors.POWDER,
tick: function(pixel) {
if(pixel.charge) {
delete pixel.charge;
pixel.chargeCD = 1;
changePixel(pixel,randomChoice(randomChoices),true);
};
},
conduct: 1,
state: "solid",
density: 1987, //average density of all vanilla elements: 1987.2842952763815
temp: 20,
category: "special",
desc: "Turns to a random element when shocked",
};
//ALKAHEST ##
alkahestBlacklist = ["alkahest","alkahest_fairy","wall","alkahest_spout"]
elements.alkahest = {
color: "#33eeee",
behavior: behaviors.LIQUID_OLD,
state: "liquid",
category: "liquids",
density: 3308,
hardness: 1,
tick: function(pixel) {
for(i = 0; i < adjacentCoords.length; i++) {
if(Math.random() < 0.1) {
var pX = pixel.x
var pY = pixel.y
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var checkPosX = pX+oX;
var checkPosY = pY+oY;
if(!isEmpty(checkPosX,checkPosY,true)) {
var newPixel = pixelMap[checkPosX][checkPosY];
var newElement = newPixel.element;
if(!alkahestBlacklist.includes(newElement)) { //unless someone's willing to implement dragon parts
if(typeof(pixel[newElement]) === "undefined") {
pixel[newElement] = 0;
};
pixel[newElement]++;
deletePixel(checkPosX,checkPosY);
continue
};
};
};
};
},
};
//LIQUID ENERGY ELEMENTS ##
elements.liquid_plasma = {
color: ["#8800ff","#b184d9","#8800ff"],
behavior: [
"XX|XX|XX",
"M2|DL%0.1|M2",
"M1|M1|M1",
],
behaviorOn: [
"XX|CL%5|XX",
"CL%5 AND M2|XX|CL%5 AND M2",
"M1|M1 AND CL%5|M1",
],
temp:7065,
tempLow:5000,
stateLow: "liquid_fire",
category: "energy liquids",
state: "liquid",
density: 70,
charge: 0.5,
conduct: 1,
},
elements.liquid_fire = {
color: ["#ff6b21","#ffa600","#ff4000"],
behavior: [
"XX|M2|XX",
"M2|XX|M2",
"M1|M1|M1",
],
reactions: {
"water": { "elem1": "liquid_smoke" }
},
temp:600,
tempLow:100,
stateLow: "liquid_smoke",
tempHigh: 7000,
stateHigh: "liquid_plasma",
category: "energy liquids",
burning: true,
burnTime: 500,
burnInto: "liquid_smoke",
state: "liquid",
density: 21,
},
elements.liquid_smoke = {
color: "#383838",
behavior: [
"XX|XX|XX",
"M2|DL%0.1|M2",
"M1|M1|M1",
],
reactions: {
"water": { "elem1": "dirty_water", "elem2": null },
"steam": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,15] },
"rain_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,15] },
"snow_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,15] },
"acid_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,15] },
"fire_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,15] },
"pyrocumulus": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,15] }
},
temp: 114,
tempHigh: 605,
stateHigh: "liquid_fire",
category: "energy liquids",
state: "liquid",
density: 2180,
},
elements.liquid_cold_fire = {
color: ["#21cbff","#006aff","#00ffff"],
behavior: [
"XX|M2|XX",
"M2|CH:liquid_smoke%0.1|M2",
"M1|M1|M1",
],
reactions: {
"fire": { "elem1": "liquid_smoke", "elem2": "liquid_smoke" },
"plasma": { "elem1": "le_liquid_light", "elem2": "le_liquid_light" }, //prefixed to avoid conflict with F&M liquid_light
},
temp:-200,
tempHigh:0,
stateHigh: "liquid_smoke",
category: "energy liquids",
state: "liquid",
density: 42,
},
elements.le_liquid_light = {
color: "#ffffa8",
behavior: [
"XX|XX|XX",
"M2|DL%0.1 AND RT%0.5|M2 AND BO",
"M1|M1|M1",
],
temp: 40,
category: "energy liquids",
},
elements.liquid_laser = {
color: "#ff0000",
behavior: [
"XX|M2|XX",
"M2|DL%0.05 AND RT%0.5|M2 AND BO:1,2,3",
"XX|M1|XX",
],
temp: 40,
category: "energy liquids",
},
elements.liquid_electric = {
color: "#dddd00",
behavior: [
"CL%3|CL%3 AND SH|CL%3",
"M2%15 AND CL%3 AND SH|SH%3 AND DL%15|M2%15 AND CL%3 AND SH",
"M1%15 AND CL%4|M1%50 AND CL%9 AND SH|M1%15 AND CL%4",
],
charge: 3,
category: "energy liquids",
state: "solid",
density: 44.1,
},
elements.liquid_radiation = {
color: ["#00ff00","#6fff00"],
behavior: [
"XX|M2%50 AND HT|XX",
"M2%50 AND HT|DL%0.2|M2%50 AND HT",
"M1%50|M1 AND HT|M1%50",
],
reactions: {
"water": { "elem2":"rad_steam", "chance":0.8 },
"steam": { "elem2":"rad_steam", "chance":0.8 },
"salt_water": { "elem2":"rad_steam", "chance":0.8 },
"sugar_water": { "elem2":"rad_steam", "chance":0.8 },
"dirty_water": { "elem2":"rad_steam", "chance":0.8 },
"bubble": { "elem2":"rad_steam", "chance":0.8 },
"foam": { "elem2":"rad_steam", "chance":0.8 },
"ice": { "elem2":"rad_steam", "chance":0.8 },
"snow": { "elem2":"rad_steam", "chance":0.8 },
"packed_snow": { "elem2":"rad_steam", "chance":0.8 },
"slime": { "elem2":"rad_steam", "chance":0.8 },
"milk": { "elem2":"cheese", "chance":0.8 },
"permafrost": { "elem1":"rad_steam", "elem2":"dirt", "chance":0.8 },
"mud": { "elem1":"rad_steam", "elem2":"dirt", "chance":0.8 },
"wet_sand": { "elem1":"rad_steam", "elem2":"sand", "chance":0.8 },
"clay": { "elem1":"rad_steam", "elem2":"clay_soil", "chance":0.8 },
"slaked_lime": { "elem1":"rad_steam", "elem2":"limestone", "chance":0.8 },
"rain_cloud": { "elem2":"rad_cloud", "chance":0.8 },
"snow_cloud": { "elem2":"rad_cloud", "chance":0.8 },
"plant": { "elem2":"straw", "chance":0.8 },
"grass": { "elem2":["straw","grass_seed","wheat_seed"], "chance":0.8 },
"algae": { "elem2":["mushroom_spore","lichen","yeast"], "chance":0.8 },
"mushroom_spore": { "elem2":["lichen","yeast"], "chance":0.8 },
"mushroom_cap": { "elem2":["lichen","plant"], "chance":0.8 },
"mushroom_stalk": { "elem2":["lichen","yeast"], "chance":0.8 },
"mushroom_gill": { "elem2":["lichen","yeast"], "chance":0.8 },
"flea": { "elem2":["ash","ant","termite"], "chance":0.8 },
"ant": { "elem2":["ash","flea","termite"], "chance":0.8 },
"termite": { "elem2":["ash","flea","ant"], "chance":0.8 },
"fly": { "elem2":["ash","firefly","bee"], "chance":0.8 },
"bee": { "elem2":["ash","firefly","fly"], "chance":0.8 },
"firefly": { "elem2":["ash","bee","fly"], "chance":0.8 },
"frog": { "elem2":["ash","meat","rotten_meat","cooked_meat"], "chance":0.8 },
"fish": { "elem2":["ash","meat","rotten_meat","cooked_meat"], "chance":0.8 },
"rat": { "elem2":["ash","meat","rotten_meat","cooked_meat","plague"], "chance":0.8 },
"bone": { "elem2":["calcium","calcium","calcium","cancer"], "chance":0.8 },
"meat": { "elem2":["ash","rotten_meat","cooked_meat"], "chance":0.8 },
"rotten_meat": { "elem2":["ash","meat","cooked_meat"], "chance":0.8 },
"cooked_meat": { "elem2":["ash","rotten_meat"], "chance":0.8 },
"bamboo": { "elem2":["wood","plant","bamboo_plant"], "chance":0.8 },
"bamboo_plant": { "elem2":["wood","plant","bamboo"], "chance":0.8 },
"sapling": { "elem2":["wood","plant","tree_branch"], "chance":0.8 },
"tree_branch": { "elem2":["wood","plant","sapling"], "chance":0.8 },
"grass_seed": { "elem2":["straw","wheat_seed"], "chance":0.8 },
"lichen": { "elem2":"algae", "chance":0.8 },
"yeast": { "elem2":["algae","mushroom_spore","lichen"], "chance":0.8 },
"wheat_seed": { "elem2":["straw","wheat","grass_seed"], "chance":0.8 },
"flower_seed": { "elem2":["straw","grass","pistil","petal"], "chance":0.8 },
"pistil": { "elem2":["straw","grass","flower_seed","petal"], "chance":0.8 },
"petal": { "elem2":["straw","grass","flower_seed","pistil"], "chance":0.8 },
"vine": { "elem1":["vine"], "chance":0.8 },
"worm": { "elem2":"ash", "chance":0.8 },
"corn": { "elem2":"corn_seed", "chance":0.8 },
"corn_seed": { "elem2":"corn", "chance":0.8 },
"potato": { "elem2":"potato_seed", "chance":0.8 },
"potato_seed": { "elem2":"potato", "chance":0.8 },
"slug": { "elem2":"slime", "chance":0.8 },
"snail": { "elem2":"slime", "chance":0.8 },
"cell": { "elem2":"cancer", "chance":0.8 },
"blood": { "elem2":["infection","cancer"], "chance":0.8 },
"antibody": { "elem2":"cancer", "chance":0.8 },
"infection": { "elem2":"cancer", "chance":0.8 },
"cancer": { "elem2":null, "chance":0.2 },
},
state: "liquid",
density: 4.2,
category: "energy liquids",
},
elements.liquid_explosion = {
color: ["#ffb48f","#ffd991","#ffad91"],
behavior: [
"XX|XX|XX",
"M2|EX:10>fire,fire,fire,liquid_explosion,liquid_explosion%0.4 AND DL%0.3|M2",
"M1|M1|M1",
],
temp: 300,
category: "energy liquids",
state: "liquid",
density: 2000,
excludeRandom: true,
}
elements.everfire_liquid = {
"name": "everfire liquid",
"color": "#06142b",
"state": "liquid",
"behavior": behaviors.LIQUID,
"density": 1290,
"burn": 100,
"burnTime": 2000,
"burnInto": "extinguished_everfire_liquid",
"category": "energy liquids",
"fireColor": ["#0041a8","#8ab7ff"],
},
elements.extinguished_everfire_liquid = {
"name": "extinguished everfire liquid",
"color": "#242d3b",
"state": "liquid",
"behavior": behaviors.LIQUID,
"density": 1290,
"fireColor": ["#0041a8","#8ab7ff"],
"category": "energy liquids",
"hidden": true,
},
elements.liquid_magic = {
"name": "liquid magic",
"color": ["#a270ff","#f2d9ff"],
"state": "liquid",
"behavior": [
"M2%50|M2%50|M2%50",
"M2|DL%0.2|M2",
"M1|M1|M1",
],
"density": 21,
"category": "energy liquids",
"reactions": elements.magic.reactions,
},
elements.liquid_mystic_fire = {
"name": "liquid mystic fire",
"color": ["#5454ff","#2020d4","#5800c4"],
"behavior": [
"M2%50|M2%50 AND CR:liquid_mystic_fire%10 AND CR:mystic_fire%5|M2%50",
"M2 AND CR:liquid_mystic_fire%5|EX:15>liquid_mystic_fire%0.1|M2 AND CR:liquid_mystic_fire%5",
"M1|M1|M1",
],
"temp":8500,
"tempChange":-100,
"tempLow":8000,
"stateLow": "liquid_fire",
"category": "energy liquids",
"burning": true,
},
//concoction and essence are already liquid
elements.liquid_frostbomb = {
color: "#72dfed",
behavior: [
"XX|XX|XX",
"M2|EX:15>frostwind,frostwind,frostwind,liquid_frostbomb%0.4 AND DL%0.2 AND CO:1%10|M2",
"M1|M1|M1",
],
temp: -200,
category: "energy liquids",
state: "liquid",
density: 2000,
excludeRandom: true,
}
elements.frostwind.tempHigh = 0;
elements.frostwind.stateHigh = null;
//LIQUID VOID ##
elements.liquid_void = {
color: "#262626",
behavior: [
"XX|DL|XX",
"DL AND M2|XX|DL AND M2",
"M1|DL AND M1|M1",
],
ignore: ["liquid_void", "void", "wall", "cloner", "ecloner", "slow_cloner", "clone_powder", "floating_cloner", "clone_liquid", "liquid_cloner", "fire_cloner", "antigravity_powder_cloner", "floating_cloner_spout", "clone_liquid_spout", "liquid_cloner_spout", "fire_cloner_spout", "converter", "liquid_void_spout"],
/*The hardcoded array of cloners is used because I don't know how to detect them.
Generation code:
elementArray = Object.keys(elements);
for (let i = 0; i < elementArray.length; i++) {
var elementName = elementArray[i];
if(elementName.indexOf("lone") !== -1) {
console.log(elementName);
};
};
*/
category: "liquids",
state: "liquid",
density: 6969,
excludeRandom: true,
}
if(!elements.void.ignore) {
elements.void.ignore = [];
};
elements.void.ignore.push("liquid_void");
//LIQUID CLONER ##
elements.clone_liquid = {
color: "#f0f000",
behavior: [
"XX|CF|XX",
"CF AND M2|XX|CF AND M2",
"M1|CF AND M1|M1",
],
ignore: ["cloner","ecloner","slow_cloner","floating_cloner","clone_powder","clone_liquid_spout"],
category:"machines",
insulate:true,
state:"gas",
density:2710,
hardness: 1,
},
elements.floating_cloner.state = "gas";
elements.floating_cloner.ignore.push("floating_cloner_spout");
//ASSORTED RANDOM THINGS ##
//TPT reference
elements.warp = {
name: "warp",
color: "#111111",
behavior: [
"M1%30 AND SW%30|M1%30 AND SW%30|M1%30 AND SW%30",
"M1%30 AND SW%30|DL%1|M1%30 AND SW%30",
"M1%30 AND SW%30|M1%30 AND SW%30|M1%30 AND SW%30",
],
category: "special",
state: "gases",
},
elements.unrealistically_flammable_gas = {
color: "#ddee11",
behavior: [
"M1%05 AND SW%2 AND HT:1%1|M1%05 AND SW%2 AND HT:1%1|M1%05 AND SW%2 AND HT:1%1",
"M1%10 AND SW%2 AND HT:1%1|HT:1%1.000000000000000000|M1%10 AND SW%2 AND HT:1%1",
"M1%15 AND SW%2 AND HT:1%1|M1%15 AND SW%2 AND HT:1%1|M1%15 AND SW%2 AND HT:1%1",
],
behaviorOn: [
"M1%10 AND SW%4 AND HT:2%2|M1%10 AND SW%4 AND HT:2%2|M1%10 AND SW%4 AND HT:2%2",
"M1%20 AND SW%4 AND HT:2%2|HT:2%2 AND CH:plasma%0.01|M1%20 AND SW%4 AND HT:2%2",
"M1%30 AND SW%4 AND HT:2%2|M1%30 AND SW%4 AND HT:2%2|M1%30 AND SW%4 AND HT:2%2",
],
category: "gases",
burn: 3000,
burnTime: 5,
burnInto: "burning_unrealistically_flammable_gas",
state: "gas",
density: 2,
tempHigh: 95,
stateHigh: "burning_unrealistically_flammable_gas",
conduct: 0.2
},
elements.burning_unrealistically_flammable_gas = {
color: "#eedd11",
behavior: [
"M2 AND HT:3750%70 AND CR:plasma%10|M1 AND HT:3750%70 AND CR:plasma%10.000000000000000000000000000000000000000000|M2 AND HT:3750%70 AND CR:plasma%10",
"M1 AND HT:3750%70 AND CR:plasma%10|HT:3750%70.000000 AND CH:plasma%6.71 AND EX:9>plasma,plasma,burning_unrealistically_flammable_gas%0.25|M1 AND HT:3750%70 AND CR:plasma%10",
"M2 AND HT:3750%70 AND CR:plasma%10|M1 AND HT:3750%70 AND CR:plasma%10.000000000000000000000000000000000000000000|M2 AND HT:3750%70 AND CR:plasma%10",
],
behaviorOn: [
"M2 AND HT:7500%70 AND CR:plasma%15|M1 AND HT:7500%70 AND CR:plasma%15.00000000000000000000000000000000000|M2 AND HT:7500%70 AND CR:plasma%15",
"M1 AND HT:7500%70 AND CR:plasma%15|HT:7500%70 AND CH:plasma%5.60 AND EX:11>plasma,plasma,burning_unrealistically_flammable_gas%0.5|M2 AND HT:7500%70 AND CR:plasma%15",
"M2 AND HT:7500%70 AND CR:plasma%15|M1 AND HT:7500%70 AND CR:plasma%15.00000000000000000000000000000000000|M2 AND HT:7500%70 AND CR:plasma%15",
],
category: "gases",
burn: 2000,
burnTime: 950,
burnInto: "plasma",
state: "gas",
density: 1.5,
tempHigh: 200001,
stateHigh: "plasma",
hidden: true,
excludeRandom: true,
},
elements.unrealistically_flammable_powder = {
color: "#cddd22",
behavior: [
"HT:2%2 AND CR:unrealistically_flammable_gas%3|HT:2%2 AND CR:unrealistically_flammable_gas%3|HT:2%2 AND CR:unrealistically_flammable_gas%3",
"HT:2%2 AND CR:unrealistically_flammable_gas%1|HT:2%2.00000000000000000000|HT:2%2 AND CR:unrealistically_flammable_gas%1",
"M2 AND HT:2%2.0000000000000|M1 AND HT:2%2.0000000000000|M2 AND HT:2%2.0000000000000",
],
behaviorOn: [
"HT:4%4 AND CR:unrealistically_flammable_gas%6|HT:4%4 AND CR:unrealistically_flammable_gas%6|HT:4%4 AND CR:unrealistically_flammable_gas%6",
"HT:4%4 AND CR:unrealistically_flammable_gas%2|HT:4%4.00000000000000000000|HT:4%4 AND CR:unrealistically_flammable_gas%2",
"M2 AND HT:4%4.0000000000000|M1 AND HT:4%4.0000000000000|M2 AND HT:4%4.0000000000000",
],
category: "powders",
burn: 3000,
burnTime: 5,
burnInto: "burning_unrealistically_flammable_gas",
state: "powders",
density: 20,
tempHigh: 95,
stateHigh: "burning_unrealistically_flammable_gas",
conduct: 0.4,
},
elements.burning_unrealistically_flammable_powder = {
color: "#ddcd22",
behavior: [
"HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7|HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7.0000000000000000000000000000000000000000000000000000000000000000000000000000|HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7",
"HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7|HT:89850%70 AND CH:plasma%00000000005.60 AND EX:12>plasma,plasma,plasma,burning_unrealistically_flammable_gas,burning_unrealistically_flammable_powder%0.5|HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7",
"M2 AND HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7|M1 AND HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7.00000000000000000000000000000000000000000000000000000000000000|M2 AND HT:89850%70 AND CR:burning_unrealistically_flammable_gas%7",
],
behaviorOn: [
"HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9|HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9.00000000000000000000000000000000000000000000000000000000000000000000000000|HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9",
"HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9|HT:179700%70 AND CH:plasma%00000000004.79 AND EX:13>plasma,plasma,plasma,burning_unrealistically_flammable_gas,burning_unrealistically_flammable_gas,burning_unrealistically_flammable_powder%1|HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9",
"M2 AND HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9|M1 AND HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9.000000000000000000000000000000000000000000000000000000000000|M2 AND HT:179700%70 AND CR:burning_unrealistically_flammable_gas%9",
],
category: "powders",
burn: 2000,
burnTime: 1150,
burnInto: "plasma",
state: "powders",
density: 15,
tempHigh: 200001,
stateHigh: "burning_unrealistically_flammable_gas",
conduct: 0.4,
hidden: true,
excludeRandom: true,
},
elements.black_decay = { //random mystcraft mod reference
name: "black decay",
color: "#222222",
behavior: [
"XX|CH:black_decay%2 AND DL:black_decay%30|XX",
"CH:black_decay%1|DL%0.2|CH:black_decay%1",
"XX|CH:black_decay%1 AND M1|XX",
],
category: "special",
excludeRandom: true,
},
elements.steel.behavior = behaviors.FAIRYKILL;
elements.tungstensteel = {
color: "#555589",
behavior: behaviors.FAIRYKILL,
tempHigh: 3600,
category: "solids",
density: 19000,
conduct: 0.48,
},
elements.stainless_steel = {
color: "#7d8181",
behavior: behaviors.WALL,
reactions: {
"pool_water": { elem1:"rust", chance:0.0009 },
"salt_water": { elem1:"rust", chance:0.0003 },
"salt": { elem1:"rust", chance:0.0003 },
"acid": { elem1:"rust" }
},
tempHigh: 1455.5,
category: "solids",
density: 7930,
conduct: 0.42,
hardness: 0.85
};
elements.steel.reactions.acid = { elem1:"rust" };
elements.molten_tungsten = {
density: 17600,
temp: 3500,
tempHigh: 5555,
stateHigh: "tungsten_gas",
},
elements.pop_rock_pop = {
color: ["#ffb49f","#ffd9a1","#ffada1"],
behavior: [
"XX|XX|XX",
"XX|EX:3>carbon_dioxide,sugar|XX",
"XX|XX|XX",
],
category: "energy",
state: "gas",
density: 100,
excludeRandom: true,
hidden: true,
},
elements.pop_rocks = {
color: ["#d4d4d4","#74d4d4","#d474d4","#7474d4","#d4d474","#74d474","#d47474","#747474","#2f2f2f","#8f2f2f","#2f8f2f","#8f8f2f","#2f2f8f","#8f2f8f","#2f8f8f","#8f8f8f","#606060","#c06060","#60c060","#c0c060","#6060c0","#c060c0","#60c0c0","#c0c0c0"],
behavior: behaviors.POWDER,
reactions: {
water: { elem1: "sugar_water", elem2: [null,"pop_rock_pop"] },
salt_water: { elem1: "salt_water", elem2: [null,"pop_rock_pop"] },
sugar_water: { elem1: "sugar_water", elem2: [null,"pop_rock_pop"] },
pool_water: { elem1: "pool_water", elem2: [null,"pop_rock_pop"] },
dirty_water: { elem1: "dirty_water", elem2: [null,"pop_rock_pop"] },
radioactive_water: { elem1: "radioactive_water", elem2: [null,"pop_rock_pop"] },
pure_water: { elem1: "sugar_water", elem2: [null,"pop_rock_pop"] },
chilly_water: { elem1: "chilly_water", elem2: [null,"pop_rock_pop"] },
ethanol: { elem1: "sugar", elem2: [null,"pop_rock_pop"], chance: 0.003 }, // 1g/170mL vs 200g/100mL
methanol: { elem1: "sugar", elem2: [null,"pop_rock_pop"], chance: 0.005 } // 1g/100mL cs 200g/100mL
},
tempHigh: 138,
stateHigh: ["caramel","pop_rock_pop"],
category: "land",
state: "solid",
density: 333.333333333, //made-up
hardness: 0.2,
breakInto: ["sugar","pop_rock_pop"],
},
elements.tungsten_gas = {
color: "#FFEEE2",
behavior: [
"CR:plasma%0.625 AND M2|M1|CR:plasma%0.625 AND M2",
"M1|XX|M1",
"CR:plasma%0.625 AND M2|M1|CR:plasma%0.625 AND M2",
],
density: 15800, //https://link.springer.com/article/10.1007/s11661-019-05262-5
temp: 5600,
tempLow: 5555,
stateLow: "molten_tungsten",
category: "gases",
hidden: true,
},
elements.molten_steel ??= {};
elements.molten_steel.reactions ??= {};
elements.molten_steel.reactions.molten_tungsten = { "elem1":"molten_tungstensteel", "elem2":"molten_tungstensteel" };
elements.molten_steel.reactions.molten_chromium = { "elem1":"molten_stainless_steel", "elem2":["molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_stainless_steel"] };
elements.iron.burnInto = "rust";
elements.steel.burnInto = "rust";
elements.unrealistically_flammable_substance_bomb = {
name: "unrealistically flammable bomb",
color: "#cdad52",
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"M2|M1 AND EX:10>plasma,burning_unrealistically_flammable_powder,unrealistically_flammable_powder,unrealistically_flammable_powder,unrealistically_flammable_powder,burning_unrealistically_flammable_gas,unrealistically_flammable_gas,unrealistically_flammable_gas,unrealistically_flammable_gas|M2",
],
category: "weapons",
state: "solid",
density: 1300,
excludeRandom: true,
},
elements.warp_bomb = {
name: "warp bomb",
color: "#422e4a",
behavior: [
"XX|XX|XX",
"XX|CC:#5b3a69,#382740,#400e61|XX",
"M2|M1 AND EX:15>warp|M2",
],
category: "weapons",
state: "solid",
density: 1300,
excludeRandom: true,
},
elements.turbine = {
color: "#75726a",
tempHigh: elements.copper.tempHigh,
stateHigh: ["steel","molten_copper"],
conduct: 1,
behavior: behaviors.WALL,
tick: function(pixel) {
var neighbors = adjacentCoords.map(offsetPair => pixelMap[pixel.x+offsetPair[0]]?.[pixel.y+offsetPair[1]]).filter(function(pixelOrUndefined) { return typeof(pixelOrUndefined) == "object" });
if(neighbors.length < 0) { return };
var neighboringElements = neighbors.filter(function(px) { return !!px }).map(x => x.element);
var neighboringStates = neighboringElements.map(elemName => elements[elemName].state ?? "solid");
var nonSolidNeighbors = neighboringStates.filter(function(string) { return (string !== "solid") }).length;
if(nonSolidNeighbors == 0) { return };
pixel.charge ??= 0;
pixel.charge += nonSolidNeighbors / 8;
pixel.temp += (nonSolidNeighbors / 500);
},
onTryMoveInto: function(pixel,otherPixel) {
pixel.charge ??= 0;
pixel.charge += 1/8;
pixel.temp += (1/500);
},
hardness: averageNumericArray([elements.copper.hardness,elements.steel.hardness,elements.steel.hardness]),
breakInto: ["metal_scrap", "steel_scrap", "steel_scrap", "copper_scrap", "copper_scrap", "steel_scrap"],
state: "solid",
category: "machines",
density: averageNumericArray([elements.steel.density, elements.copper.density, airDensity])
};
elements.test_fader = { //basically an aray clone
color: _cc.w.h,
properties: {
"life": 100,
"fadeRate": 1
},
hardness: 0.8,
density: 0,
state: "solid",
tick: function(pixel) {
pixel.life ??= 100;
var alpha = isNaN(pixel.life) ? Math.floor(Math.random() * 256) : (pixel.life * 2.55); //ALPHA/??!?!?!?!/1/ CL REFERENCE??!?!?!?!?!?!?!?!??!?
//console.log("tick");
var splitColor = convertColorFormats(pixel.color,"json");
//console.log(pixel.color,splitColor);
splitColor.a = alpha;
pixel.color = convertColorFormats(splitColor,"hex");
//console.log(pixel.color);
if(pixel.fadeRate == 0 || (pixel.fadeRate && isNaN(pixel.fadeRate))) {
} else {
pixel.life -= (pixel.fadeRate ?? 1);
};
if(pixel.life < 0) {
deletePixel(pixel.x,pixel.y);
return
}
}
};
sweepingLaserTransparencyWhitelist = ["glass","glass_shard","rad_glass","rad_glass_shard","glass_pane","rad_glass_pane","water","salt_water","sugar_water","pool_water"];
sweepingLaserTransparencyBlacklist = [];
//Sweeping laser
elements.sweeping_laser = {
"color": "#905050",
customColor: true,
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","sweepingLaserRotationSpeed");
p0.setAttribute("min","-4");
p0.value = ambaPlaceProperties.sweepingLaserRotationSpeed;
};
if(p0h) {
p0h.innerText = "Rotation Speed";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","sweepingLaserBeamLength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.sweepingLaserBeamLength;
};
if(p1h) {
p1h.innerText = "Length";
};
showSetterColumn("numeric",2);
var p2 = document.getElementById("propertynumeric2input");
var p2h = document.getElementById("propertynumeric2heading");
if(p2) {
p2.setAttribute("set","sweepingLaserBeamTemperature");
p2.setAttribute("min","-99999999");
p2.value = ambaPlaceProperties.sweepingLaserBeamTemperature;
};
if(p2h) {
p2h.innerText = "Temperature";
};
showSetterColumn("numeric",3);
var p3 = document.getElementById("propertynumeric3input");
var p3h = document.getElementById("propertynumeric3heading");
if(p3) {
p3.setAttribute("set","sweepingLaserBeamBrevity");
p3.setAttribute("min","0");
p3.value = ambaPlaceProperties.sweepingLaserBeamBrevity;
};
if(p3h) {
p3h.innerText = "Brevity";
}
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
"tick": function(pixel) {
pixel.r ??= 0;
if(isNaN(pixel.r)) { return false };
pixel.rSpeed ??= -(ambaPlaceProperties?.sweepingLaserRotationSpeed ?? -0.03);
pixel.beamLength ??= (ambaPlaceProperties?.sweepingLaserBeamLength ?? 10);
pixel.beamTemp ??= (ambaPlaceProperties?.sweepingLaserBeamTemperature ?? 2000);
pixel.brevity ??= (ambaPlaceProperties?.sweepingLaserBeamBrevity ?? 5);
pixel.untssa ??= Math.floor(Math.random() * (Number.MAX_SAFE_INTEGER + 1)) * (Math.floor() < 0.5 ? -1 : 1); //unique number to stop self-addition
if(Object.is(pixel.untssa,-0)) { pixel.untssa = Number.MAX_SAFE_INTEGER + 3 };
pixel.beamColor ??= currentColor;
var beamElement = "test_fader";
var rotation = -(((pixel.r ?? 0) % 4) + 1); //preserving the original behavior of 0 = up, 1 = left
var rotationInRadians = scale(rotation,0,4,0,Math.PI * 2);
var vector = [Math.cos(rotationInRadians), Math.sin(rotationInRadians)];
var distance = Math.min(300,Math.max(2,(pixel.beamLength + 1) ?? 10));
for(var i = 1; i <= distance; i += (3 ** -(Math.ceil(Math.log2(distance / 10))))) { //increase the tries to try to reduce gaps in the beam, as distance goes up
var newOffsets = vector.map(coord => Math.round(coord * i));
var finalPos = {x: pixel.x + newOffsets[0], y: pixel.y + newOffsets[1]};
//console.log(finalPos);
//console.log({x:pixel.x,y:pixel.y},finalPos);
if(!(isEmpty(finalPos.x,finalPos.y))) {
var otherPixel = pixelMap[finalPos.x]?.[finalPos.y];
if(otherPixel && (
[beamElement,pixel.element].concat(sweepingLaserTransparencyWhitelist).includes(otherPixel.element) ||
elements[otherPixel.element].state === "gas"
) && !(sweepingLaserTransparencyBlacklist.includes(otherPixel.element))) {
if(otherPixel.element == "test_fader") { //intentionally hard-coded
otherPixel.life = 100;
if(otherPixel.untssa !== pixel.untssa) {
var _pc = convertColorFormats(pixel.color,"hex",true).slice(0,7);
otherPixel.lastColors ??= [convertColorFormats(otherPixel.color,"hex",true).slice(0,7)];
if(otherPixel.lastColors.indexOf(_pc) === -1) {
otherPixel.lastColors.push(_pc);
otherPixel.color = otherPixel.lastColors.reduce((a,b) => addColors(a,b,"hex").slice(0,7)).padEnd(9,"F")
}
}
};
continue
} else {
break
}
};
var newBeamPixel = tryCreatePixelReturn(beamElement,finalPos.x,finalPos.y);
if(!newBeamPixel) {
break
} else {
newBeamPixel.temp = pixel.beamTemp ?? 2000;
newBeamPixel.fadeRate = pixel.brevity ??= 5;
newBeamPixel.untssa = pixel.untssa;
newBeamPixel.color = (pixel.beamColor ?? "#FF0000");
}
};
pixel.r += pixel.rSpeed ?? 0.03;
},
"reactions": {
"water": { elem1: "steel", charge1: 1 },
},
"category": "special",
"breakInto": "charcoal",
"tempHigh": 2700,
"stateHigh": "molten_steel",
};
//hormones
//estrogens
elements.estradiol = {
color: "#f2fcee", //it absorbs shorter wavelength UV than testosterone and I am treating this like absorbing violet for convenience
//https://www.researchgate.net/publication/226065469_Optical_Properties_of_Two_Types_of_Sex_Hormones_of_the_Cyclopentenephenanthrene_Series
//http://depts.washington.edu/cmditr/modules/lum/color.html
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1200,
tempHigh: 173,
category: "powders",
},
elements.molten_estradiol = {
tempHigh: 446,
stateHigh: "vaporized_estradiol",
},
elements.vaporized_estradiol = {
color: ["#ffbf60","#ffdc60","#ff9d60"], //hormone gas wouldn't glow that brightly at these temperatures but just ignore that
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 972,
temp: 500,
tempLow: 446,
stateLow: "molten_estradiol",
},
//progestogens
elements.progesterone = {
color: "#f7eefc", //slightly different? from testosterone but exaggerated
//https://downloads.hindawi.com/journals/ijps/2017/9603140.pdf
//these hormones all absorb in the uv region anyway so they would all look white to us
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1100,
tempHigh: 121,
category: "powders",
},
elements.molten_progesterone = {
tempHigh: 447,
stateHigh: "vaporized_progesterone",
},
elements.vaporized_progesterone = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 891,
tempLow: 447,
stateLow: "molten_progesterone",
}
//androgens
//plain testosterone
elements.testosterone = {
color: "#f7eef7", //it absorbs longer wavelength UV than estradiol and I am treating this like absorbing green for convenience
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1100,
tempHigh: 155,
category: "powders",
},
elements.molten_testosterone = {
tempHigh: 433,
temp: 400,
stateHigh: "vaporized_testosterone",
},
elements.vaporized_testosterone = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 891,
temp: 500,
tempLow: 433,
stateLow: "molten_testosterone",
},
//undecanoate (form actually used in HRT)
elements.testosterone_undecanoate = {
color: "#f8f2fc", //more creatively-interpreted UV data: https://spectrabase.com/spectrum/5Yc7XCCDkA7 plus http://depts.washington.edu/cmditr/modules/lum/color.html and a lot of eyeballing and loose approximation
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1037, //https://www.chembk.com/en/chem/Testosterone%20Undecanoate
tempHigh: 63,
category: "powders",
},
elements.molten_testosterone_undecanoate = {
tempHigh: 550,
stateHigh: "vaporized_testosterone_undecanoate",
hidden: true,
},
elements.vaporized_testosterone_undecanoate = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 834, //made-up due to lack of data
temp: 600,
tempLow: 63,
stateLow: "molten_testosterone_undecanoate",
},
//other
//anti-androgens
//CPA
elements.cyproterone_acetate = {
color: "#efeef8", //it absorbs far longer uv than the others, which i am rendering as red absorption
//https://www.researchgate.net/figure/UV-spectrum-for-drospirenone-cyproterone-acetate-desogestrel-and-ethinyl-estradiol-at-1_fig1_315746083
//i didn't really expect to find a spectrum for this
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1068,
tempHigh: 200,
category: "powders",
},
/* > Hazardous decomposition products:
> Hydrogen chloride (HCl)
> Carbon monoxide and carbon dioxide
> Hydrogen
> https://cdn.caymanchem.com/cdn/msds/16622m.pdf
so many interesting effects i can't add
*/
elements.molten_cyproterone_acetate = {
tempHigh: 569,
stateHigh: "vaporized_cyproterone_acetate",
},
elements.vaporized_cyproterone_acetate = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 865,
tempLow: 569,
stateLow: "molten_cyproterone_acetate",
},
//spironolactone
elements.spironolactone = {
color: "#f7eef1", //UV absorbance peak wavelength is slightly shorter than that of testosterone
//https://www.researchgate.net/publication/348592381_Quantification_of_Spironolactone_by_first_and_second_order_UV_Derivative_Spectrophotometry_in_bulk_and_tablet_dosage_form/link/6006b3cf299bf14088a649bd/download
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1200,
tempHigh: 207,
category: "powders",
},
elements.molten_spironolactone = {
tempHigh: 597,
stateHigh: "vaporized_spironolactone",
/*should have more decomps
https://sci-hub.se/https://link.springer.com/article/10.1007/BF01979243
> The TG-DTG curves of spironolactone in Fig. 7 demonstrate that the compound is thermally stable up to 200*C, and that its thermal decomposition occurs between 200 and 620*C. Four consecutive steps are observed in the TG-DTG curves. The first step, up to 260*C is ascribed to the elimination of the substituent group, SCOCH_{3} (TG= 19.59%, Calc. = 19.33%). The second step (260-370*C) and the third and fourth steps (370-700*C) involve losses of 42.93% and 37.48%, respectively, but do not permit a suggestion as to which parts of the compound are eliminated in each step. */
},
elements.vaporized_spironolactone = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 972,
tempLow: 597,
stateLow: "molten_spironolactone",
},
//finasteride
elements.finasteride = {
color: "#fcfcf1", //UV absorbance peak wavelength is even shorter than that of estradiol
//https://www.researchgate.net/publication/312317200
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1100,
tempHigh: 253,
category: "powders",
},
elements.molten_finasteride = {
tempHigh: 577,
stateHigh: "vaporized_finasteride",
},
elements.vaporized_finasteride = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 891,
tempLow: 577,
stateLow: "molten_finasteride",
},
//dutasteride
elements.dutasteride = {
color: "#fbf6ee", //High UV absorbances around the peak wavelengths of both estradiol and testosterone
//https://sphinxsai.com/sphinxsaivol_2no.1/pharmtech_vol_2no.1/PharmTech_Vol_2No.1PDF/PT=18%20(113-117).pdf
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1303, //https://www.chemicalbook.com/ChemicalProductProperty_EN_CB3254628.htm
tempHigh: 243,
category: "powders",
},
elements.molten_dutasteride = {
tempHigh: 620, //http://www.chemspider.com/Chemical-Structure.5293502.html
stateHigh: "vaporized_dutasteride",
},
elements.vaporized_dutasteride = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 1055,
tempLow: 620,
stateLow: "molten_dutasteride",
},
//bicalutamide
elements.bicalutamide = {
color: "#f4fcee", //peaks at 200-220 and at 270
//i am probably mapping uv to visible wrong and misreading color.html
//https://www.researchgate.net/publication/257679318
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1520, //https://www.chemicalbook.com/ProductMSDSDetailCB7457827_EN.htm
tempHigh: 192,
category: "powders",
},
elements.molten_bicalutamide = {
tempHigh: 659,
stateHigh: "vaporized_bicalutamide",
},
elements.vaporized_bicalutamide = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 1231,
tempLow: 659,
stateLow: "molten_bicalutamide",
},
//puberty blockers
elements.leuprolide = {
color: "#f5eefb", //http://dspace.hmlibrary.ac.in:8080/jspui/bitstream/123456789/1143/11/11_Chapter%203.pdf
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1440, //https://www.chemicalbook.com/ProductMSDSDetailCB7457827_EN.htm
tempHigh: 150,
category: "powders",
},
elements.molten_leuprolide = {
tempHigh: 1720, //https://web.archive.org/web/20210512074205/http://www.shreejipharmainternational.com/leuprolide-acetate-1177796.html
stateHigh: "vaporized_leuprolide",
},
elements.vaporized_leuprolide = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
density: 1166,
tempLow: 1720,
stateLow: "molten_leuprolide",
},
//histrelin
elements.histrelin = {
color: "#f8f5ee", //no spectrum available
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
density: 1500, //https://www.chemicalbook.com/ProductMSDSDetailCB7457827_EN.htm
tempHigh: 1800, //https://www.chemsrc.com/en/cas/76712-82-8_1042020.html
stateHigh: "vaporized_histrelin",
category: "powders",
},
elements.vaporized_histrelin = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: behaviors.GAS,
state: "gas",
category: "gases",
hidden: true,
tempLow: 1800,
stateLow: "histrelin",
},
//end of hrt section
elements.densinium = {
color: ["#565656","#575657","#565257","#554d57","#554659"],
tempHigh: 4712, //arbitrary
hardness: 0.9991, //somewhat arbitrary
density: 39180,
conduct: 0.86, //arbitrary
behavior: behaviors.WALL,
state: "solid",
category: "solids",
} //this is effectively a mere interpretation of densinium
elements.molten_densinium = {
hardness: 0.9991,
}
elements.acid.ignore.push("densinium","molten_densinium")
elements.silk_velvet = {
color: ["#edece8", "#ede7e4"],
grain: 0.5,
category: "land",
state: "solid",
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"XX|M1|XX",
],
burnInto: "ash",
burn:72,
burnTime:25,
density: 182,
};
elements.red_velvet = {
color: ["#a80508", "#b30b0e"],
grain: 0.5,
category: "land",
state: "solid",
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"XX|M1|XX",
],
tick: function(pixel) { //alias for velvet that is red
pixel.element = "silk_velvet";
},
burnInto: "ash",
burn: 72,
burnTime: 25,
density: 182,
};
elements.netherrack.hardness = 0.07;
elements.netherrack.breakInto = ["crushed_netherrack","crushed_netherrack","crushed_netherrack","crushed_netherrack","crushed_netherrack","crushed_netherrack","crushed_netherrack","sulfur"] // and some copper, gold, iron, nickel after processing //sulfur closer to 1/7 in-game
elements.netherrack.burn = 9
elements.netherrack.burnTime = 9007199254740995
elements.netherrack.burnInto = "netherrack"
elements.crushed_netherrack = {
color: ["#e34b46","#b04235","#73431f","#522510","#7a3326"],
behavior: behaviors.POWDER,
category:"land",
tempHigh: 2750,
stateHigh: "molten_netherrack",
state: "solid",
density: 1680,
burn: 20,
burnTime: 9007199254740995,
hardness: 0.02,
hidden: true,
};
elements.sencc = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/8)*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc2 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
for (let i = -3; i < 4; i++) {
for (let j = -3; j < 4; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/24)*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc3 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 3
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc4 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 4
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc5 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 5
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc6 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 6
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc7 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 7
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc8 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 8
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc9 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 9
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc10 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 10
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc11 = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
tick: function(pixel) {
pixel.uwu = 0
var squadius = 11
for (let i = (-1*squadius); i < (squadius+1); i++) {
for (let j = (-1*squadius); j < (squadius+1); j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++
}
}
}
}
pixel.uwu -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/((((squadius*2)+1)**2)-1))*pixel.uwu + ",0,0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.sencc2b = { //same element neighbor count check
color: _cc.b.h,
uwu: 0,
owo: 0,
tick: function(pixel) {
pixel.uwu = 0
pixel.owo = 0
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
if(pixel.uwu < 8) {
pixel.uwu++
} else {
pixel.owo++
}
}
}
}
}
pixel.owo -= 1
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu) || pixel.owo == undefined || pixel.owo == null || isNaN(pixel.owo)) {
pixel.color = "rgb(127,127,127)"
} else {
pixel.color = "rgb(" + (255/8)*pixel.uwu + "," + (255/16)*pixel.owo + ",0)"
}
},
category: "machines",
insulate: true,
state: "solid",
hidden: true,
},
elements.discharge = {
color: "#7f7f7f",
tick: function(pixel) {
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
if (!isEmpty(i,j)) {
pixelMap[i][j].charge = 0
}
}
}
deletePixel(pixel.x, pixel.y)
},
category:"special",
insulate:true,
state: "solid",
behavior: behaviors.SELFDELETE,
},
elements.troll_powder = {
color: [_cc.w.h,_cc.b.h],
tick: function(pixel) {
ddd = Math.random()
eee = Math.random()
fff = 1-eee
doHeat(pixel);
doBurning(pixel);
if(ddd < 0.9) {
if(!tryMove(pixel, pixel.x, pixel.y+1)) {
if(eee < 1/2) { tryMove(pixel, pixel.x-1, pixel.y+1) } else tryMove(pixel, pixel.x+1, pixel.y+1)
}
if(Math.random() < 0.0017) {
if(fff < 1/5) { tryMove(pixel, pixel.x-2, pixel.y-1) }
if(fff < 2/5) { tryMove(pixel, pixel.x-1, pixel.y-2) }
if(fff < 3/5) { tryMove(pixel, pixel.x, pixel.y-3) }
if(fff < 4/5) { tryMove(pixel, pixel.x+1, pixel.y-2) }
if(fff < 5/5) { tryMove(pixel, pixel.x+2, pixel.y-1) }
}
if(Math.random() < 0.0003) { tryMove(pixel, pixel.y, pixel.y); }
if(Math.random() < 0.0003) { tryMove(pixel, pixel.x, pixel.x); }
if(((Math.floor(pixel.x/2) % 2 == 0) && (Math.floor(pixel.y/2) % 2 == 0)) || ((Math.floor(pixel.x/2) % 2 == 1) && (Math.floor(pixel.y/2) % 2 == 1))) {
pixel.color = "rgb(32,32,32)"
} else {
pixel.color = "rgb(224,224,224)"
}
}
if(ddd >= 0.9) {
if(!tryMove(pixel, pixel.x, pixel.y-1)) {
if(eee < 1/2) { tryMove(pixel, pixel.x-1, pixel.y-1) } else tryMove(pixel, pixel.x+1, pixel.y-1)
}
if(Math.random() < 0.0017) {
if(fff < 1/5) { tryMove(pixel, pixel.x-2, pixel.y+1) }
if(fff < 2/5) { tryMove(pixel, pixel.x-1, pixel.y+2) }
if(fff < 3/5) { tryMove(pixel, pixel.x, pixel.y+3) }
if(fff < 4/5) { tryMove(pixel, pixel.x+1, pixel.y+2) }
if(fff < 5/5) { tryMove(pixel, pixel.x+2, pixel.y+1) }
}
if(Math.random() < 0.0003) { tryMove(pixel, pixel.y, pixel.y); }
if(Math.random() < 0.0003) { tryMove(pixel, pixel.x, pixel.x); }
if(((Math.floor(pixel.x/2) % 2 == 0) && (Math.floor(pixel.y/2) % 2 == 0)) || ((Math.floor(pixel.x/2) % 2 == 1) && (Math.floor(pixel.y/2) % 2 == 1))) {
pixel.color = "rgb(32,32,32)"
} else {
pixel.color = "rgb(224,224,224)"
}
pixel.temp = pixel.temp + ((Math.floor(Math.random()*3) - 1)*2)
}
},
category: "powders",
state: "solid",
density: 1602,
},
elements.void_first = {
color: "#262626",
tick: function(pixel) {
if(!pixel.void) {
//store 4 touching pixels in variables if the variables don't exist
if(!outOfBounds(pixel.x,pixel.y-1) && !isEmpty(pixel.x,pixel.y-1)) {
if(!pixel.dc1 && pixelMap[pixel.x][pixel.y-1].element != pixel.element) {
pixel.dc1 = pixelMap[pixel.x][pixel.y-1].element
}
}
if(!outOfBounds(pixel.x+1,pixel.y) && !isEmpty(pixel.x+1,pixel.y)) {
if(!pixel.dc2 && pixelMap[pixel.x+1][pixel.y].element != pixel.element) {
pixel.dc2 = pixelMap[pixel.x+1][pixel.y].element
}
}
if(!outOfBounds(pixel.x,pixel.y+1) && !isEmpty(pixel.x,pixel.y+1)) {
if(!pixel.dc3 && pixelMap[pixel.x][pixel.y+1].element != pixel.element) {
pixel.dc3 = pixelMap[pixel.x][pixel.y+1].element
}
}
if(!outOfBounds(pixel.x-1,pixel.y) && !isEmpty(pixel.x-1,pixel.y)) {
if(!pixel.dc3 && pixelMap[pixel.x-1][pixel.y].element != pixel.element) {
pixel.dc4 = pixelMap[pixel.x-1][pixel.y].element
}
}
//choose from 1
if(pixel.dc1 && !pixel.dc2 && !pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
pixel.void = pixel.dc1
}
}
if(!pixel.dc1 && pixel.dc2 && !pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
pixel.void = pixel.dc2
}
}
if(!pixel.dc1 && !pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
pixel.void = pixel.dc3
}
}
if(!pixel.dc1 && !pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
pixel.void = pixel.dc4
}
}
ggg = Math.random()
hhh = Math.random()
iii = Math.random()
//choose from 2
//1100 and 0011
if(pixel.dc1 && pixel.dc2 && !pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
if(ggg < 1/2) {
pixel.void = pixel.dc1
} else {
pixel.void = pixel.dc2
}
}
}
if(!pixel.dc1 && !pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(ggg < 1/2) {
pixel.void = pixel.dc3
} else {
pixel.void = pixel.dc4
}
}
}
//1010 and 0101
if(pixel.dc1 && !pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
if(ggg < 1/2) {
pixel.void = pixel.dc1
} else {
pixel.void = pixel.dc3
}
}
}
if(!pixel.dc1 && pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(ggg < 1/2) {
pixel.void = pixel.dc2
} else {
pixel.void = pixel.dc4
}
}
}
//0110 and 1001
if(!pixel.dc1 && pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
if(ggg < 1/2) {
pixel.void = pixel.dc2
} else {
pixel.void = pixel.dc3
}
}
}
if(pixel.dc1 && !pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(ggg < 1/2) {
pixel.void = pixel.dc1
} else {
pixel.void = pixel.dc4
}
}
}
//choose from 3
//0111
if(!pixel.dc1 && pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(hhh < 1/3) {
pixel.void = pixel.dc2
} else if(hhh < 2/3) {
pixel.void = pixel.dc3
} else {
pixel.void = pixel.dc4
}
}
}
//1011
if(pixel.dc1 && !pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(hhh < 1/3) {
pixel.void = pixel.dc1
} else if(hhh < 2/3) {
pixel.void = pixel.dc3
} else {
pixel.void = pixel.dc4
}
}
}
//1101
if(pixel.dc1 && pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(hhh < 1/3) {
pixel.void = pixel.dc1
} else if(hhh < 2/3) {
pixel.void = pixel.dc2
} else {
pixel.void = pixel.dc4
}
}
}
//1110
if(pixel.dc1 && pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.void) {
if(hhh < 1/3) {
pixel.void = pixel.dc1
} else if(hhh < 2/3) {
pixel.void = pixel.dc2
} else {
pixel.void = pixel.dc3
}
}
}
//choose from 4
//1111
if(pixel.dc1 && pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.void) {
if(iii < 1/4) {
pixel.void = pixel.dc1
} else if(iii < 2/4) {
pixel.void = pixel.dc2
} else if(iii < 3/4) {
pixel.void = pixel.dc3
} else {
pixel.void = pixel.dc4
}
}
}
} else if(pixel.void) {
if(pixel.dc1 || pixel.dc2 || pixel.dc3 || pixel.dc4) {
delete pixel.dc1;
delete pixel.dc2;
delete pixel.dc3;
delete pixel.dc4;
}
}
for(i = 0; i < adjacentCoords.length; i++) {
var pX = pixel.x; var pY = pixel.y; var oX = adjacentCoords[i][0]; var oY = adjacentCoords[i][1]; var nX = pX+oX; var nY = pY+oY;
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY]
var newElement = newPixel.element;
if(newElement != pixel.element && newElement === pixel.void) {
deletePixel(nX,nY);
};
};
};
},
category:"special",
hardness: 1,
},
elements.converter = {
color: "#2ec408",
tick: function(pixel) {
if(!pixel.changeTo) {
//store 4 touching pixels in variables if the variables don't exist
if(!outOfBounds(pixel.x,pixel.y-1) && !isEmpty(pixel.x,pixel.y-1)) {
if(!pixel.dc1 && pixelMap[pixel.x][pixel.y-1].element != pixel.element) {
pixel.dc1 = pixelMap[pixel.x][pixel.y-1].element
}
}
if(!outOfBounds(pixel.x+1,pixel.y) && !isEmpty(pixel.x+1,pixel.y)) {
if(!pixel.dc2 && pixelMap[pixel.x+1][pixel.y].element != pixel.element) {
pixel.dc2 = pixelMap[pixel.x+1][pixel.y].element
}
}
if(!outOfBounds(pixel.x,pixel.y+1) && !isEmpty(pixel.x,pixel.y+1)) {
if(!pixel.dc3 && pixelMap[pixel.x][pixel.y+1].element != pixel.element) {
pixel.dc3 = pixelMap[pixel.x][pixel.y+1].element
}
}
if(!outOfBounds(pixel.x-1,pixel.y) && !isEmpty(pixel.x-1,pixel.y)) {
if(!pixel.dc3 && pixelMap[pixel.x-1][pixel.y].element != pixel.element) {
pixel.dc4 = pixelMap[pixel.x-1][pixel.y].element
}
}
//choose from 1
if(pixel.dc1 && !pixel.dc2 && !pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) {
pixel.changeTo = pixel.dc1
}
}
if(!pixel.dc1 && pixel.dc2 && !pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) {
pixel.changeTo = pixel.dc2
}
}
if(!pixel.dc1 && !pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) {
pixel.changeTo = pixel.dc3
}
}
if(!pixel.dc1 && !pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
pixel.changeTo = pixel.dc4
}
}
ggg = Math.random()
hhh = Math.random()
iii = Math.random()
//choose from 2
//1100 and 0011
if(pixel.dc1 && pixel.dc2 && !pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) {
if(ggg < 1/2) {
pixel.changeTo = pixel.dc1
} else {
pixel.changeTo = pixel.dc2
}
}
}
if(!pixel.dc1 && !pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(ggg < 1/2) {
pixel.changeTo = pixel.dc3
} else {
pixel.changeTo = pixel.dc4
}
}
}
//1010 and 0101
if(pixel.dc1 && !pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) { //7989 yay soshi!
if(ggg < 1/2) {
pixel.changeTo = pixel.dc1
} else {
pixel.changeTo = pixel.dc3
}
}
}
if(!pixel.dc1 && pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(ggg < 1/2) {
pixel.changeTo = pixel.dc2
} else {
pixel.changeTo = pixel.dc4
}
}
}
//0110 and 1001
if(!pixel.dc1 && pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) {
if(ggg < 1/2) {
pixel.changeTo = pixel.dc2
} else {
pixel.changeTo = pixel.dc3
}
}
}
if(pixel.dc1 && !pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(ggg < 1/2) {
pixel.changeTo = pixel.dc1
} else {
pixel.changeTo = pixel.dc4
}
}
}
//choose from 3
//0111
if(!pixel.dc1 && pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(hhh < 1/3) {
pixel.changeTo = pixel.dc2
} else if(hhh < 2/3) {
pixel.changeTo = pixel.dc3
} else {
pixel.changeTo = pixel.dc4
}
}
}
//1011
if(pixel.dc1 && !pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(hhh < 1/3) {
pixel.changeTo = pixel.dc1
} else if(hhh < 2/3) {
pixel.changeTo = pixel.dc3
} else {
pixel.changeTo = pixel.dc4
}
}
}
//1101
if(pixel.dc1 && pixel.dc2 && !pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(hhh < 1/3) {
pixel.changeTo = pixel.dc1
} else if(hhh < 2/3) {
pixel.changeTo = pixel.dc2
} else {
pixel.changeTo = pixel.dc4
}
}
}
//1110
if(pixel.dc1 && pixel.dc2 && pixel.dc3 && !pixel.dc4) {
if(!pixel.changeTo) {
if(hhh < 1/3) {
pixel.changeTo = pixel.dc1
} else if(hhh < 2/3) {
pixel.changeTo = pixel.dc2
} else {
pixel.changeTo = pixel.dc3
}
}
}
//choose from 4
//1111
if(pixel.dc1 && pixel.dc2 && pixel.dc3 && pixel.dc4) {
if(!pixel.changeTo) {
if(iii < 1/4) {
pixel.changeTo = pixel.dc1
} else if(iii < 2/4) {
pixel.changeTo = pixel.dc2
} else if(iii < 3/4) {
pixel.changeTo = pixel.dc3
} else {
pixel.changeTo = pixel.dc4
}
}
}
} else if(pixel.changeTo) {
if(pixel.dc1 || pixel.dc2 || pixel.dc3 || pixel.dc4) {
delete pixel.dc1;
delete pixel.dc2;
delete pixel.dc3;
delete pixel.dc4;
}
}
for(i = 0; i < adjacentCoords.length; i++) {
var pX = pixel.x; var pY = pixel.y; var oX = adjacentCoords[i][0]; var oY = adjacentCoords[i][1]; var nX = pX+oX; var nY = pY+oY;
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY]
var newElement = newPixel.element;
if((elements[pixel.element].ignore ?? []).includes(newElement)) { return };
if(newElement != pixel.element) {
changePixel(newPixel,pixel.changeTo)
};
};
};
},
category:"special",
ignore: ["wall","cloner","liquid_cloner","slow_cloner","void","clone_powder","floating_cloner","void_first","converter"],
hardness: 1,
},
conveyorIgnoreList = ["conveyor_1","conveyor_2","wall"]
elements.conveyor_1 = {
color: "#7f7f7f",
tick: function(pixel) {
//top right
if (!isEmpty(pixel.x,pixel.y-1) && !outOfBounds(pixel.x,pixel.y-1)) {
if (pixelMap[pixel.x][pixel.y-1].element == "body") {
if(!isEmpty(pixel.x,pixel.y-2) && !outOfBounds(pixel.x,pixel.y-2)) {
if (pixelMap[pixel.x][pixel.y-2].element == "head") {
if(isEmpty(pixel.x+1,pixel.y-1) && isEmpty(pixel.x+1,pixel.y-2) && !outOfBounds(pixel.x+1,pixel.y-1) && !outOfBounds(pixel.x+1,pixel.y-2)) {
tryMove(pixelMap[pixel.x][pixel.y-1],pixel.x+1,pixel.y-1)
tryMove(pixelMap[pixel.x][pixel.y-2],pixel.x+1,pixel.y-2)
}
}
} else {
if(isEmpty(pixel.x+1,pixel.y-1) && !outOfBounds(pixel.x+1,pixel.y-1)) {
tryMove(pixelMap[pixel.x][pixel.y-1],pixel.x+1,pixel.y-1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x][pixel.y-1].element)) {
tryMove(pixelMap[pixel.x][pixel.y-1],pixel.x+1,pixel.y-1)
}
}
//right down
if (!isEmpty(pixel.x+1,pixel.y) && !outOfBounds(pixel.x+1,pixel.y)) {
if (pixelMap[pixel.x+1][pixel.y].element == "body") {
if(!isEmpty(pixel.x+1,pixel.y-1) && !outOfBounds(pixel.x+1,pixel.y-1)) {
if (pixelMap[pixel.x+1][pixel.y-1].element == "head") {
if(isEmpty(pixel.x+1,pixel.y+1) && !outOfBounds(pixel.x+1,pixel.y+1)) {
tryMove(pixelMap[pixel.x+1][pixel.y],pixel.x+1,pixel.y+1)
tryMove(pixelMap[pixel.x+1][pixel.y-1],pixel.x+1,pixel.y)
}
}
} else {
if(isEmpty(pixel.x+1,pixel.y+1) && !outOfBounds(pixel.x+1,pixel.y+1)) {
tryMove(pixelMap[pixel.x+1][pixel.y],pixel.x+1,pixel.y+1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x+1][pixel.y].element)) {
tryMove(pixelMap[pixel.x+1][pixel.y],pixel.x+1,pixel.y+1)
}
}
//bottom left
if (!isEmpty(pixel.x,pixel.y+1) && !outOfBounds(pixel.x,pixel.y+1)) {
if (pixelMap[pixel.x][pixel.y+1].element == "head") {
if(!isEmpty(pixel.x,pixel.y+2) && !outOfBounds(pixel.x,pixel.y+2)) {
if (pixelMap[pixel.x][pixel.y+2].element == "body") {
if(isEmpty(pixel.x-1,pixel.y+1) && isEmpty(pixel.x-1,pixel.y+2) && !outOfBounds(pixel.x-1,pixel.y+2) && !outOfBounds(pixel.x-1,pixel.y+2)) {
tryMove(pixelMap[pixel.x][pixel.y+1],pixel.x-1,pixel.y+1)
tryMove(pixelMap[pixel.x][pixel.y+2],pixel.x-1,pixel.y+2)
}
}
} else {
if(isEmpty(pixel.x-1,pixel.y+1) && !outOfBounds(pixel.x-1,pixel.y+1)) {
tryMove(pixelMap[pixel.x][pixel.y+1],pixel.x-1,pixel.y+1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x][pixel.y+1].element)) {
tryMove(pixelMap[pixel.x][pixel.y+1],pixel.x-1,pixel.y+1)
}
}
//left up
if (!isEmpty(pixel.x-1,pixel.y) && !outOfBounds(pixel.x-1,pixel.y)) {
if (pixelMap[pixel.x-1][pixel.y].element == "head") {
if(!isEmpty(pixel.x-1,pixel.y+1) && !outOfBounds(pixel.x-1,pixel.y+1)) {
if (pixelMap[pixel.x-1][pixel.y+1].element == "body") {
if(isEmpty(pixel.x-1,pixel.y-1) && !outOfBounds(pixel.x-1,pixel.y-1)) {
tryMove(pixelMap[pixel.x-1][pixel.y],pixel.x-1,pixel.y-1)
tryMove(pixelMap[pixel.x-1][pixel.y+1],pixel.x-1,pixel.y)
}
}
} else {
if(isEmpty(pixel.x-1,pixel.y-1) && !outOfBounds(pixel.x-1,pixel.y-1)) {
tryMove(pixelMap[pixel.x-1][pixel.y],pixel.x-1,pixel.y-1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x-1][pixel.y].element)) {
tryMove(pixelMap[pixel.x-1][pixel.y],pixel.x-1,pixel.y-1)
}
}
},
category: "machines",
insulate: true,
state: "solid",
},
elements.conveyor_2 = {
color: "#7f7f7f",
tick: function(pixel) {
//top left
if (!isEmpty(pixel.x,pixel.y-1) && !outOfBounds(pixel.x,pixel.y-1)) {
if (pixelMap[pixel.x][pixel.y-1].element == "body") {
if(!isEmpty(pixel.x,pixel.y-2) && !outOfBounds(pixel.x,pixel.y-2)) {
if (pixelMap[pixel.x][pixel.y-2].element == "head") {
if(isEmpty(pixel.x-1,pixel.y-1) && isEmpty(pixel.x-1,pixel.y-2) && !outOfBounds(pixel.x-1,pixel.y-1) && !outOfBounds(pixel.x-1,pixel.y-2)) {
tryMove(pixelMap[pixel.x][pixel.y-1],pixel.x-1,pixel.y-1)
tryMove(pixelMap[pixel.x][pixel.y-2],pixel.x-1,pixel.y-2)
}
}
} else {
if(isEmpty(pixel.x-1,pixel.y-1) && !outOfBounds(pixel.x-1,pixel.y-1)) {
tryMove(pixelMap[pixel.x][pixel.y-1],pixel.x-1,pixel.y-1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x][pixel.y-1].element)) {
tryMove(pixelMap[pixel.x][pixel.y-1],pixel.x-1,pixel.y-1)
}
}
//right up
if (!isEmpty(pixel.x+1,pixel.y) && !outOfBounds(pixel.x+1,pixel.y)) {
if (pixelMap[pixel.x+1][pixel.y].element == "head") {
if(!isEmpty(pixel.x+1,pixel.y+1) && !outOfBounds(pixel.x+1,pixel.y+1)) {
if (pixelMap[pixel.x+1][pixel.y+1].element == "body") {
if(isEmpty(pixel.x+1,pixel.y-1) && !outOfBounds(pixel.x+1,pixel.y-1)) {
tryMove(pixelMap[pixel.x+1][pixel.y],pixel.x+1,pixel.y-1)
tryMove(pixelMap[pixel.x+1][pixel.y+1],pixel.x+1,pixel.y)
}
}
} else {
if(isEmpty(pixel.x+1,pixel.y-1) && !outOfBounds(pixel.x+1,pixel.y-1)) {
tryMove(pixelMap[pixel.x+1][pixel.y],pixel.x+1,pixel.y-1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x+1][pixel.y].element)) {
tryMove(pixelMap[pixel.x+1][pixel.y],pixel.x+1,pixel.y-1)
}
}
//bottom right
if (!isEmpty(pixel.x,pixel.y+1) && !outOfBounds(pixel.x,pixel.y+1)) {
if (pixelMap[pixel.x][pixel.y+1].element == "head") {
if(!isEmpty(pixel.x,pixel.y+2) && !outOfBounds(pixel.x,pixel.y+2)) {
if (pixelMap[pixel.x][pixel.y+2].element == "body") {
if(isEmpty(pixel.x+1,pixel.y+1) && isEmpty(pixel.x+1,pixel.y+2) && !outOfBounds(pixel.x+1,pixel.y+2) && !outOfBounds(pixel.x+1,pixel.y+2)) {
tryMove(pixelMap[pixel.x][pixel.y+1],pixel.x+1,pixel.y+1)
tryMove(pixelMap[pixel.x][pixel.y+2],pixel.x+1,pixel.y+2)
}
}
} else {
if(isEmpty(pixel.x+1,pixel.y+1) && !outOfBounds(pixel.x+1,pixel.y+1)) {
tryMove(pixelMap[pixel.x][pixel.y+1],pixel.x+1,pixel.y+1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x][pixel.y+1].element)) {
tryMove(pixelMap[pixel.x][pixel.y+1],pixel.x+1,pixel.y+1)
}
}
//left down
if (!isEmpty(pixel.x-1,pixel.y) && !outOfBounds(pixel.x-1,pixel.y)) {
if (pixelMap[pixel.x-1][pixel.y].element == "body") {
if(!isEmpty(pixel.x-1,pixel.y-1) && !outOfBounds(pixel.x-1,pixel.y-1)) {
if (pixelMap[pixel.x-1][pixel.y-1].element == "head") {
if(isEmpty(pixel.x-1,pixel.y+1) && !outOfBounds(pixel.x-1,pixel.y+1)) {
tryMove(pixelMap[pixel.x-1][pixel.y],pixel.x-1,pixel.y+1)
tryMove(pixelMap[pixel.x-1][pixel.y-1],pixel.x-1,pixel.y)
}
}
} else {
if(isEmpty(pixel.x-1,pixel.y+1) && !outOfBounds(pixel.x-1,pixel.y+1)) {
tryMove(pixelMap[pixel.x-1][pixel.y],pixel.x-1,pixel.y+1)
}
}
} else if(!conveyorIgnoreList.includes(pixelMap[pixel.x-1][pixel.y].element)) {
tryMove(pixelMap[pixel.x-1][pixel.y],pixel.x-1,pixel.y+1)
}
}
},
category: "machines",
insulate: true,
state: "solid",
},
elements.vanishing_wall = {
behavior: behaviors.WALL,
color: "#8080b0",
colorObject: hexToRGB("#8080b0"),
density: 3333,
tick: function(pixel) {
pixelTick(pixel)
if(pixel.charge) {
if(!isEmpty(pixel.x,pixel.y)) {
deletePixel(pixel.x,pixel.y)
}
}
},
category: "special",
state: "solid",
hardness: 1,
insulate: true,
conduct: 1,
extraInfo: "It disappears when charged.",
},
elements.vanishing_steel = {
color: "#71797E",
behavior: behaviors.WALL,
tick: function(pixel) {
pixelTick(pixel);
if(pixel.charge) {
if(!isEmpty(pixel.x,pixel.y)) {
deletePixel(pixel.x,pixel.y);
};
};
},
category: "solids",
state: "solid",
density: 7850,
conduct: 1,
hardness: 0.8,
};
elements.polka_dotted_powder = {
color: [_cc.b.h,_cc.b.h,"#7f7f7f",_cc.w.h,_cc.w.h],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 1400,
tick: function(pixel) {
if(pixel.y % 6 == 0) {
if(pixel.x % 6 == 0) {
pixel.color = _cc.w.r
} else {
if(!settings.bg || settings.bg == _cc.b.h) {
pixel.color = "rgb(15,15,15)"
} else {
pixel.color = _cc.b.r
}
}
} else if((pixel.y + 3) % 6 == 0) {
if((pixel.x + 3) % 6 == 0) {
pixel.color = _cc.w.r
} else {
if(!settings.bg || settings.bg == _cc.b.h) {
pixel.color = "rgb(15,15,15)"
} else {
pixel.color = _cc.b.r
}
}
} else {
if(!settings.bg || settings.bg == _cc.b.h) {
pixel.color = "rgb(15,15,15)"
} else {
pixel.color = _cc.b.r
}
}
},
tempHigh: 800,
},
elements.molten_polka_dotted_powder = {
color: ["#ff7f00","#ff7f00","#ff9f00","#ffbf00","#ffbf00"],
density: 1100,
tick: function(pixel) {
if(pixel.y % 6 == 0) {
if(pixel.x % 6 == 0) {
pixel.color = "rgb(255,191,0)"
} else {
if(!settings.bg || settings.bg == "#ff7f00") {
pixel.color = "rgb(255,143,16)"
} else {
pixel.color = "rgb(255,127,16)"
}
}
} else if((pixel.y + 3) % 6 == 0) {
if((pixel.x + 3) % 6 == 0) {
pixel.color = "rgb(255,191,0)"
} else {
if(!settings.bg || settings.bg == "#ff7f00") {
pixel.color = "rgb(255,143,16)"
} else {
pixel.color = "rgb(255,127,16)"
}
}
} else {
if(!settings.bg || settings.bg == "#ff7f00") {
pixel.color = "rgb(255,143,16)"
} else {
pixel.color = "rgb(255,127,16)"
}
}
},
temp: 850,
tempLow: 800,
stateLow: "polka_dotted_powder",
tempHigh: 2000,
stateHigh: "vaporized_polka_dotted_powder",
viscosity: 6,
hidden: true,
},
elements.vaporized_polka_dotted_powder = {
color: ["#ffdf7f","#ffdf7f","#ffefbf",_cc.w.h,_cc.w.h],
behavior: behaviors.GAS,
category: "gases",
state: "gas",
density: 550,
tick: function(pixel) {
if(pixel.y % 6 == 0) {
if(pixel.x % 6 == 0) {
pixel.color = _cc.w.r
} else {
if(!settings.bg || settings.bg == "#ffdf7f") {
pixel.color = "rgb(255,233,137)"
} else {
pixel.color = "rgb(255,223,127)"
}
}
} else if((pixel.y + 3) % 6 == 0) {
if((pixel.x + 3) % 6 == 0) {
pixel.color = _cc.w.r
} else {
if(!settings.bg || settings.bg == "#ffdf7f") {
pixel.color = "rgb(255,143,16)"
} else {
pixel.color = "rgb(255,233,137)"
}
}
} else {
if(!settings.bg || settings.bg == "#ffdf7f") {
pixel.color = "rgb(255,233,137)"
} else {
pixel.color = "rgb(255,223,127)"
}
}
},
temp: 2200,
tempLow: 2000,
stateLow: "molten_polka_dotted_powder",
tempHigh: 8000,
stateHigh: "ionized_polka_dotted_powder",
hidden: true,
},
elements.ionized_polka_dotted_powder = {
color: ["#fffff0","#fffff0","#fffff7",_cc.w.h,_cc.w.h],
behavior: [
"M2 AND CR:plasma%0.3|M1|M2 AND CR:plasma%0.3",
"M1|XX|M1",
"M2 AND CR:plasma%0.3|M1|M2 AND CR:plasma%0.3",
],
category: "gases",
state: "gas",
density: 0.02,
tick: function(pixel) {
if(pixel.y % 6 == 0) {
if(pixel.x % 6 == 0) {
pixel.color = _cc.w.r
} else {
if(!settings.bg || settings.bg == "#fffff0") {
pixel.color = "rgb(255,255,247)"
} else {
pixel.color = "rgb(255,255,240)"
}
}
} else if((pixel.y + 3) % 6 == 0) {
if((pixel.x + 3) % 6 == 0) {
pixel.color = _cc.w.r
} else {
if(!settings.bg || settings.bg == "#fffff0") {
pixel.color = "rgb(255,255,247)"
} else {
pixel.color = "rgb(255,255,240)"
}
}
} else {
if(!settings.bg || settings.bg == "#fffff0") {
pixel.color = "rgb(255,255,247)"
} else {
pixel.color = "rgb(255,255,240)"
}
}
},
temp: 8500,
tempLow: 8000,
stateLow: "vaporized_polka_dotted_powder",
hidden: true,
},
elements.hdet = {
name: "heat- dependent explosion text",
color: "#33aa44",
behavior: behaviors.POWDER,
tick: function(pixel) {
if(pixel.charge > 0) {
var temp = pixel.temp
if(temp < 0) {
temp = 0
}
if(temp >= 0 && temp < 1) {
temp = 1
}
if(temp > 56000) {
temp = 56000
}
if(isNaN(temp) || isNaN(pixel.temp)) {
temp = 20
pixel.temp = 20
}
var r = ((Math.sqrt((Math.log(temp)/Math.log(20)))*(temp**0.5))/(6000**0.126284318))/2
explodeAt(pixel.x,pixel.y,Math.floor(r))
if(temp > 200) {
if(Math.random() < (Math.log(temp)/Math.log(56000))**9) {
pixel.charge = 1
if(pixel.chargeCD) {
delete pixel.chargeCD
}
}
}
if(isNaN(temp) || isNaN(pixel.temp)) {
temp = 20
pixel.temp = 20
}
}
},
density: 1200,
conduct: 0.5,
state: "solid",
category: "special"
},
function randInt(max) {
return Math.floor(Math.random() * (max + 1))
}
function randIntR(min,max) {
if(min > max) {
var temp = max; //the need of a temporary space has always annoyed me
max = min;
min = temp;
};
return Math.floor(Math.random() * (max - min + 1)) + min
};
elements.lower_color_copy = {
behavior: behaviors.POWDER,
tick: function(pixel) {
if(!isEmpty(pixel.x,pixel.y+1,true)) {
pixel.color = pixelMap[pixel.x][pixel.y+1].color;
} else {
if(settings.bg) {
pixel.color = settings.bg;
} else {
pixel.color = _cc.b.h;
}
}
},
color: [_cc.b.h, _cc.b.h, _cc.b.h, _cc.b.h, _cc.b.h, _cc.b.h, _cc.b.h, "#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#007FFF", "#0000FF", "#7F00FF"],
density: 1250,
breakInto: ["metal_scrap", "glass_shard"],
hardness: 0.7,
}
elements.brimstone_slag = {
color: ["#745B57","#534D4A","#463F53","#51113E","#6D283B","#BC4949","#EA9B4E"],
fireColor: ["#E50000", "#D52D2D", "#EE4545", "#F8A7A7"],
properties: {
needsOffset: true
},
colorPattern: [
"FGGFGFGGF",
"FFGFGFFGG",
"DEEDEEDEE",
"DEDEEEEED",
"BDCBACDCB",
"BCADCDDBB",
"ABBCAABCC"
],
colorKey: {
"A": "#745B57",
"B": "#534D4A",
"C": "#463F53",
"D": "#51113E",
"E": "#6D283B",
"F": "#BC4949",
"G": "#EA9B4E",
},
behavior: behaviors.POWDER,
hardness: 0.5,
enableOffsetsOnTextureColors: true,
breakInto: ["slag","sulfur"],
tempHigh: 1780,
state: "solid",
category: "solids",
tick: function(pixel) {
if(pixel.needsOffset) {
var offset = 15;
offset = randomIntegerFromZeroToValue(offset) * (Math.random() < 0.5 ? -1 : 1);
pixel.color = convertColorFormats(pixel.color,"json");
for(var k in pixel.color) { pixel.color[k] += offset };
pixel.color = convertColorFormats(pixel.color,"rgb");
delete pixel.needsOffset;
return
}
}
};
elements.molten_slag ??= {};
elements.molten_slag.reactions ??= {};
elements.molten_slag.reactions.sulfur = elements.molten_slag.reactions.molten_sulfur = elements.molten_slag.reactions.sulfur_gas = elements.molten_sulfur.reactions.slag = elements.sulfur.reactions.molten_slag = { elem1: "brimstone_slag", elem2: null };
elements.slag.tempHigh = 1780;
var temp = "firesea,lektre,concoction,mistake,unstable_mistake,toxic_mistake".split(",");
for(var i = 0; i < temp.length; i++) {
temp[i].state = "liquid";
temp[i].category = "liquids"
};
elements.head.cutInto = ["bone","meat","blood"];
elements.body.cutInto = ["bone","meat","meat","blood","blood"];
elements.wood.cutInto = ["wood_plank","wood_plank","wood_plank","wood_plank","wood_plank","wood_plank","wood_plank","wood_plank","sawdust"];
elements.fish.breakInto = ["meat","meat","bone","blood"];
elements.fish.cutInto = ["meat","meat","bone","blood"];
elements.bladesea = {
color: ["#959696", "#b1b3b3", "#d4d4d4", "#bfbdbd"],
state: "liquid",
viscosity: 5,
behavior: behaviors.LIQUID,
tick: function(pixel) { //Code from R74n/vanilla "smash" tool
var pX = pixel.x;
var pY = pixel.y;
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pX+oX;
var fY = pY+oY;
if(!isEmpty(fX,fY,true)) {
var checkPixel = pixelMap[fX][fY];
var otherElement = elements[checkPixel.element];
if (typeof(otherElement.cutInto) !== "undefined") {
var hardness = otherElement.hardness ?? 0;
if (Math.random() < (1 - hardness)) {
var cutInto = otherElement.cutInto;
// if breakInto is an array, pick one
if (Array.isArray(cutInto)) {
cutInto = randomChoice(cutInto);
};
changePixel(checkPixel,cutInto);
}
}
};
};
},
density: 200,
category: "liquids",
hidden: true,
reactions: {
"concoction": { "elem1": "bladesea", "elem2": "bladesea", "chance":0.005},
},
};
function newLegacyFnmDye(colorName,hexColor) {
if(!(hexColor.startsWith("#"))) { hexColor = "#" + hexColor };
colorName = colorName.toLowerCase();
var key = `${colorName}_dye`;
var name = `${colorName.replaceAll("_"," ")} dye`;
var pixelColor = changeLightness(hexColor,0.73333333333333,"multiply","hex",null,false);
elements[key] = {
"name": name,
"color": pixelColor,
"state": "solid",
"behavior": [
"XX|XX|XX",
`CC:${hexColor}|CC:${pixelColor}|CC:${hexColor}`,
`M2 AND CC:${hexColor}|M1 AND CC:${hexColor}|M2 AND CC:${hexColor}`
],
"density": 100,
"category": "dyes"
};
eLists.DYE.push(key);
elements.concoction.reactions[key] = { "elem1": "mistake", "elem2": null };
return elements[key]
};
var dyeColors = [
["rose", "#FF0067"],
["orange", "#FF7F00"],
["pink", "#FF7FFF"],
["purple", "#C700CF"],
["burgundy", "#9F005F"],
["peach", "#ffbf7f"],
["mint", "#4df0a9"],
["gray", "#7F7F7F"],
["lime", "#7FFF00"],
["black", _cc.b.h],
["white", _cc.w.h],
["sky_blue", "#99d1f2"]
];
for(var i = 0; i < dyeColors.length; i++) {
newLegacyFnmDye(dyeColors[i][0],dyeColors[i][1])
};
eLists.LED = ["led_r","led_g","led_b"];
function newLED(abbrev,hexColor,baseColorOverrideHex=null) {
if(!(hexColor.startsWith("#"))) { hexColor = "#" + hexColor };
if(baseColorOverrideHex && !(baseColorOverrideHex.startsWith("#"))) { baseColorOverrideHex = "#" + baseColorOverrideHex };
abbrev = abbrev.toLowerCase();
var key = `led_${abbrev}`;
var pixelColor = baseColorOverrideHex ?? changeLightness(hexColor,0x66/0xff,"multiply","hex",null,false);
elements[key] = {
behavior: behaviors.WALL,
reactions: {
"light": {"charge1":1},
"liquid_light": {"charge1":1},
},
color: pixelColor,
colorOn: hexColor,
category: "machines",
tempHigh: 1500,
stateHigh: ["molten_glass","molten_glass","molten_glass","molten_gallium"],
conduct: 1,
breakInto: "glass_shard"
};
eLists.LED.push(key)
};
var ledColors = [
["c", "#00FFFF"], //cyan
["y", "#FFFF00"], //yellow
["m", "#FF00FF"], //magenta (cursed)
["p", "#AB00C2"], //purple (cursed)
["v", "#7700FF"], //violet
["w", _cc.w.h], //white (cursed)
["gy", "#7F7F7F"], //gray (more cursed)
["bl", _cc.b.h, "#2b2b2b"], //black (super cursed)
["o", "#FF7F00"], //orange
["a", "#FFBF00"], //amber
["l", "#7FFF00"], //lime
["rs", "#FF0067"], //rose (cursed)
["pk", "#FF7FFF"], //pink (cursed)
["bg", "#9F005F"], //burgundy (cursed)
["pc", "#ffbf7f"], //peach
["mg", "#4df0a9"], //mint green
["sb", "#99d1f2"] //sky blue (cursed)
];
for(var i = 0; i < ledColors.length; i++) {
newLED(...ledColors[i]);
};
for(var i = 0; i < eLists.LED.length; i++) {
var key = eLists.LED[i];
elements.malware.reactions[key] = { elem2:eLists.LED, chance:0.01 }
};
function heatNeighbors(pixel,temp,trueIfMooreFalseIfNeumann=false) {
var neighborOffsets = trueIfMooreFalseIfNeumann ? squareCoords : adjacentCoords;
var pX = pixel.x;
var pY = pixel.y;
for(var i = 0; i < neighborOffsets.length; i++) {
var offsets = neighborOffsets[i];
var newPixel = pixelMap[pX + offsets[0]]?.[pY + offsets[1]];
if(!newPixel) { continue };
newPixel["temp"] += temp;
pixelTempCheck(newPixel)
}
};
function getNeighborCount(pixel,useVonNeumannGrid=false) {
var x = pixel.x;
var y = pixel.y;
return (
0 +
(!isEmpty(x-1,y,true)) +
(!isEmpty(x+1,y,true)) +
(!isEmpty(x,y-1,true)) +
(!isEmpty(x,y+1,true))
) + (
(!useVonNeumannGrid) && (
(!isEmpty(x-1,y-1,true)) +
(!isEmpty(x+1,y+1,true)) +
(!isEmpty(x+1,y-1,true)) +
(!isEmpty(x-1,y+1,true))
)
);
};
elements.amba_black_hole = {
color: _cc.b.h,
grain: 0,
excludeRandom: true,
insulate: true,
onSelect: function() {
if(typeof(showPropertySetter) == "function") { showPropertySetter() };
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","blackHoleRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.blackHoleRange;
};
if(p0h) {
p0h.innerText = "Radius";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter
},
renderer: function(pixel,ctx) {
if(shiftDown || currentElement == pixel.element) {
//for some reason the range is fucked up (centered around the top left of the pixel, and always even) so that's the behavior we need to indicate
drawSquare(ctx, "#202020", pixel.x - 0.5, pixel.y - 0.5);
if(pixel.range !== undefined) {
var centerX = (pixel.x) * pixelSize;
var centerY = (pixel.y) * pixelSize;
var radius = pixel.range * pixelSize;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = 2;
ctx.strokeStyle = 'rgba(127,127,127,0.5)';
ctx.stroke();
}
}
},
hoverStat: (pixel => `r = ${(pixel.range?.toString() ?? "??")}`),
tick: function(pixel) {
pixel.color = _cc.b.r;
//if(pixelTicks == pixel.start) { console.log("spawn range",ambaPlaceProperties.blackHoleRange) };
pixel.range ??= ambaPlaceProperties?.blackHoleRange ?? 15;
//if(pixelTicks == pixel.start) { console.log("this range",pixel.range) };
if(pixel.range <= 0) { deletePixel(pixel.x,pixel.y); return };
var range = (pixel.range ?? (ambaPlaceProperties?.blackHoleRange ?? 15)) * 2;
if(settings.dopressure) { changePressure(pixel.x,pixel.y,10 + ((range / 2) ** 2),"-",true) };
var targets = mouseLikeRange(pixel.x,pixel.y,range,"circle",true);
shuffleArray(targets);
for (var i = 0; i < targets.length; i++) {
var newPixel = pixelMap[targets[i][0]]?.[targets[i][1]];
if ((!newPixel) || newPixel.del) { continue };
if(elements[pixel.element].ignore && elements[pixel.element].ignore.includes(newPixel.element)) { continue };
newPixel.tempDrag = pixelTicks + 1;
var [mX, mY] = [pixel.x, pixel.y];
var distanceComplement = (range / 2) - pyth(mX,mY,newPixel.x,newPixel.y);
var distanceProportion = 0.2 + (distanceComplement / (range / 2));
var distanceModifier = distanceProportion ** 2;
var pullCount = (4 * distanceModifier) * (commonMovableCriteria(newPixel.element) ? 1 : 0.8) * (1 - (((getNeighborCount(newPixel)) / (8.1 + ((elements[newPixel.element].hardness ?? 0) * 3)))));
var pullCountIntegerPart = Math.floor(pullCount);
var pullCountFractionalPart = pullCount % 1;
var truePullCount = Math.min(3,pullCountIntegerPart + (Math.random() < pullCountFractionalPart));
for(var j = 0; j < truePullCount; j++) {
if((pullCountIntegerPart >= 1) && (Math.random() < distanceProportion)) { tryBreak(newPixel) };
var x = newPixel.x;
var y = newPixel.y;
var empty = checkForEmptyPixels(x, y);
let bestVal = Math.sqrt(Math.pow(mX - x, 2) + Math.pow(mY - y, 2));
let best = null;
for (const pixelPair of empty) {
const x_ = x + pixelPair[0];
const y_ = y + pixelPair[1];
const c = Math.sqrt(Math.pow(mX - x_, 2) + Math.pow(mY - y_, 2));
if (c < bestVal) {
bestVal = c;
best = pixelPair;
}
}
if (best) {
newPixel.vx ??= 0;
newPixel.vy ??= 0;
var _vx = (truePullCount * (best[0])); _vx += Math.sign(_vx);
var _vy = (truePullCount * (best[1])); _vy += Math.sign(_vy);
newPixel.vx += _vx;
newPixel.vy += _vy;
tryMove(newPixel, x + best[0], y + best[1], undefined, true);
if(haseuliteSpreadWhitelist.includes(newPixel.element)) { newPixel.value += ((15 + (distanceComplement / (distanceProportion ** 2))) * 3) };
var heat = (20 * pullCount) * getNeighborCount(newPixel);
heatNeighbors(newPixel,heat);
pixel.temp += heat;
pixelTempCheck(pixel);
}
};
var taxicabDistance = Math.abs(newPixel.x - pixel.x) + Math.abs(newPixel.y - pixel.y);
if((taxicabDistance <= 3) && (taxicabDistance > 0)) {
pixel.temp += (newPixel.temp - (settings.abszero ?? 273.15));
if(["amba_black_hole","amba_white_hole"].includes(newPixel.element) && ((newPixel.range ?? 15) > 0) && (newPixel !== pixel)) {
//console.log("adding range on tick",pixelTicks);
pixel.range ??= (ambaPlaceProperties?.blackHoleRange ?? 15);
var rangeChange = (newPixel.range ?? (ambaPlaceProperties?.blackHoleRange ?? 15));
switch(newPixel.element) {
case "amba_black_hole":
//console.log("range add",rangeChange);
pixel.range += rangeChange;
//console.log("new range",pixel.range);
break;
case "amba_white_hole":
//console.log("range remove",rangeChange);
pixel.range -= rangeChange;
//console.log("new range",pixel.range);
break;
}
//console.log("new range:",pixel.range);
newPixel.range = 0;
} else {
deletePixel(newPixel.x,newPixel.y);
continue
}
}
}
},
state: undefined,
density: 1797.69313486e305, //about as close to Infinity as we can serializably get
category: "special",
hardness: 1,
maxSize: 1,
ignore: ["wall"].concat(eLists.CLONERS)
};
elements.amba_white_hole = {
color: _cc.w.h,
grain: 0,
excludeRandom: true,
insulate: true,
onSelect: function() {
showPropertySetter();
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","whiteHoleRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.whiteHoleRange;
};
if(p0h) {
p0h.innerText = "Radius";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter
},
renderer: function(pixel,ctx) {
drawSquare(ctx, "#ffffff", pixel.x - 0.5, pixel.y - 0.5);
if(shiftDown || currentElement == pixel.element) {
//for some reason the range is fucked up (centered around the top left of the pixel, and always even) so that's the behavior we need to indicate
if(pixel.range !== undefined) {
var centerX = (pixel.x) * pixelSize;
var centerY = (pixel.y) * pixelSize;
var radius = pixel.range * pixelSize;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = 2;
ctx.strokeStyle = 'rgba(127,127,127,0.5)';
ctx.stroke();
}
}
},
hoverStat: (pixel => `r = ${(pixel.range?.toString() ?? "??")}`),
tick: function(pixel) {
pixel.color = _cc.w.r;
pixel.range ??= (ambaPlaceProperties?.whiteHoleRange ?? 15);
if(pixel.range <= 0) { deletePixel(pixel.x,pixel.y); return };
var range = (pixel.range ?? (ambaPlaceProperties?.whiteHoleRange ?? 15)) * 2;
var targets = mouseLikeRange(pixel.x,pixel.y,range,"circle",true);
shuffleArray(targets);
for (var i = 0; i < targets.length; i++) {
var newPixel = pixelMap[targets[i][0]]?.[targets[i][1]];
if ((!newPixel) || newPixel.del) { continue };
if(((newPixel.element == pixel.element) || (elements[pixel.element].ignore && elements[pixel.element].ignore.includes(newPixel.element))) || ((newPixel.x == pixel.x) && (newPixel.y == pixel.y))) { continue };
newPixel.tempDrag = pixelTicks + 1;
var [mX, mY] = [pixel.x, pixel.y];
var distanceComplement = (range / 2) - pyth(mX,mY,newPixel.x,newPixel.y);
var distanceProportion = 0.2 + (distanceComplement / (range / 2));
var distanceModifier = distanceProportion ** 2;
var pullCount = (4 * distanceModifier) * (commonMovableCriteria(newPixel.element) ? 1 : 0.8);
var pullCountIntegerPart = Math.floor(pullCount);
var pullCountFractionalPart = pullCount % 1;
var truePullCount = Math.min(3,pullCountIntegerPart + (Math.random() < pullCountFractionalPart));
for(var j = 0; j < truePullCount; j++) {
if((pullCountIntegerPart >= 1) && (Math.random() < pullCount / 3)) { tryBreak(newPixel) };
var x = newPixel.x;
var y = newPixel.y;
var empty = checkForEmptyPixels(x, y);
let bestVal = Math.sqrt(Math.pow(mX - x, 2) + Math.pow(mY - y, 2));
let best = null;
for (const pixelPair of empty) {
const x_ = x + pixelPair[0];
const y_ = y + pixelPair[1];
const c = Math.sqrt(Math.pow(mX - x_, 2) + Math.pow(mY - y_, 2));
if (c < bestVal) {
bestVal = c;
best = pixelPair;
}
}
if (best) {
var destCoords = [x - best[0], y - best[1]];
newPixel.vx ??= 0;
newPixel.vy ??= 0;
var _vx = -(truePullCount * (best[0])); _vx += Math.sign(_vx);
var _vy = -(truePullCount * (best[1])); _vy += Math.sign(_vy);
newPixel.vx += _vx;
newPixel.vy += _vy;
var moveResult = tryMoveAndReturnBlockingPixel(newPixel, destCoords[0], destCoords[1], undefined, true);
if((moveResult !== true) && !(outOfBounds(...destCoords))) {
swapPixels(newPixel,moveResult);
tryMove(newPixel, destCoords[0] - best[0], destCoords[1] - best[1], undefined, true)
};
heatNeighbors(newPixel,20);
var a0 = settings.abszero ?? -273.15;
if(pixel.temp >= a0) {
if(pixel.temp <= (a0 + 20)) {
pixel.temp = a0
} else {
pixel.temp -= 20
}
}
}
}
}
},
state: undefined,
density: -(1797.69313486e305), //about as close to -Infinity as we can serializably get
category: "special",
hardness: 1,
maxSize: 1
};
elements.pus = {
color: "#bfba71",
behavior: behaviors.LIQUID,
reactions: {
"water": { elem1:["pus","pus","pus","pus","pus","pus","dirty_water"], elem2:"dirty_water", chance:0.01 },
"blood": { elem1:["pus","pus","pus","pus","pus","pus","infection"], elem2:"infection", chance:0.01 },
"poison": { elem1:"bio_ooze", elem2:"bio_ooze", chance:0.2 },
"bio_ooze": { elem1:"bio_ooze", chance:0.2 },
"frog": { elem2:"rotten_meat", chance:0.005 },
"fish": { elem2:"rotten_meat", chance:0.005 },
"meat": { elem2:"rotten_meat", chance:0.005 },
"alcohol": { elem1:"dirty_water", chance:0.2 }
},
viscosity: 30,
tempHigh: 124.55,
stateHigh: ["plague","stench","steam","steam","steam","salt"],
tempLow: -2,
category:"liquids",
hidden: true,
state: "liquid",
density: 1100,
stain: 0.08
};
//ASSORTED RAINBOW VARIANTS ##
elements.concoction.reactions.diorite_gravel = {
elem1: "static", elem2: null
};
elements.concoction.reactions.static = { //spread
elem1: "static", elem2: "static"
};
elements.concoction.state = "liquid";
elements.static.reactions ??= {}; elements.static.reactions.concoction = { "elem1": "static", "elem2": "static", "chance":0.005},
/*function isRed(colorIn) {
var color = colorToHsl(colorIn,"json");
var modularHue = color.h % 360;
if (!((modularHue >= -10 && modularHue <= 10) || modularHue >= 350)) { return false };
if (color.s < 55) { return false };
if (color.l < 40 || color.l > 60) { return false };
return true
};
function isWhite(colorIn) {
var color = colorToHsl(colorIn,"json");
return color.s <= 15 && color.l >= 85
};*/
elements.rainbow.reactions ??= {};
elements.rainbow.reactions.fire = { elem1: "fireshimmer", chance: 0.1 };
elements.rainbow.reactions.plasma = { elem1: "plasmashimmer", chance: 0.1 };
elements.rainbow.insulate = false;
elements.rainbow.burnInto = "fireshimmer";
elements.rainbow.burn = 0.1;
elements.rainbow.burnTime = 150;
elements.rainbow.burnTempChange = 0.1;
elements.rainbow.reactions.bleach = { elem1: "pastel_rainbow" };
elements.rainbow.reactions.ink = { elem1: "dark_rainbow" };
elements.rainbow.reactions.coal = { elem1: "dark_rainbow" };
elements.rainbow.reactions.charcoal = { elem1: "dark_rainbow" };
elements.rainbow.reactions.coal_dust = { elem1: "dark_rainbow" };
elements.rainbow.reactions.malware = { elem1: "glitchy_rainbow" };
elements.rainbow.reactions.ruby = { elem1: "rubyshimmer" };
elements.rainbow.reactions.molten_ruby = { elem1: "rubyshimmer" };
elements.rainbow.reactions.garnet = { elem1: "rubyshimmer" };
elements.rainbow.reactions.molten_garnet = { elem1: "rubyshimmer" };
elements.rainbow.reactions.topaz = { elem1: "topazshimmer" };
elements.rainbow.reactions.bee = { elem1: "beeshimmer" };
elements.rainbow.reactions.sap = { elem1: "ambershimmer" };
elements.rainbow.reactions.amber = { elem1: "ambershimmer" };
elements.rainbow.reactions.emerald = { elem1: "emeraldshimmer" };
elements.rainbow.reactions.molten_emerald = { elem1: "emeraldshimmer" };
elements.rainbow.reactions.cold_fire = { elem1: "iceshimmer" };
elements.rainbow.reactions.sapphire = { elem1: "sapphireshimmer" };
elements.rainbow.reactions.molten_sapphire = { elem1: "sapphireshimmer" };
elements.rainbow.reactions.blue_dust = { elem1: "sapphireshimmer" };
elements.rainbow.reactions.amethyst = { elem1: "amethystshimmer" };
elements.rainbow.reactions.molten_amethyst = { elem1: "amethystshimmer" };
elements.rainbow.reactions.spinel = { elem1: "spinelshimmer" };
elements.rainbow.reactions.molten_spinel = { elem1: "spinelshimmer" };
elements.rainbow.reactions.mullite = { elem1: "mulliteshimmer" };
elements.rainbow.reactions.molten_mullite = { elem1: "mulliteshimmer" };
elements.rainbow.reactions.dantite = { elem1: "dantiteshimmer" };
elements.rainbow.reactions.molten_dantite = { elem1: "dantiteshimmer" };
elements.rainbow.reactions.turquoise_dust = { elem1: "turquoiseshimmer" };
elements.rainbow.reactions.diabaline = { elem1: "diabalineshimmer" };
elements.rainbow.reactions.gold_coin = { elem1: "goldshimmer" };
elements.rainbow.reactions.gold_scrap = { elem1: "goldshimmer" };
elements.rainbow.reactions.gold = { elem1: "goldshimmer" };
elements.rainbow.reactions.molten_gold = { elem1: "goldshimmer" };
elements.rainbow.reactions.onyx = { elem1: "onyxshimmer" };
elements.rainbow.reactions.opal = { elem1: "opalshimmer" };
elements.rainbow.reactions.jadeite = { elem1: "jadeshimmer" };
elements.rainbow.reactions.dirt = { elem1: "earthshimmer" };
elements.rainbow.reactions.lead_scrap = { elem1: "leadshimmer" };
elements.rainbow.reactions.lead = { elem1: "leadshimmer" };
elements.rainbow.reactions.molten_lead = { elem1: "leadshimmer" };
elements.rainbow.reactions.water = { elem1: "seashimmer" };
elements.rainbow.reactions.ultramafic_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.intermediate_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.intermediate_felsic_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.felsic_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.rainbow_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.nellish_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.crimson_magma = { elem1: "lavashimmer" };
elements.rainbow.reactions.uranium = { elem1: "radioshimmer" };
elements.rainbow.reactions.ash = { elem1: "ashenshimmer" };
elements.rainbow.reactions.steel_scrap = { elem1: "steelshimmer" };
elements.rainbow.reactions.molten_steel = { elem1: "steelshimmer" };
elements.rainbow.reactions.steel = { elem1: "steelshimmer" };
elements.rainbow.reactions.iron_scrap = { elem1: "steelshimmer" };
elements.rainbow.reactions.molten_iron = { elem1: "steelshimmer" };
elements.rainbow.reactions.iron = { elem1: "steelshimmer" };
elements.rainbow.reactions.smoke = { elem1: "smokeshimmer" };
elements.rainbow.reactions.smog = { elem1: "smokeshimmer" };
elements.rainbow.reactions.cloud = { elem1: "cloudshimmer" };
elements.rainbow.reactions.fog = { elem1: "cloudshimmer" };
elements.rainbow.reactions.steam = { elem1: "cloudshimmer" };
elements.rainbow.reactions.rain_cloud = { elem1: "cloudshimmer" };
elements.rainbow.reactions.snow_cloud = { elem1: "cloudshimmer" };
elements.rainbow.reactions.hail_cloud = { elem1: "cloudshimmer" };
elements.rainbow.reactions.thunder_cloud = { elem1: "cloudshimmer" };
elements.rainbow.reactions.fluorine = { elem1: "fluoroshimmer" };
elements.rainbow.reactions.liquid_fluorine = { elem1: "fluoroshimmer" };
elements.rainbow.reactions.fluorine_ice = { elem1: "fluoroshimmer" };
elements.rainbow.reactions.chlorine = { elem1: "chloroshimmer" };
elements.rainbow.reactions.liquid_chlorine = { elem1: "chloroshimmer" };
elements.rainbow.reactions.chlorine_ice = { elem1: "chloroshimmer" };
elements.rainbow.reactions.chlorine_snow = { elem1: "chloroshimmer" };
elements.rainbow.reactions.bromine = { elem1: "bromoshimmer" };
elements.rainbow.reactions.liquid_bromine = { elem1: "bromoshimmer" };
elements.rainbow.reactions.bromine_snow = { elem1: "bromoshimmer" };
elements.rainbow.reactions.bromine_ice = { elem1: "bromoshimmer" };
elements.rainbow.reactions.iodine = { elem1: "iodoshimmer" };
elements.rainbow.reactions.molten_iodine = { elem1: "iodoshimmer" };
elements.rainbow.reactions.iodine_gas = { elem1: "iodoshimmer" };
runAfterLoad(function() { elements.astatine.tempHigh = 302 });
elements.molten_astatine ??= {}; elements.molten_astatine.tempHigh = 337;
elements.rainbow.reactions.astatine = { elem1: "astatoshimmer" };
elements.rainbow.reactions.molten_astatine = { elem1: "astatoshimmer" };
elements.rainbow.reactions.astatine_gas = { elem1: "astatoshimmer" };
elements.rainbow.reactions.blood = { elem1: "bloodshimmer" };
elements.rainbow.reactions.blood_snow = { elem1: "bloodshimmer" };
elements.rainbow.reactions.blood_ice = { elem1: "bloodshimmer" };
elements.rainbow.reactions.salt = { elem1: "saltshimmer" };
elements.rainbow.reactions.molten_salt = { elem1: "saltshimmer" };
elements.rainbow.reactions.sand = { elem1: "sandshimmer" };
elements.rainbow.reactions.hot_sand = { elem1: "sandshimmer" };
elements.rainbow.reactions.sandy_water = { elem1: "sandshimmer" };
elements.rainbow.reactions.sand_sediment = { elem1: "sandshimmer" };
elements.rainbow.reactions.sandstone = { elem1: "sandshimmer" };
elements.rainbow.reactions.ichor = { elem1: "ichorshimmer" };
elements.rainbow.reactions.quark_matter = { elem1: "quarkshimmer" };
elements.rainbow.reactions.heejinite = { elem1: "heejinshimmer" };
elements.rainbow.reactions.heejinite_powder = { elem1: "heejinshimmer" };
elements.rainbow.reactions.molten_heejinite = { elem1: "heejinshimmer" };
elements.rainbow.reactions.heejinite_gas = { elem1: "heejinshimmer" };
/*elements.rainbow.reactions.dye = {
func: function(pixel,otherPixel) {
//The dye reactant is the otherPixel
//The rainbow is the pixel
if(
(typeof(otherPixel) == "undefined")
|| isEmpty(otherPixel.x,otherPixel.y,true)
|| typeof(pixelMap[otherPixel.x][otherPixel.y]) == "undefined"
|| !(currentPixels.includes(pixelMap[otherPixel.x][otherPixel.y]))
) { return };
var dyeColorHSL = colorToHsl(otherPixel.color,"json");
if(isRed(dyeColorHSL)) {
changePixel(pixel,"red_test");
} else if(isWhite(dyeColorHSL)) {
changePixel(pixel,"rainbow_alt_test");
};
return true
}
};*/
elements.rainbow.tick = function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks+pixel.x+pixel.y;
var r = Math.floor(127*(1-Math.cos(t*Math.PI/90)));
var g = Math.floor(127*(1-Math.cos(t*Math.PI/90+2*Math.PI/3)));
var b = Math.floor(127*(1-Math.cos(t*Math.PI/90+4*Math.PI/3)));
var baseColor = "rgb("+r+","+g+","+b+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//80% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.8);
//30% dye color, 70% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.7);
pixel.color = convertColorFormats(finalColor,"rgb")
}
};
elements.rainbow.state = "solid";
elements.rainbow.reactions.dye = {
func: function(pixel,otherPixel) {
//The dye reactant is the otherPixel
//The rainbow is the pixel
if(
(typeof(otherPixel) == "undefined")
|| isEmpty(otherPixel.x,otherPixel.y,true)
|| typeof(pixelMap[otherPixel.x][otherPixel.y]) == "undefined"
|| !(currentPixels.includes(pixelMap[otherPixel.x][otherPixel.y]))
) { return false };
if(pixel.dyeColor == otherPixel.color) {
return false
} else {
pixel.dyeColor = otherPixel.color;
return true
}
}
};
rainbowMathlet = function(t,scale,offset) { return Math.cos(t*Math.PI/scale+offset*Math.PI/3) };
elements.dark_rainbow = {
color: [_cc.b.h,"#ff0000",_cc.b.h,"#ff8800",_cc.b.h,"#ffff00",_cc.b.h,"#00ff00",_cc.b.h,"#00ffff",_cc.b.h,"#0000ff",_cc.b.h,"#ff00ff"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks+pixel.x+pixel.y;
var l = 50 * (Math.max(0,rainbowMathlet(t,17.1428571,0)) ** 4);
var h = (((t * 1.05) - 2) % 360);
var color = {h: h, s: 100, l: l};
var baseColor = convertHslObjects(color,"rgb");
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//80% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.8);
//30% dye color, 70% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.7);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.fireshimmer = {
color: ["#ff0000","#ff8800","#ffff00","#ff8800","#ff0000"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var g = Math.floor(127*((Math.max(0,1-(rainbowMathlet(t,25,0)))) ** 1.1));
baseColor = "rgb(255,"+g+",0)";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
category: "special",
reactions: {
dye: elements.rainbow.reactions.dye,
plasma: {elem1: "plasmashimmer", tempMin: 10000}
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
movable: false,
};
elements.plasmashimmer = {
color: ["#8800ff","#f2f2f2","#8800ff","#f2f2f2"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var value = Math.floor(127*((Math.max(0,1-(rainbowMathlet(t,25,0)))) ** 1.1));
baseColor = "rgb(" + [Math.round(127 + (value/2)), value, 255].join(",") + ")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
category: "special",
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
movable: false,
};
elements.glitchy_rainbow = {
color: ["#ff0000","#ff8800","#ffff00","#ff8800","#ff0000"],
tick: function(pixel) {
if(Math.random() < 0.25) { return };
var dyeColor = pixel.dyeColor ?? null;
var t = (
(Math.floor(pixelTicks / 3) * 3)
+ (Math.floor(pixel.x / 3) * 3)
+ pixel.y
+ (Math.floor(Math.random() * 5)-2)
);
var r = Math.floor(127*(1-Math.cos(t*Math.PI/90)));
var g = Math.floor(127*(1-Math.cos(t*Math.PI/90+2*Math.PI/3)));
var b = Math.floor(127*(1-Math.cos(t*Math.PI/90+4*Math.PI/3)));
var baseColor = Math.random() < 0.02 ? [g,r,b] : [r,g,b];
baseColor = "rgb("+baseColor.join(",")+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//80% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.8);
//30% dye color, 70% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.7);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
category: "special",
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
movable: false,
};
elements.rainbow.behavior = behaviors.WALL;
elements.dye.ignore ??= [];
elements.pastel_rainbow = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/240)));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/240+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/240+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye,
dust: { elem1: "pastel_rainbow_small", elem2: null },
flameshockwave4: { elem1: "pastel_rainbow_x", elem2: null }, //fs4 = left, fs5 = right
flameshockwave5: { elem1: "pastel_rainbow_x", elem2: null },
flameshockwave2: { elem1: "pastel_rainbow_y", elem2: null }, //fs2 = up, fs7 = down
flameshockwave7: { elem1: "pastel_rainbow_y", elem2: null },
flameshockwave1: { elem1: "pastel_rainbow_d", elem2: null }, //fs1 ul, fs3 ur, fs6 dl, fs8 dr
flameshockwave3: { elem1: "pastel_rainbow_d", elem2: null },
flameshockwave6: { elem1: "pastel_rainbow_d", elem2: null },
flameshockwave8: { elem1: "pastel_rainbow_d", elem2: null },
slime: { elem1: "pastel_rainbow_t_d_x", elem2: null },
feather: { elem1: "pastel_rainbow_t_d_y", elem2: null },
glue: { elem1: "pastel_rainbow_x_p_y", elem2: null },
plasma: { elem1: "pastel_rainbow_x_m_y", elem2: null },
liquid_light: { elem1: "pastel_rainbow_x_t_y", elem2: null },
tectonic_petrotheum: { elem1: "pastel_rainbow_x_d_y", elem2: null },
seed: { elem1: "pastel_rainbow_x_e_y", elem2: null },
dirt: { elem1: "pastel_rainbow_x_r_y", elem2: null },
sawdust: { elem1: "pastel_rainbow_x_l_y", elem2: null },
water: { elem1: "pastel_rainbow_s_x", elem2: null },
magma: { elem1: "pastel_rainbow_c_x", elem2: null },
gelid_cryotheum: { elem1: "pastel_rainbow_t_x", elem2: null },
steam: { elem1: "pastel_rainbow_sh_x", elem2: null },
vaporized_magma: { elem1: "pastel_rainbow_ch_x", elem2: null },
blazing_pyrotheum: { elem1: "pastel_rainbow_th_x", elem2: null },
rock: { elem1: "pastel_rainbow_sr_x", elem2: null },
polka_dotted_powder: { elem1: "pastel_rainbow_x_mod_y", elem2: null }
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.rubyshimmer = {
color: ["#ff0000","#200000","#ff0000","#200000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
pixel.color = "rgb("+Math.ceil((r*(7/8))+32)+","+0+","+0+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.garnetshimmer = {
color: ["#bf1f2f","#180406","#bf1f2f","#180406"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
r = (r*(7/8))+32;
pixel.color = "rgb("+Math.ceil(r * 0.65)+","+Math.ceil(r * 0.1)+","+Math.ceil(r * 0.15)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.topazshimmer = {
color: ["#ffff00","#202000","#ffff00","#202000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+value+",0)";
doHeat(pixel);
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.beeshimmer = {
color: ["#ffff00","#202000","#ffff00","#202000","#ffff00","#202000","#ffff00","#202000"],
tick: function(pixel) {
var t = pixelTicks*1.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/4)));
var value = Math.ceil(r/2);
pixel.color = "rgb("+value+","+value+",0)";
doHeat(pixel);
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.ambershimmer = {
color: ["#ff7f00","#201000","#ff7f00","#201000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+Math.round(value*0.5)+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.emeraldshimmer = {
color: ["#00ff00","#002000","#00ff00","#002000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb(0,"+value+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.iceshimmer = {
color: ["#00ffff","#001520","#00ffff","#001520"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb(0,"+Math.round(value * 0.75)+","+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.sapphireshimmer = {
color: ["#0000ff","#000020","#0000ff","#000020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb(0,0,"+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.amethystshimmer = {
color: ["#7f00ff","#100020","#7f00ff","#100020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value/2)+",0,"+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.spinelshimmer = {
color: ["#ff00ff","#200020","#ff00ff","#200020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+",0,"+Math.round(value * 0.5)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.mulliteshimmer = {
color: ["#f8eeff","#151020","#f8eeff","#151020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var l = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((l*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.9)+","+Math.round(value * 0.75)+","+Math.round(value*0.85)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.dantiteshimmer = {
color: ["#00ff7f","#002010","#00ff7f","#002010"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var l = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((l*(7/8))+32);
pixel.color = "rgb(0,"+value+","+Math.round(value*0.5)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
nellfireImmune: true
};
elements.turquoiseshimmer = {
color: ["#00ffff","#002020","#00ffff","#002020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var l = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((l*(7/8))+32);
pixel.color = "rgb(0,"+value+","+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
nellfireImmune: true
};
elements.diabalineshimmer = {
color: ["#af7fcf","#141018","#af7fcf","#141018"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.625)+","+Math.round(value*0.5)+","+Math.round(value*0.75)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.goldshimmer = {
color: ["#ffcf00","#201800","#ffcf00","#201800"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+Math.round(value*0.75)+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.leadshimmer = {
color: ["#2f2f4f","#040410","#2f2f4f","#040410"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.3)+","+Math.round(value*0.3)+","+Math.round(value*0.5)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.onyxshimmer = {
color: ["#1f1f1f","#040404","#1f1f1f","#040404"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+16);
pixel.color = "rgb("+Math.round(value*0.125)+","+Math.round(value*0.125)+","+Math.round(value*0.125)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.opalshimmer = {
color: function() { var rc = elements.rainbow.color; var rc2 = rc.map(x => lightenColor(x,127,"hex")); return rc2.concat(rc2) }(),
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t1 = pixelTicks+pixel.x+pixel.y;
var t2 = pixelTicks+pixel.x-pixel.y;
var scale = 20;
var r1 = Math.floor(127*(1-Math.cos(t1*Math.PI/scale)));
var g1 = Math.floor(127*(1-Math.cos(t1*Math.PI/scale+2*Math.PI/3)));
var b1 = Math.floor(127*(1-Math.cos(t1*Math.PI/scale+4*Math.PI/3)));
var r2 = Math.floor(127*(1-Math.cos(t2*Math.PI/scale)));
var g2 = Math.floor(127*(1-Math.cos(t2*Math.PI/scale+2*Math.PI/3)));
var b2 = Math.floor(127*(1-Math.cos(t2*Math.PI/scale+4*Math.PI/3)));
var r3 = (r1+r2)*0.75;
var g3 = (g1+g2)*0.75;
var b3 = (b1+b2)*0.75;
var baseColor = {r: r3, g: g3, b: b3};
baseColor = averageColorObjects(baseColor,_cc.w.j,0.8);
baseColor = convertColorFormats(baseColor,"rgb");
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//80% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.8);
//30% dye color, 70% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.7);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye,
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.jadeshimmer = {
color: ["#5f8f2f","#0c1206","#5f8f2f","#0c1206"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
pixel.color = "rgb("+Math.ceil((r*(4/16))+32)+","+Math.ceil((r*(8/16))+32)+","+Math.ceil((r*(1/8))+32)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.earthshimmer = {
color: ["#5f3f00","#0c0800","#5f3f00","#0c0800"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.375)+","+Math.round(value*0.2)+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.seashimmer = {
color: ["#007fff","#001020","#007fff","#001020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb(0,"+Math.round(value*0.5)+","+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.lavashimmer = {
color: ["#ff3f00","#200800","#ff3f00","#200800"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+Math.round(value*0.25)+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.radioshimmer = { //if it captures and renders harmless fire+crimmagma+lava then it can provide radiation shielding
color: ["#7fff00","#102000","#7fff00","#102000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.5)+","+value+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.ashenshimmer = {
color: ["#cfcfcf","#181818","#cfcfcf","#181818"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.75)+","+Math.round(value*0.75)+","+Math.round(value*0.75)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.steelshimmer = {
color: ["#7f7f7f","#101010","#7f7f7f","#101010"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.5)+","+Math.round(value*0.5)+","+Math.round(value*0.5)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.smokeshimmer = {
color: ["#3f3f3f","#050505","#3f3f3f","#050505"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.25)+","+Math.round(value*0.25)+","+Math.round(value*0.25)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.cloudshimmer = {
color: ["#dfefff","#1d1e20","#dfefff","#1d1e20"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+48);
pixel.color = "rgb("+Math.round(value*0.8)+","+Math.round(value*0.9)+","+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.fluoroshimmer = {
color: ["#5f6f2f","#081000","#5f6f2f","#081000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.375)+","+Math.round(value*0.4375)+","+Math.round(value*0.1875)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.chloroshimmer = {
color: ["#3f7f00","#081000","#3f7f00","#081000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.25)+","+Math.round(value*0.5)+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.bromoshimmer = {
color: ["#7f1f00","#100400","#7f1f00","#100400"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.5)+","+Math.round(value*0.125)+",0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.iodoshimmer = {
color: ["#5f007f","#0c0010","#5f007f","#0c0010"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.375)+",0,"+Math.round(value*0.5)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.astatoshimmer = {
color: ["#230f27","#050205","#230f27","#050205"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.137)+","+Math.round(value*0.059)+","+Math.round(value*0.153)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.bloodshimmer = {
color: ["#7f0000","#100000","#7f0000","#100000"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+Math.round(value*0.4)+",0,0)";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.saltshimmer = {
color: [_cc.w.h,"#202020",_cc.w.h,"#202020"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+value+","+value+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.sandshimmer = {
color: ["#ffdf7f","#201d10","#ffdf7f","#201d10"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+Math.round(value*0.8)+","+Math.round(value*0.5)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.ichorshimmer = {
color: ["#ffbf5f","#201804","#ffbf5f","#201804"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
var value = Math.ceil((r*(7/8))+32);
pixel.color = "rgb("+value+","+Math.round(value*0.75)+","+Math.round(value*0.375)+")";
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.quarkshimmer = {
color: ["#ff0000","#00ff00","#0000ff","#ff0000","#00ff00","#0000ff"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(127*(((Math.max(0,1-(rainbowMathlet(t,20,0))) / 1.575) ** 5) * 1.575));
var g = Math.floor(127*(((Math.max(0,1-(rainbowMathlet(t,20,2))) / 1.575) ** 5) * 1.575));
var b = Math.floor(127*(((Math.max(0,1-(rainbowMathlet(t,20,4))) / 1.575) ** 5) * 1.575));
baseColor = "rgb("+([r,g,b].join(","))+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
category: "special",
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
movable: false,
};
elements.heejinshimmer = {
color: ["#ff007f","#200010","#ff007f","#200010"],
tick: function(pixel) {
var t = pixelTicks*2.5+pixel.x+pixel.y;
var t2 = pixelTicks/2;
//var r = Math.floor(255*(1-Math.cos(t*Math.PI/24)));
//var value = Math.ceil((r*(7/8))+32);
var l = Math.floor(40*(1-Math.cos(t*Math.PI/24)));
var h = (320 + Math.floor(30*(Math.cos(t2*Math.PI/24)))) % 360;
//pixel.color = "rgb("+value+",0,"+Math.round(value * 0.5)+")";
pixel.color = convertHslObjects({h:h,s:100,l:l},"rgb");
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants",
};
elements.pastel_rainbow_small = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/60)));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/60+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/60+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_t_d_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (time/x)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixelTicks/pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixelTicks/pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixelTicks/pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_t_d_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (time/y)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixelTicks/pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixelTicks/pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixelTicks/pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
behavior: behaviors.WALL,
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x distance)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/pixel.x)));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/pixel.x+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/pixel.x+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye,
polka_dotted_powder: { elem1: "pastel_rainbow_d_mod_x", elem2: null }
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (y distance)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/pixel.y)));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/pixel.y+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/pixel.y+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye,
polka_dotted_powder: { elem1: "pastel_rainbow_d_mod_y", elem2: null }
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_d = {
name: "pastel rainbow (diagonal distance)",
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2)))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye,
plasma: { elem1: "pastel_rainbow_d_m_x", elem2: null },
liquid_light: { elem1: "pastel_rainbow_d_t_x", elem2: null }
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_p_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x+y)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x+pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x+pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x+pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_m_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x-y)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x-pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x-pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x-pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_t_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x*y)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x*pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x*pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x*pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_d_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x/y)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x/pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x/pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x/pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye,
flameshockwave1: { elem1: "pastel_rainbow_x_d_d", elem2: null },
flameshockwave3: { elem1: "pastel_rainbow_x_d_d", elem2: null },
flameshockwave6: { elem1: "pastel_rainbow_x_d_d", elem2: null },
flameshockwave8: { elem1: "pastel_rainbow_x_d_d", elem2: null }
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_e_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x^y)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x**pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x**pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x**pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_r_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (ʸ√x)",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.pow(pixel.x, 1/pixel.y)))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.pow(pixel.x, 1/pixel.y))+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.pow(pixel.x, 1/pixel.y))+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_l_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (logᵧ(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.log(pixel.x) / Math.log(pixel.y)))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.log(pixel.x) / Math.log(pixel.y))+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.log(pixel.x) / Math.log(pixel.y))+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_s_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (sin(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sin(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sin(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sin(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_c_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (cos(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.cos(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.cos(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.cos(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_t_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (tan(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.tan(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.tan(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.tan(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_sh_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (sinh(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sinh(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sinh(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sinh(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_ch_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (cosh(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.cosh(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.cosh(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.cosh(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_th_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (tanh(x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.tanh(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.tanh(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.tanh(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_sr_x = {
name: "pastel rainbow (√x))",
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sqrt(pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sqrt(pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/Math.sqrt(pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_d_m_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (diagonal distance - x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))-pixel.x)));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))-pixel.x+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))-pixel.x+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_d_t_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (diagonal distance * x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))*pixel.x)));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))*pixel.x+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(Math.sqrt(pixel.x**2+pixel.y**2))*pixel.x+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_d_d = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x / diagonal distance))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x/(Math.sqrt(pixel.x**2+pixel.y**2))))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x/(Math.sqrt(pixel.x**2+pixel.y**2)))+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x/(Math.sqrt(pixel.x**2+pixel.y**2)))+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_x_mod_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (x % y))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x%pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x%pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/(pixel.x%pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_d_mod_x = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (diagonal distance modulo x))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/((Math.sqrt(pixel.x**2+pixel.y**2))%pixel.x))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/((Math.sqrt(pixel.x**2+pixel.y**2))%pixel.x)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/((Math.sqrt(pixel.x**2+pixel.y**2))%pixel.x)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
elements.pastel_rainbow_d_mod_y = {
color: ["#ffaacc","#ffaacc","#aaccff","#aaccff","#ffffbb","#ffffbb"],
name: "pastel rainbow (diagonal distance modulo y))",
tick: function(pixel) {
var dyeColor = pixel.dyeColor ?? null;
var t = pixelTicks*3+pixel.x+pixel.y;
var r = Math.floor(255*(1-Math.cos(t*Math.PI/((Math.sqrt(pixel.x**2+pixel.y**2))%pixel.y))));
var g = Math.floor(255*(1-Math.cos(t*Math.PI/((Math.sqrt(pixel.x**2+pixel.y**2))%pixel.y)+2*Math.PI/3)));
var b = Math.floor(255*(1-Math.cos(t*Math.PI/((Math.sqrt(pixel.x**2+pixel.y**2))%pixel.y)+4*Math.PI/3)));
var baseColor = "rgb("+Math.ceil((r/2)+127)+","+Math.ceil((g/2)+127)+","+Math.ceil((b/2)+127)+")";
if(!dyeColor) {
pixel.color = baseColor
} else {
var baseJSON = convertColorFormats(baseColor,"json");
var dyeJSON = convertColorFormats(dyeColor,"json");
var dyedColor = multiplyColors(dyeJSON,baseJSON,"json");
//70% multiplied
var semiDyedColor = averageColorObjects(dyedColor,baseJSON,0.7);
//35% dye color, 65% result
var finalColor = averageColorObjects(semiDyedColor,dyeJSON,0.65);
pixel.color = convertColorFormats(finalColor,"rgb")
}
},
reactions: {
dye: elements.rainbow.reactions.dye
},
state: "solid",
category: "rainbow variants"
};
//ASSORTED RANDOMLY GENERATED MATERIALS ##
elements.fowtim_ice = {
color: "#6c6dec",
behavior: behaviors.WALL,
tempHigh: 9382.73,
temp: 9362.73,
stateHigh: "fowtim",
category: "random solids",
state: "solid",
density: 1009.20,
hardness: 0.54,
breakInto: "fowtim",
conduct: 0.14,
};
elements.fowtim = {
color: "#2324e2",
behavior: behaviors.LIQUID,
tempLow: 9382.73,
temp: 9402.73,
tempHigh: 11187.06,
stateLow: "fowtim_ice",
stateHigh: "fowtim_gas",
category: "random liquids",
state: "liquid",
density: 905.92,
hardness: 0.27,
viscosity: 547.09,
breakInto: "fowtim_gas",
conduct: 0.078,
};
elements.fowtim_gas = {
color: "#b6b6f5",
behavior: behaviors.GAS,
tempLow: 11187.06,
temp: 11207.06,
stateLow: "fowtim",
category: "random gases",
state: "gas",
density: 1.36,
hardness: 1,
};
elements.shit = {
color: ["#756674","#554754","#827381"],
behavior: behaviors.POWDER,
tempHigh: 975.54,
category: "random rocks",
state: "solid",
density: 2902.23,
hardness: 0.45,
breakInto: ["dust","shit_gravel"],
stateHigh: "molten_shit"
};
elements.shit_gravel = {
color: ["#b9a9b5","#97858d","#6e6068","#57454e"],
behavior: behaviors.POWDER,
tempHigh: 975.54,
stateHigh: "shit",
category: "random rocks",
state: "solid",
density: 1912.06,
hardness: 0.19,
breakInto: "dust",
};
elements.loona = {
color: ["#6f7d54","#4f5d34","#7c8a61"],
behavior: behaviors.POWDER,
tempHigh: 1031.02,
category: "random rocks",
state: "solid",
density: 2466.73,
hardness: 0.51,
breakInto: ["dust","loona_gravel"],
stateHigh: "molten_loona"
},
elements.loona_gravel = {
color: ["#b3be98","#919a6f","#68744b","#515931"],
behavior: behaviors.POWDER,
tempHigh: 1031.02,
stateHigh: "loona",
category: "random rocks",
state: "solid",
density: 1625.14,
hardness: 0.20,
breakInto: "dust",
};
//ROSEYIEDE ##
elements.roseyiede = {
color: "#686118",
behavior: behaviors.LIQUID,
tempHigh: 103,
stateHigh: "gaseous_roseyiede",
tempLow: -8,
stateLow: "solid_roseyiede",
category: "liquids",
state: "liquid",
density: 1000,
},
elements.gaseous_roseyiede = {
color: "#a49e4c",
behavior: behaviors.GAS,
tempLow: -8,
stateLow: "powdered_roseyiede",
tick: function(pixel) {
if((pixelTicks - pixel.start) % 5 == 0) {
if(pixel.temp < 3 && Math.random() < 0.00135) {
changePixel(pixel,"roseyiede",false);
} else if(pixel.temp < 23 && Math.random() < 0.001) {
changePixel(pixel,"roseyiede",false);
} else if(pixel.temp < 43 && Math.random() < 0.0007) {
changePixel(pixel,"roseyiede",false);
} else if(pixel.temp < 63 && Math.random() < 0.00045) {
changePixel(pixel,"roseyiede",false);
} else if(pixel.temp < 83 && Math.random() < 0.00025) {
changePixel(pixel,"roseyiede",false);
} else if(pixel.temp < 103 && Math.random() < 0.0001) {
changePixel(pixel,"roseyiede",false);
}
};
},
category: "gases",
state: "gas",
density: 0.63,
temp: 120,
},
elements.solid_roseyiede = {
color: "#685e10",
behavior: behaviors.WALL,
tempHigh: 103,
stateHigh: "gaseous_roseyiede",
category: "solids",
state: "solid",
density: 1121,
hardness: 0.121,
breakInto: "powdered_roseyiede",
temp: -20,
},
elements.powdered_roseyiede = {
color: "#6c641c",
behavior: behaviors.POWDER,
tempHigh: -8,
stateHigh: "roseyiede",
category: "powders",
state: "solid",
density: 182,
temp: -20,
}
console.log("1/4 loaded")
//Volatile Roseyiede
elements.explosive_roseyiede = {
color: "#986118",
behavior: behaviors.LIQUID,
tempHigh: 98,
stateHigh: "gaseous_explosive_roseyiede",
tempLow: -6,
stateLow: "solid_explosive_roseyiede",
burn: 11,
burnInto: ["explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","explosive_roseyiede","fire","fire","fire","fire","fire","fire","fire","fire","fire","explosion"],
burnTime: 312,
tick: function(pixel) {
if((pixelTicks - pixel.start) % 5 == 0) {
if(pixel.temp < 3 && Math.random() < 0.0001) {
changePixel(pixel,"explosive_roseyiede_vapor",false)
} else if(pixel.temp < 23 && Math.random() < 0.0002) {
changePixel(pixel,"explosive_roseyiede_vapor",false)
} else if(pixel.temp < 43 && Math.random() < 0.0035) {
changePixel(pixel,"explosive_roseyiede_vapor",false)
} else if(pixel.temp < 63 && Math.random() < 0.00055) {
changePixel(pixel,"explosive_roseyiede_vapor",false)
} else if(pixel.temp < 83 && Math.random() < 0.0008) {
changePixel(pixel,"explosive_roseyiede_vapor",false)
} else if(pixel.temp < 98 && Math.random() < 0.0011) {
changePixel(pixel,"explosive_roseyiede_vapor",false)
}
}
},
category: "liquids",
state: "liquid",
density: 1000,
},
elements.gaseous_explosive_roseyiede = {
color: "#c89e4c",
behavior: behaviors.GAS,
tempLow: -6,
stateLow: "powdered_explosive_roseyiede",
burn: 88,
burnInto: ["gaseous_explosive_roseyiede","gaseous_explosive_roseyiede","gaseous_explosive_roseyiede","gaseous_explosive_roseyiede","gaseous_explosive_roseyiede","explosion","fire","fire","fire","fire","fire","fire","fire","fire","gaseous_explosive_roseyiede","explosion","fire","fire","fire","explosion"],
burnTime: 48,
tick: function(pixel) {
if((pixelTicks - pixel.start) % 5 == 0) {
if(pixel.temp < 3 && Math.random() < 0.00135) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 23 && Math.random() < 0.001) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 43 && Math.random() < 0.0007) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 63 && Math.random() < 0.00045) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 83 && Math.random() < 0.00025) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 98 && Math.random() < 0.0001) {
changePixel(pixel,"explosive_roseyiede",false);
}
}
},
category: "gases",
state: "gas",
density: 0.63,
temp: 120,
},
elements.explosive_roseyiede_vapor = {
color: "#c89449",
behavior: behaviors.GAS,
tempHigh: 98,
stateHigh: "gaseous_explosive_roseyiede",
tempLow: -6,
stateLow: "powdered_explosive_roseyiede",
burn: 88,
burnInto: ["explosive_roseyiede_vapor","explosive_roseyiede_vapor","explosive_roseyiede_vapor","explosive_roseyiede_vapor","explosive_roseyiede_vapor","explosion","fire","fire","fire","fire","fire","fire","fire","fire","explosive_roseyiede_vapor","fire","fire","fire","fire","explosion"],
burnTime: 48,
tick: function(pixel) {
if((pixelTicks - pixel.start) % 5 == 0) {
if(pixel.temp < 3 && Math.random() < 0.0011) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 23 && Math.random() < 0.0008) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 43 && Math.random() < 0.00055) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 63 && Math.random() < 0.00035) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 83 && Math.random() < 0.0002) {
changePixel(pixel,"explosive_roseyiede",false);
} else if(pixel.temp < 98 && Math.random() < 0.0001) {
changePixel(pixel,"explosive_roseyiede",false);
}
}
},
category: "gases",
state: "gas",
density: 0.63,
temp: 40,
},
elements.solid_explosive_roseyiede = {
color: "#985e10",
behavior: behaviors.WALL,
tempHigh: 98,
stateHigh: "gaseous_explosive_roseyiede",
burn: 4,
burnInto: ["solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","solid_explosive_roseyiede","fire","fire","fire","fire","fire","fire","fire","fire","fire","explosion"],
burnTime: 662,
category: "solids",
state: "solid",
density: 1121,
hardness: 0.121,
breakInto: "powdered_explosive_roseyiede",
temp: -20,
},
elements.powdered_explosive_roseyiede = {
color: "#98641c",
behavior: behaviors.POWDER,
tempHigh: -6,
stateHigh: "explosive_roseyiede",
burn: 42,
burnInto: ["powdered_explosive_roseyiede","powdered_explosive_roseyiede","powdered_explosive_roseyiede","powdered_explosive_roseyiede","powdered_explosive_roseyiede","powdered_explosive_roseyiede","powdered_explosive_roseyiede","powdered_explosive_roseyiede","fire","fire","explosion","fire","fire","fire","fire","fire","fire","fire","fire","explosion"],
burnTime: 101,
category: "powders",
state: "solid",
density: 182,
temp: -20,
},
elements.boiling_roseyiede = {
name: "forever- boiling roseyiede",
color: "#9e942e",
behavior: [
"XX|M2%5 AND CR:gaseous_roseyiede%0|XX", //display CR
"M2|HT:0|M2", //display HT
"M1|M1|M1",
],
reactions: {
"roseyiede": { elem2: "boiling_roseyiede", chance: 0.006 }
},
tick: function(pixel) {
if((pixelTicks - pixel.start) % 3 == 0) {
if(pixel.temp > (-206/3)) {
if(Math.random() < (pixel.temp - 103) / (51500/3) + 0.01) {
tryCreatePixel("gaseous_roseyiede",pixel.x,pixel.y-1)
};
} else if(pixel.temp < 103) {
pixel.temp += (((pixel.temp - 103) / 100) ** 2) / 2 + 1;
}
};
},
category: "liquids",
state: "liquid",
density: 956,
temp: 120,
}
//MINESWEEPER ##
msColorArray = ["#a0a0a0", "#0000ff", "#008000", "#ff0000", "#000080", "#800000", "#008080", _cc.b.h, "#808080"]
elements.msfield = {
name: "minefield",
color: "#c0c0c0",
conduct: 1,
insulate: true,
properties: {
uwu: 0,
revealed: false,
revealedAround: false
},
tick: function(pixel) {
pixel.revealed ??= false;
pixel.uwu ??= 0;
pixel.revealedAround ??= false;
if(pixel.charge) {
if(!pixel.revealed) { pixel.revealed = true };
delete pixel.charge
if(pixel.chargeCD) {
delete pixel.chargeCD
}
}
if(pixel.revealed) {
//count neighbors
pixel.uwu = 0
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == "msmine") {
pixel.uwu++
}
}
}
}
if(typeof(pixel.uwu) === 'number' && isFinite(pixel.uwu) && !isNaN(pixel.uwu)) {
if(pixel.uwu >= 0 && pixel.uwu <= 8) {
pixel.color = msColorArray[pixel.uwu];
pixel.displayText = pixel.uwu.toString()
}
} else {
pixel.color = "#ff00ff"
}
} else {
pixel.color = "#c0c0c0" //I feel bad suppressing the sand effect.
}
},
grain: 0,
category: "special",
state: "solid",
hidden: true,
};
elements.msmine = {
name: "minefield",
color: "#c0c0c0",
conduct: 1,
insulate: true,
properties: {
uwu: 0,
revealed: false
},
tick: function(pixel) {
if(pixel.charge) {
pixel.revealed = true
delete pixel.charge
if(pixel.chargeCD) {
delete pixel.chargeCD
}
}
if(pixel.revealed) {
pixel.color = ("#" + ((192 + Math.abs((pixelTicks * 4) % 64)).toString(16) + "c0c0").padStart(6, '0'));
//oldFillStyle = ctx.fillStyle
//ctx.fillStyle = "#ff0000";
////ctx.fillRect(pixel.x*pixelSize, pixel.y*pixelSize, pixelSize/2, pixelSize);
//ctx.fillRect(23*pixelSize, 23*pixelSize, pixelSize/2, pixelSize);
//ctx.fillStyle = oldFillStyle;
} else {
pixel.color = "#c0c0c0"
}
},
category: "special",
state: "solid",
hidden: true,
};
elements.ms = { //minesweeper = {
color: ["#c0c0c0", "#c0c0c0", "#ff0000", "#008000", "#ff0000", "#000080", "#800000", "#008080", _cc.b.h, "#808080", "#808080"],
behavior: [
"XX|XX|XX",
"XX|CH:msfield,msfield,msfield,msfield,msfield,msfield,msfield,msfield,msfield,msmine|XX",
"XX|XX|XX"
],
category: "special",
state: "solid",
};
//LIFE-EATER VIRUS ##
var lifeEaterCategories = ["life","auto creepers","shit","cum","food","fantastic creatures","fey","auto fey"];
var lifeEaterBlacklist = ["life_eater_virus","life_eater_slurry","life_eater_infected_dirt"];
var lifeEaterWhitelist = ["blood","skin","hair","poop","blood_ice","wood","wood_plank","sawdust","straw","paper","birthpool","dried_poop","gloomfly","meat_monster","rotten_ravager","bone_beast","withery","withery_plant","banana","apple","rotten_apple","apioform_player","apioform_bee","apioform","apiodiagoform","sugar_cactus","sugar_cactus_seed","flowering_sugar_cactus","tree_branch","sap","silk","red_velvet","silk_velvet","ketchup", "enchanted_ketchup", "frozen_ketchup", "poisoned_ketchup", "frozen_poisoned_ketchup", "ketchup_spout", "ketchup_cloud", "poisoned_ketchup_cloud", "ketchup_snow", "ketchup_snow_cloud", "poisoned_ketchup_snow", "poisoned_ketchup_snow_cloud", "ketchup_gas", "poisoned_ketchup_gas", "ketchup_powder", "poisoned_ketchup_powder", "eketchup_spout", "ketchup_metal", "antiketchup", "dirty_ketchup", "ketchup_gold", "molten_ketchup_metal", "ketchup_fairy", "ketchup_metal_scrap", "ketchup_gold_scrap", "molten_ketchup_gold", "mycelium","vaccine","antibody","infection","sap","caramel","molasses","melted_chocolate","soda","mustard","fry_sauce","tomato_sauce","sugary_tomato_sauce","bio_ooze","zombie_blood","feather","tooth","decayed_tooth","plaque","tartar","bacteria","replacer_bacteria","pop_rocks"];
var lifeEaterSubstitutions = {
"dirt": "life_eater_infected_dirt",
"crimsoil": "life_eater_infected_dirt",
"rainbow_dirt": "life_eater_infected_dirt"
};
function tryCreatePlus(element,centerX,centerY) {
var plusCoords = adjacentCoords.concat([[0,0]]);
var pixels = 0;
for(let i = 0; i < plusCoords.length; i++) {
var newX = centerX + plusCoords[i][0];
var newY = centerY + plusCoords[i][1];
if(isEmpty(newX,newY)) {
while(element instanceof Array) { element = element[Math.floor(Math.random() * element.length)] };
createPixel(element,newX,newY);
pixels++;
};
};
return pixels;
};
function spreadLifeEater(pixel) {
var convertedPixels = [];
for(i = 0; i < adjacentCoords.length; i++) { //iterate through neighbor spots
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) { //check for adjacentCoords
var newPixel = pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]]
var isLifeEaterFairy = (elements[newPixel.element].category == "auto fey" && newPixel.element.includes("life_eater_"))
//console.log(newPixel.element,isLifeEaterFairy);
if(
(lifeEaterCategories.includes(elements[newPixel.element].category) || lifeEaterWhitelist.includes(newPixel.element) || Object.keys(lifeEaterSubstitutions).includes(newPixel.element)) &&
!lifeEaterBlacklist.includes(newPixel.element) &&
!isLifeEaterFairy //exclude fairies which produce life eater
) {
if(Object.keys(lifeEaterSubstitutions).includes(newPixel.element)) {
var data = lifeEaterSubstitutions[newPixel.element];
while(data instanceof Array) {
data = data[Math.floor(Math.random() * data.length)];
};
if(data === null) {
if(newPixel) { deletePixel(newPixel.x,newPixel.y) };
} else {
changePixel(newPixel,data);
convertedPixels.push(newPixel);
};
} else {
changePixel(newPixel,"life_eater_slurry");
convertedPixels.push(newPixel);
};
};
};
};
return convertedPixels;
};
elements.life_eater_explosion = {
color: ["#96c785","#f0d654","#ffb47a"],
behavior: [
"XX|XX|XX",
"XX|EX:9>plasma,fire,life_eater_virus|XX",
"XX|XX|XX",
],
temp: 1600,
category: "energy",
state: "gas",
density: 1000,
excludeRandom: true,
hidden: true,
},
elements.life_eater_virus = {
color: ["#7bb064", "#aabd60", "#9e9e29"],
behavior: behaviors.GAS,
tick: function(pixel) {
spreadLifeEater(pixel).forEach(infectedPixel => spreadLifeEater(infectedPixel));
},
category: "life",
state: "gas",
density: airDensity,
excludeRandom: true,
tempHigh: 300,
stateHigh: null,
};
elements.life_eater_slurry = {
color: ["#3d6e29", "#666617", "#7d5716"],
behavior: behaviors.LIQUID,
properties: {
methaned: false
},
tick: function(pixel) {
spreadLifeEater(pixel).forEach(infectedPixel => spreadLifeEater(infectedPixel));
if(pixelTicks - pixel.start > 6) {
if(!pixel.methaned && Math.random() < 0.2) {
changePixel(pixel,Math.random() < 0.2 ? "life_eater_virus" : "methane");
} else {
pixel.methaned = true;
};
tryCreatePlus(["methane","methane","methane","methane","life_eater_virus"],pixel.x,pixel.y);
return;
};
},
category: "life",
state: "liquid",
density: 1050,
burn: 100,
burnTime: 10,
fireSpawnTemp: 1500,
burnTempChange: 200,
burnInto: ["life_eater_virus","plasma","fire","life_eater_explosion"],
excludeRandom: true,
};
var crRule50 = "CR:life_eater_virus,methane,methane,methane%0.5";
var crRule100 = "CR:life_eater_virus,methane,methane,methane%1";
elements.life_eater_infected_dirt = {
behavior: [
"XX|"+crRule100+"|XX",
crRule50+"|XX|"+crRule50,
"M2|M1 AND "+crRule50+"|M2",
],
color: ["#757137","#617a35","#66622c","#707538"],
tick: function(pixel) {
spreadLifeEater(pixel).forEach(infectedPixel => spreadLifeEater(infectedPixel));
},
category: "life",
state: "liquid",
density: 1050,
burn: 70,
burnTime: 15,
fireSpawnTemp: 1400,
burnTempChange: 180,
burnInto: ["life_eater_virus","fire","plasma","life_eater_explosion"],
excludeRandom: true,
};
for(i = 0; i < 4; i++) {
elements.life_eater_infected_dirt.burnInto.push(elements.dry_dirt ? "dry_dirt" : "sand");
};
elements.virus_bomb = {
color: "#accc70",
behavior: [
"XX|EX:16>life_eater_virus|XX",
"XX|XX|XX",
"XX|EX:16>life_eater_virus AND M1|XX"
],
density: 3500,
hardness: 0.95,
breakInto: "life_eater_virus",
tempHigh: 2400,
category: "weapons",
excludeRandom: true,
stateHigh: ["molten_iron","molten_aluminum","molten_tin","life_eater_virus","life_eater_virus","life_eater_virus"]
};
//PLANET CRACKER ##
function planetCrackerHeat(pixel,x,y,radius,fire,smoke,power,damage) {
//console.log(`Radius: ${radius}\nPower: ${power}\nPixel: (${pixel.x},${pixel.y})\nDamage: ${damage}`);
//console.log(`Expected temperature increase for pixel at (${pixel.x},${pixel.y}): ${800 * ((1 + (7 * damage)) ** 2) * ((power ** 2) * 1.5)}`);
var reversedCloseness = ((radius / 6) ** 0.5) - 1; //mathematically inaccurate but properly correlated
pixel.temp += 500 * ((reversedCloseness * 2) + 1);
if(pixel.vx) {
pixel.vx *= 2;
};
if(pixel.vy) {
pixel.vy *= 2;
};
};
function planetCrackerFinale(doColorChange=true,spawnElements=null) {
var bottomFortyPercent = Math.round(height * 0.6);
var bottomTwentyPercent = Math.round(height * 0.8);
var bottomTenPercent = Math.round(height * 0.9);
if(typeof(spawnElements) == "string") {
if(spawnElements.indexOf(",") >= 0) {
spawnElements = spawnElements.split(",")
} else { spawnElements = [spawnElements] };
};
if(Array.isArray(spawnElements)) {
spawnElements = spawnElements.filter(n => elementExists(n));
if(spawnElements.length == 0) {
spawnElements = null
}
};
var doSpawning = (spawnElements !== null);
for(x = 1; x < width; x++) {
for(y = bottomFortyPercent; y < height; y++) {
var chance = y > bottomTwentyPercent ? 0.03 : 0.01
var radius = y > bottomTwentyPercent ? 8 : 6
var newPixel = pixelMap[x]?.[y];
if(doSpawning && y > bottomTenPercent && isEmpty(x,y,false) && (Math.random() < 0.6)) {
var _np = tryCreatePixelReturn(randomChoice(spawnElements),x,y);
if(_np) { newPixel = _np }
};
if(newPixel) {
newPixel.vy ??= 0;
newPixel.vy -= 20;
};
if(newPixel && y > bottomTenPercent) {
newPixel.temp += 2000;
pixelTempCheck(newPixel)
};
if(Math.random() < chance) {
explodeAt(x,y,radius,spawnElements ? ((",plasma".repeat(spawnElements.length * 14).replace(",","")) + "," + spawnElements.join(",")) : "plasma");
};
};
};
if(doColorChange) {
settings.bg = [_cc.b.h,_cc.b.h,_cc.b.h,_cc.b.h,"#29180e","#663814","#9e6f19","#f7af2a"];
settings.bgAngle = 90;
};
};
elements.planet_cracker = {
color: "#ffc8ba",
excludeRandom: true,
behavior: behaviors.WALL,
properties: {
active: true,
counter: 1,
},
tick: function(pixel) {
if(!pixel?.active) {
return;
};
if(outOfBounds(pixel.x,pixel.y+pixel.counter)) {
planetCrackerFinale(true,pixel._bottomStateHighCache ?? null);
pixel.active = false;
changePixel(pixel,"metal_scrap");
};
if(pixel.active) {
pixel._bottomStateHighCache ??= [];
pixel._bottomStateHighCache = currentPixels.filter(p => p.y == height - 1).map(p => p.element);
var bshcUniques = Array.from(new Set(pixel._bottomStateHighCache));
pixel._bottomStateHighCache = bshcUniques.filter(elemNameToFilterBy => (pixel._bottomStateHighCache.filter(elemName => elemName == elemNameToFilterBy).length >= (pixel._bottomStateHighCache.length / 10)));
pixel._bottomStateHighCache = pixel._bottomStateHighCache.map(elemName => getStateHigh(elemName) ?? elemName);
var pixelDistanceFromBottom = height - pixel.y;
var counterDistanceFromBottom = height - (pixel.y + pixel.counter);
var yRisingFromBottomToHalfway = Math.round((height - 1) - (pixel.counter / 2));
var closenessToBottom = 1 - (counterDistanceFromBottom / pixelDistanceFromBottom);
var finalRadius = Math.round(((1 + closenessToBottom) ** 2) * 6);
var earthquakeChance = ((closenessToBottom >= 0.5) && (0.1 + (0.05 * (1 + (Math.max(closenessToBottom - 0.5,0) * 25)))))
var earthquakeMaxTryCount = 2 + (Math.random() < (closenessToBottom - 0.5)) + (Math.random() < (closenessToBottom - 0.75)) + (Math.random() < earthquakeChance) + (Math.random() < (earthquakeChance ** 2));
for(var i = 0; i < earthquakeMaxTryCount; i++) {
if((closenessToBottom >= 0.5) && (Math.random() < earthquakeChance)) { //random earthquake
var rX = (Math.floor(Math.random() * (width - 1)) + 1);
var rY = Math.round(height / 2) + Math.floor(Math.random() * height / 2);
var eq = createOrChangePixelAndReturn("earthquake",rX,rY);
if(eq) {
eq.stage = 1;
eq.mag = Math.floor(Math.random() * ((5 * (1 + (Math.max(closenessToBottom - 0.5,0) * 2.5))) + 1)) + 15;
}
}
};
for(var x = 1; x < width; x++) {
var y = yRisingFromBottomToHalfway;
if(isEmpty(x,y,true)) { continue };
var newPixel = pixelMap[x][y];
var newData = elements[newPixel.element]
if(Math.random() < closenessToBottom) { tryBreak(newPixel) }
newPixel.temp += 400 + ((1 - closenessToBottom) * 100);
pixelTempCheck(newPixel)
if(!newData.excludeVelocity) {
newPixel.vy ??= 0;
newPixel.vy -= Math.round((2 + (closenessToBottom * 2)) ** 2)
}
};
explodeAtPlus(pixel.x,pixel.y+pixel.counter,finalRadius,"plasma","fire",null,planetCrackerHeat);
pixel.counter++;
};
},
state: "solid",
density: 10000,
category: "weapons",
hardness: 1,
};
//ASSORTED CELL EDITS AND GOLDEN FAIRY CHAIN ##
goldObject = {
gold: 1,
gold_coin: 1,
gold_fairy: 3
};
goldObjectNameArray = Object.keys(goldObject);
if(urlParams.get('goldFairyAmount') != null) { //null check
goldFairyAmount = urlParams.get('goldFairyAmount')
if(isNaN(goldFairyAmount) || goldFairyAmount === "" || goldFairyAmount === null) { //NaN check
goldFairyAmount = 10
}
goldFairyAmount = parseInt(goldFairyAmount)
if(goldFairyAmount > 10000) {
alert("Maximum amount of additional gold fairies is 10000.\nOnly 10000 fairies were added.")
} else if(goldFairyAmount < 1) {
alert("Minimum amount of additional gold fairies is 1.\n1 fairy was added.")
}
goldFairyAmount = Math.min(10000,Math.max(goldFairyAmount,1))
} else {
goldFairyAmount = 10
}
elements.cell_1 = { //heats up
color: ["#bbee00","#eeee00","#cfee00"],
behavior: [
"XX|CL%0.5|XX",
"CL%0.5|HT:1%2|CL%0.5",
"M2%10|M1|M2%10",
],
uwu: 0,
properties: {
uwu: 0
},
tick: function(pixel) {
pixel.uwu = 0;
for (let i = -1; i < 2; i++) { //neighbor count
for (let j = -1; j < 2; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++;
};
};
};
};
pixel.uwu -= 1; //exclude self
var tempGrowthDecrease = null;
if(pixel.temp < 70) {
tempGrowthDecrease = 0;
} else if(pixel.temp > 100) {
tempGrowthDecrease = 70;
} else {
tempGrowthDecrease = pixel.temp - 70;
}
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
uwu = 0;
} else {
var tempGain = pixel.uwu / 48;
var chanceGain = pixel.uwu / 96;
};
if(Math.random() < ( (2 + chanceGain) - (tempGrowthDecrease / 30) )) {
pixel.temp += tempGain;
};
},
reactions: {
"infection": { "elem1":"cancer", "chance":0.01 },
"blood": { "elem1":"blood", "chance":0.01 },
"antibody": { "elem1":"antibody", "chance":0.01 },
"sugar": { "elem2":"cell", "chance":0.03 },
"sugar_water": { "elem2":"cell", "chance":0.04 },
"alcohol": { "elem1":[null,"dna"], "chance":0.02 },
"poison": { "elem1":null, "chance":0.02 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.05 },
"ammonia": { "elem2":"nitrogen", "chance":0.05 }
},
tempHigh: 122,
stateHigh: "steam",
tempLow: -6,
stateLow: "ice",
state: "solid",
density: 1000.2,
category: "life",
breakInto: ["water","dna","dna","dna"]
};
elements.cell_2 = { //Grows just a bit too fast
color: ["#32280b","#5a4711","#87660c"],
behavior: [
"XX|CL%1.8|XX",
"CL%1.8|XX|CL%1.8",
"M2%5|M1|M2%5",
],
reactions: {
"cancer": { "elem2":"cell_2", "chance":0.035 },
"cell": { "elem2":"cell_2", "chance":0.001 },
"frog": { "elem2":"cell_2", "chance":0.001 },
"fish": { "elem2":"cell_2", "chance":0.001 },
"rat": { "elem2":"cell_2", "chance":0.001 },
"bird": { "elem2":"cell_2", "chance":0.001 },
"sugar": { "elem2":"cell_2", "chance":0.035 },
"sugar_water": { "elem2":"cell_2", "chance":0.045 },
"alcohol": { "elem1":[null,"dna"], "chance":0.012 },
"poison": { "elem1":[null,null,"poison","poison","poison","dna","dirty_water"], "chance":0.03 },
"proton": { "elem1":[null,"cancer"], "chance":0.04 }
},
tempHigh: 80,
stateHigh: ["steam","plague"],
state: "solid",
density: 1000.17,
category: "life",
breakInto: ["dirty_water","dna","dna","dna","dna"]
};
elements.cell_3 = { //Likes gold
color: ["#bbee00","#eeee00","#cfee00"],
behavior: [
"XX|CL%0.5|XX",
"CL%0.5|HT:1%2|CL%0.5",
"M2%10|M1|M2%10",
],
uwu: 0,
properties: {
uwu: 0
},
tick: function(pixel) {
pixel.uwu = 0;
for (let i = -1; i < 2; i++) { //neighbor count
for (let j = -1; j < 2; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (pixelMap[pixel.x+j][pixel.y+i].element == pixel.element) {
pixel.uwu++;
};
};
};
};
pixel.uwu -= 1; //exclude self
var tempGrowthDecrease = null;
if(pixel.temp < 70) {
tempGrowthDecrease = 0;
} else if(pixel.temp > 100) {
tempGrowthDecrease = 70;
} else {
tempGrowthDecrease = pixel.temp - 70;
}
if(pixel.uwu == undefined || pixel.uwu == null || isNaN(pixel.uwu)) {
uwu = 0;
} else {
var tempGain = pixel.uwu / 48;
var chanceGain = pixel.uwu / 96;
};
if(Math.random() < ( (2 + chanceGain) - (tempGrowthDecrease / 30) )) {
pixel.temp += tempGain;
};
},
reactions: {
"infection": { "elem1":"cancer", "chance":0.01 },
"blood": { "elem1":"blood", "chance":0.01 },
"antibody": { "elem1":"antibody", "chance":0.01 },
"sugar": { "elem2":"cell", "chance":0.03 },
"sugar_water": { "elem2":"cell", "chance":0.04 },
"alcohol": { "elem1":[null,"dna"], "chance":0.02 },
"poison": { "elem1":null, "chance":0.02 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.05 },
"ammonia": { "elem2":"nitrogen", "chance":0.05 }
},
tempHigh: 122,
stateHigh: "steam",
tempLow: -6,
stateLow: "ice",
state: "solid",
density: 1000.2,
category: "life",
breakInto: ["water","dna","dna","dna"]
};
elements.cell_3 = {
color: ["#eeee00","#eecc00","#dddd00"],
behavior: [
"XX|CL%0|XX", //CL%0 for display purposes
"CL%0|XX|CL%0",
"M2%10|M1|M2%10",
],
reactions: {
"infection": { "elem1":"cancer", "chance":0.01 },
"blood": { "elem1":"blood", "chance":0.01 },
"antibody": { "elem1":"antibody", "chance":0.01 },
"sugar": { "elem2":"cell", "chance":0.03 },
"sugar_water": { "elem2":"cell", "chance":0.04 },
"alcohol": { "elem1":[null,"dna"], "chance":0.02 },
"poison": { "elem1":null, "chance":0.02 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.05 },
"ammonia": { "elem2":"nitrogen", "chance":0.05 }
},
tempHigh: 102,
stateHigh: "steam",
tempLow: -2,
stateLow: "ice",
state: "solid",
density: 1000.1,
category: "life",
breakInto: ["water","dna","dna","dna"],
gold: 0,
properties: {
gold: 0
},
tick: function(pixel) {
var pX = pixel.x
var pY = pixel.y
var baseEatRate = 1;
var eatRate = baseEatRate + (2 * pixel.gold * 0.01);
if(Math.random() < eatRate/100) {
var randomNeighborNumber = Math.floor(Math.random() * 4)
var oX = adjacentCoords[randomNeighborNumber][0];
var oY = adjacentCoords[randomNeighborNumber][1];
var checkPosX = pX+oX;
var checkPosY = pY+oY;
if(!isEmpty(checkPosX,checkPosY,true)) {
if(goldObjectNameArray.includes(pixelMap[checkPosX][checkPosY].element)) {
pixel.gold += goldObject[pixelMap[checkPosX][checkPosY].element];
deletePixel(checkPosX,checkPosY);
};
};
};
var baseGrowthRate = 0.5;
var growthRate = baseGrowthRate + (pixel.gold * 0.025);
if(pixel.gold > 150) {
var chance = (pixel.gold - 150) / 20
var baseRadius = 10
var radius = Math.max(20,Math.round((baseRadius + (pixel.gold / 25))))
if(Math.random() < (chance / 100)) {
explodeAt(pX,pY,10,"gold_coin");
};
};
if(Math.random() < growthRate/100) {
var randomNeighborNumber = Math.floor(Math.random() * 4)
var oX = adjacentCoords[randomNeighborNumber][0];
var oY = adjacentCoords[randomNeighborNumber][1];
var checkPosX = pX+oX;
var checkPosY = pY+oY;
if(isEmpty(checkPosX,checkPosY,false)) {
var halfGold1 = pixel.gold / 2;
var halfGold2 = pixel.gold / 2;
if(halfGold1 % 1 == 0.5) {
halfGold1 = Math.ceil(halfGold1);
halfGold2 = Math.floor(halfGold2);
};
createPixel(pixel.element,checkPosX,checkPosY);
newPixel = pixelMap[checkPosX][checkPosY];
pixel.gold = halfGold1;
newPixel.gold = halfGold2;
};
};
},
reactions: {
"infection": { "elem1":"cancer", "chance":0.01 },
"blood": { "elem1":"blood", "chance":0.01 },
"antibody": { "elem1":"antibody", "chance":0.01 },
"sugar": { "elem2":"cell", "chance":0.03 },
"sugar_water": { "elem2":"cell", "chance":0.04 },
"alcohol": { "elem1":[null,"dna"], "chance":0.02 },
"poison": { "elem1":null, "chance":0.02 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.05 },
"ammonia": { "elem2":"nitrogen", "chance":0.05 }
},
tempHigh: 122,
stateHigh: "steam",
tempLow: -6,
stateLow: "ice",
state: "solid",
density: 1000.2,
category: "life",
breakInto: ["water","dna","dna","dna"]
};
runAfterLoad(function() {
elements.gold_fairy = {
name: "gold fairy",
color: ["#cfa65b","#e6df63","#faf673"],
behavior: [
"XX|M1|M1",
"XX|FX%5|XX",
"XX|CR:gold_coin%0.25 AND CR:fairy_dust%0.005 AND M1|M1",
],
state: "solid",
category: "fey"
};
elements.fairy.reactions.gold = { elem1: "gold_fairy", "elem2": null };
elements.fairy.reactions.gold_coin = { elem1: "gold_fairy", "elem2": null };
if(!elements.gold.reactions) {
elements.gold.reactions = {};
};
if(!elements.gold_coin.reactions) {
elements.gold_coin.reactions = {};
};
elements.gold.reactions.fairy = { elem1: null, elem2: "gold_fairy" };
elements.gold_coin.reactions.fairy = { elem1: null, elem2: "gold_fairy" };
for (var i = 2; i <= goldFairyAmount + 1; i++) {
nameVar = `gold_${i-1}-fairy`
if(i === 2) {
nameVar = "gold_fairy";
};
elements[`gold_${i}-fairy`] = {
name: `gold_${i}-fairy`,
color: ["#cfa65b","#e6df63","#faf673"],
behavior: [
"XX|M1|M1",
"XX|FX%5|XX",
"XX|CR:" + nameVar + "%0.25 AND CR:fairy_dust%0.005 AND M1|M1",
],
reactions: {
"glitter": { "elem1": `gold_${i+1}-fairy`, "elem2": null }
},
state: "solid",
excludeRandom:true,
category: "fey",
hidden: true,
}
goldObject[`gold_${i}-fairy`] = 3 * i;
if (i == goldFairyAmount) { elements[`gold_${i}-fairy`]["reactions"] = {}; }
}
//eList rebuilding {
eLists.FAIRY.push("gold_fairy");
for (var i = 2; i <= goldFairyAmount + 1; i++) {
eLists.FAIRY.push(`gold_${i}-fairy`);
};
elements.iron.behavior = [
"XX|DL:"+eLists.FAIRY+"|XX",
"DL:"+eLists.FAIRY+"|XX|DL:"+eLists.FAIRY+"",
"XX|DL:"+eLists.FAIRY+"|XX"
];
elements.silver.behavior = [
"XX|DL:"+eLists.FAIRY+"|XX",
"DL:"+eLists.FAIRY+"|XX|DL:"+eLists.FAIRY+"",
"XX|DL:"+eLists.FAIRY+"|XX"
];
elements.tungstensteel.behavior = [
"XX|DL:"+eLists.FAIRY+"|XX",
"DL:"+eLists.FAIRY+"|XX|DL:"+eLists.FAIRY+"",
"XX|DL:"+eLists.FAIRY+"|XX",
];
elements.molten_tungstensteel ??= {};
elements.molten_tungstensteel.behavior = [
"XX|DL:"+eLists.FAIRY+" AND CR:fire%2.5|XX",
"DL:"+eLists.FAIRY+" AND M2|XX|DL:"+eLists.FAIRY+" AND M2",
"M1|DL:"+eLists.FAIRY+"|M1",
]
//}
goldObjectNameArray = Object.keys(goldObject);
elements.rainbow.reactions.gold_fairy = { "elem1": "gold_2-fairy", "elem2": null }
});
//FIRE SLIME ##
elements.fire_slime = {
color: ["#e6683e", "#e37636", "#e38f3b", "#e3b039"],
behavior: [
"XX|CR:fire%5|XX",
"M2|XX|M2",
"M1%1 AND M2|M1|M1%1 AND M2"
],
reactions: {
"bomb": { "elem2":"sticky_bomb", "elem2":null },
},
tick: function(pixel) {
if(Math.random() < 0.01) {
pixel.temp++;
pixelTempCheck(pixel);
};
if(pixel.temp < 700) {
if(Math.random() < 0.02) {
pixel.temp++;
pixelTempCheck(pixel);
};
};
},
viscosity: 3000,
temp: 700,
tempHigh: 6000,
stateHigh: "plasma",
tempLow: -13,
stateLow: "suppressed_fire_slime",
category: "liquids",
state: "liquid",
burning: true,
burnTime: Number.MAX_SAFE_INTEGER,
burn: 85,
burnInto: "fire_slime",
density: 1400,
stain: 0.05
}
elements.suppressed_fire_slime = {
color: "#bf6a4e",
behavior: [
"XX|CR:smoke%1|XX",
"M2|XX|M2",
"M1%0.5 AND M2|M1|M1%0.5 AND M2"
],
reactions: {
"bomb": { "elem2":"sticky_bomb", "elem2":null },
},
tick: function(pixel) {
if(Math.random() < 0.001) {
pixel.temp++;
pixelTempCheck(pixel);
};
},
viscosity: 4000,
temp: -20,
tempHigh: -13,
stateHigh: "fire_slime",
category: "liquids",
state: "liquid",
burning: false,
burnTime: 1000,
burn: 1,
burnInto: "fire_slime",
density: 1550,
stain: 0.04,
hidden: true
}
//FWIBBLENS ##
elements.fwibblen = {
color: ["#73F092", "#EB7373", "#EDBC7B"],
behavior: [
"XX|M2|M1",
"XX|FX%2|BO",
"XX|XX|M1",
],
reactions: {
nickel: { elem2: ["fwibblen",null] },
nickel_scrap: { elem2: ["fwibblen",null] }
},
tempHigh: 1100,
stateHigh: "dead_fwibblen",
category:"life",
state: "solid",
density: 1500,
conduct: 0.4,
}
elements.dead_fwibblen = {
color: ["#729E7D", "#B58484", "#C4B299"],
behavior: behaviors.POWDER,
tempHigh: 1455,
stateHigh: ["molten_nickel","molten_nickel","molten_nickel","smoke"],
category:"life",
hidden: true,
state: "solid",
density: 1400,
conduct: 0.4,
}
elements.meffwibblen = {
color: ["#5CE697", "#F05B60", "#EB9560"],
behavior: [
"XX|M2|M1",
"XX|FX%2|BO",
"XX|XX|M1",
],
reactions: {
fwibblen: { elem2: ["meffwibblen",null] },
dead_fwibblen: { elem2: ["meffwibblen",null] }
},
tempHigh: 1150,
stateHigh: "dead_meffwibblen",
category:"life",
state: "solid",
density: 1800,
conduct: 0.44,
}
elements.dead_meffwibblen = {
color: ["#659E7D", "#B37073", "#B08F7B"],
behavior: behaviors.POWDER,
tempHigh: 1455,
stateHigh: ["molten_nickel","molten_nickel","molten_nickel","molten_nickel","smoke"],
category:"life",
hidden: true,
state: "solid",
density: 1800,
conduct: 0.44,
}
//Debug world
/*worldgentypes.nickel = {
layers: [
[0, "nickel"],
]
};*/
//EXPERIMENTAL CONTROLLABLE PIXEL ##
sussyKey = null;
isShift = false;
isAlt = false;
document.addEventListener("keydown", function(modifierDownListener) {
// User presses shift
if (modifierDownListener.keyCode == 16) {
isShift = true;
}
// User presses alt
if (modifierDownListener.keyCode == 18) {
isAlt = true;
}
});
document.addEventListener("keyup", function(modifierUpListener) {
// User releases shift
if (modifierUpListener.keyCode == 16) {
isShift = false;
}
// User releases alt
if (modifierUpListener.keyCode == 18) {
isAlt = false;
}
});
document.addEventListener("keyup", function(sussyListener) {
switch (sussyListener.keyCode) {
case 87:
sussyKey = "W";
break;
case 65:
sussyKey = "A";
break;
case 83:
sussyKey = "S";
break;
case 68:
sussyKey = "D";
break;
case 81:
sussyKey = "Q";
break;
case 88:
sussyKey = "X";
break;
case 90:
sussyKey = "Z";
break;
case 72:
sussyKey = "H";
break;
};
});
function controllablePixelTryCreatePixelNullCheck(element,x,y) {
if(!elements[element]) { //catch the null
return false;
};
if(isEmpty(x,y)) {
tryCreatePixel(element,x,y);
return true;
} else {
return false;
}
}
elements.controllable_pixel = {
color: _cc.w.h,
colorOn: "#FFFF00",
behavior: behaviors.WALL,
state: "solid",
density: 2000,
maxSize: 1,
conduct: 1,
hardness: 1,
tick: function(pixel) {
var xx = pixel.x;
var yy = pixel.y;
userElement = currentElement;
if(userElement === pixel.element) {
userElement = null;
};
if(isShift && !isAlt) {
sussyKey === "Z" ? pixel.color = "rgb(255,191,127)" : pixel.color = "rgb(255,127,127)";
}
if(isAlt && !isShift) {
sussyKey === "Z" ? pixel.color = "rgb(191,255,127)" : pixel.color = "rgb(127,255,127)";
}
if(isAlt && isShift) {
sussyKey === "Z" ? pixel.color = "rgb(255,255,0)" : pixel.color = "rgb(255,255,127)";
}
if(!isAlt && !isShift) {
sussyKey === "Z" ? pixel.color = "rgb(255,255,191)" : pixel.color = _cc.w.r;
}
if(sussyKey !== null) {
switch (sussyKey) {
case "W":
isAlt ? controllablePixelTryCreatePixelNullCheck(userElement,xx,yy-1) : tryMove(pixel,xx,yy-1);
if(!isShift) {
sussyKey = null;
}
break;
case "A":
isAlt ? controllablePixelTryCreatePixelNullCheck(userElement,xx-1,yy) : tryMove(pixel,xx-1,yy);
if(!isShift) {
sussyKey = null;
}
break;
case "S":
isAlt ? controllablePixelTryCreatePixelNullCheck(userElement,xx,yy+1) : tryMove(pixel,xx,yy+1);
if(!isShift) {
sussyKey = null;
}
break;
case "D":
tryMove(pixel,xx+1,yy);
if(!isShift) {
sussyKey = null;
}
break;
case "H": //Alt+D is something else in some browsers.
if(isAlt) {
controllablePixelTryCreatePixelNullCheck(userElement,xx+1,yy);
};
if(!isShift) {
sussyKey = null;
}
break;
case "X":
explodeAt(xx,yy,5)
if(!isShift) {
sussyKey = null;
}
break;
case "Z":
if (!pixel.charge && !pixel.chargeCD && !isEmpty(pixel.x,pixel.y,true)) {
pixel.charge = 1;
}
if(!isShift === 0) {
sussyKey = null;
}
break;
case "Q": //Use if a key gets stuck
sussyKey = null;
isShift = null;
isAlt = null;
break;
}
}
},
}
actExcludedElements = ["wall","alt_controllable_pixel"];
function actTryMove(pixel,x,y) {
if(!tryMove(pixel,x,y)) {
if(outOfBounds(x,y)) {
return false;
};
if(!isEmpty(x,y,true)) {
var newPixel = pixelMap[x][y];
var newElement = newPixel.element;
if(actExcludedElements.includes(newElement)) {
return false;
};
if(newElement == pixel.element) { //Copy-paste of "break" code
swapPixels(pixel,newPixel);
return true;
} else {
breakCircle(newPixel.x,newPixel.y,pixel.breakAroundRadius,false,false,false); //does nothing to elements without breakIntos if defaultBreakIntoDust is false
swapPixels(pixel,newPixel);
return true;
};
} else {
return false;
};
} else {
return true;
};
};
function cptaEapFunction(pixel,x,y,radius,fire,smoke,power,damage) {
var coords = circleCoords(pixel.x,pixel.y,radius);
for (var i = 0; i < coords.length; i++) {
var x = coords[i].x;
var y = coords[i].y;
if(isEmpty(x,y)) { //if there's space for fire
if (Array.isArray(fire)) { //this should remain "fire"
var newfire = fire[Math.floor(Math.random() * fire.length)];
} else {
var newfire = fire;
};
createPixel(newfire,x,y); //add fire
var firePixel = pixelMap[x][y];
firePixel.temp = Math.max(elements[newfire].temp,firePixel.temp);
firePixel.burning = true;
};
if(!isEmpty(x,y,true)) {
pixel.temp += (400 * ((1 + (5 * damage)) ** 2) * ((power ** 1.5) * 1.5));
pixelTempCheck(pixel);
};
if (!elements[pixel.element].excludeVelocity) {
var angle = Math.atan2(pixel.y-y,pixel.x-x);
pixel.vx = Math.round((pixel.vx|0) + Math.cos(angle) * (radius * power/10));
pixel.vy = Math.round((pixel.vy|0) + Math.sin(angle) * (radius * power/10));
}
};
};
alt_sussyKey = null;
isShift = false;
isAlt = false;
document.addEventListener("keydown", function(modifierDownListener) {
// User presses shift
if (modifierDownListener.keyCode == 16) {
isShift = true;
}
// User presses alt
if (modifierDownListener.keyCode == 18) {
isAlt = true;
}
});
document.addEventListener("keyup", function(modifierUpListener) {
// User releases shift
if (modifierUpListener.keyCode == 16) {
isShift = false;
}
// User releases alt
if (modifierUpListener.keyCode == 18) {
isAlt = false;
}
});
document.addEventListener("keyup", function(alt_sussyListener) {
switch (alt_sussyListener.keyCode) {
case 87:
alt_sussyKey = "W";
break;
case 65:
alt_sussyKey = "A";
break;
case 83:
alt_sussyKey = "S";
break;
case 68:
alt_sussyKey = "D";
break;
case 81:
alt_sussyKey = "Q";
break;
case 88:
alt_sussyKey = "X";
break;
case 90:
alt_sussyKey = "Z";
break;
case 72:
alt_sussyKey = "H";
break;
case 76:
alt_sussyKey = "L";
break;
};
});
function controllablePixelTryCreatePixelNullCheck(element,x,y) {
if(!elements[element]) { //catch the null
return false;
};
if(isEmpty(x,y)) {
tryCreatePixel(element,x,y);
return true;
} else {
return false;
}
}
elements.alt_controllable_pixel = {
color: "#7F7F7F",
colorOn: "#FFFF00",
behavior: behaviors.WALL,
state: "solid",
density: 2000,
maxSize: 1,
conduct: 1,
hardness: 1,
movable: true,
desc: "it breaks things more Use the console or enable prop.js to set speed / explosionRadius / circleRadius / breakAroundRadius (though it has an Illogical™ random resetting bug)",
breakInto: "alt_controllable_pixel",
properties: {
speed: 1,
explosionRadius: 8,
circleRadius: 8,
breakAroundRadius: 4
},
excludeVelocity: true,
tick: function(pixel) {
userElement = currentElement;
if(userElement === pixel.element) {
userElement = null;
};
if(isShift && !isAlt) {
alt_sussyKey === "Z" ? pixel.color = "rgb(255,191,127)" : pixel.color = "rgb(255,127,127)";
}
if(isAlt && !isShift) {
alt_sussyKey === "Z" ? pixel.color = "rgb(191,255,127)" : pixel.color = "rgb(127,255,127)";
}
if(isAlt && isShift) {
alt_sussyKey === "Z" ? pixel.color = "rgb(255,255,0)" : pixel.color = "rgb(255,255,127)";
}
if(!isAlt && !isShift) {
alt_sussyKey === "Z" ? pixel.color = "rgb(255,255,191)" : pixel.color = _cc.w.r;
}
if(alt_sussyKey !== null) {
switch (alt_sussyKey) {
case "W":
if(isAlt) { controllablePixelTryCreatePixelNullCheck(userElement,pixel.x,pixel.y-1) } else { for(move = 0; move < pixel.speed; move++) { actTryMove(pixel,pixel.x,pixel.y-1) } };
if(!isShift) {
alt_sussyKey = null;
}
break;
case "A":
if(isAlt) { controllablePixelTryCreatePixelNullCheck(userElement,pixel.x-1,pixel.y) } else { for(move = 0; move < pixel.speed; move++) { actTryMove(pixel,pixel.x-1,pixel.y) } };
if(!isShift) {
alt_sussyKey = null;
}
break;
case "S":
if(isAlt) { controllablePixelTryCreatePixelNullCheck(userElement,pixel.x,pixel.y+1) } else { for(move = 0; move < pixel.speed; move++) { actTryMove(pixel,pixel.x,pixel.y+1) } };
if(!isShift) {
alt_sussyKey = null;
}
break;
case "D":
for(move = 0; move < pixel.speed; move++) { actTryMove(pixel,pixel.x+1,pixel.y) };
if(!isShift) {
alt_sussyKey = null;
}
break;
case "H": //Alt+D is something else in some browsers.
if(isAlt) {
controllablePixelTryCreatePixelNullCheck(userElement,pixel.x+1,pixel.y);
};
if(!isShift) {
alt_sussyKey = null;
}
break;
case "X":
explodeAtPlus(pixel.x,pixel.y,pixel.explosionRadius,"plasma,fire,fire","fire,smoke,smoke",null,cptaEapFunction)
if(!isShift) {
alt_sussyKey = null;
}
break;
case "Z":
if (!pixel.charge && !pixel.chargeCD && !isEmpty(pixel.x,pixel.y,true)) {
pixel.charge = 1;
}
if(!isShift === 0) {
alt_sussyKey = null;
}
break;
case "L":
if(userElement !== null) {
fillCircle(currentElement,pixel.x,pixel.y,pixel.circleRadius,false);
if(!isShift === 0) {
alt_sussyKey = null;
}
};
break;
case "Q": //Use if a key gets stuck
alt_sussyKey = null;
isShift = null;
isAlt = null;
break;
}
}
}
}
//PARTIAL APIOFORM GAME ##
playerKills = 0;
aplReceivedKey = null;
isShift = false;
isAlt = false;
document.addEventListener("keydown", function(modifierDownListener) {
// User presses shift
if (modifierDownListener.keyCode == 16) {
isShift = true;
}
// User presses alt
if (modifierDownListener.keyCode == 18) {
isAlt = true;
}
});
document.addEventListener("keyup", function(modifierUpListener) {
// User releases shift
if (modifierUpListener.keyCode == 16) {
isShift = false;
}
// User releases alt
if (modifierUpListener.keyCode == 18) {
isAlt = false;
}
});
entities = ["apioform_bee", "apioform", "apiodiagoform", "apiokinetoform", "apiopyroform", "cryoapioform", "apiopariform"]
function apioTryMove(pixel,nx,ny,leaveBehind=undefined) {
if(!isEmpty(nx,ny,true) && !outOfBounds(nx.ny)) {
otherPixel = pixelMap[nx][ny];
var thisElement = pixel.element;
var otherElement = otherPixel.element;
if(thisElement == "apioform_player") {
if(entities.includes(otherElement)) {
deletePixel(nx,ny);
playerKills++;
movePixel(pixel,nx,ny,leaveBehind)
};
} else if(entities.includes(thisElement)) {
if(otherElement == "apioform_player") {
deletePixel(nx,ny);
movePixel(pixel,nx,ny,leaveBehind)
};
};
} else {
tryMove(pixel,nx,ny,leaveBehind);
};
}
document.addEventListener("keyup", function(apioformPlayerListener) {
switch (apioformPlayerListener.keyCode) {
case 38: //arrow up, letter 87:
aplReceivedKey = "W";
break;
case 37: //arrow left, letter 65
aplReceivedKey = "A";
break;
case 40: //arrow down, letter 83
aplReceivedKey = "S";
break;
case 39: //arrow right, letter 68
aplReceivedKey = "D";
break;
case 27: //escape key, letter 81
aplReceivedKey = "Q";
break;
};
});
elements.apioform_player = {
color: "#7F7F7F",
behavior: behaviors.WALL,
state: "solid",
density: 2000,
maxSize: 1,
hardness: 0.8,
burnTime: 10,
burn: 50,
category: "apioform game",
tick: function(pixel) {
var xx = pixel.x;
var yy = pixel.y;
if(isShift) {
pixel.color = "rgb(255,127,127)";
} else {
pixel.color = _cc.w.r;
}
if(aplReceivedKey !== null) {
switch (aplReceivedKey) {
case "W":
apioTryMove(pixel,xx,yy-1);
if(!isShift) {
aplReceivedKey = null;
}
break;
case "A":
apioTryMove(pixel,xx-1,yy);
if(!isShift) {
aplReceivedKey = null;
}
break;
case "S":
apioTryMove(pixel,xx,yy+1);
if(!isShift) {
aplReceivedKey = null;
}
break;
case "D":
apioTryMove(pixel,xx+1,yy);
if(!isShift) {
aplReceivedKey = null;
}
break;
case "Q": //Use if a key gets stuck
aplReceivedKey = null;
isShift = null;
break;
};
};
},
}
elements.apioform_bee = {
color: ["#808020", "#A0A050"],
properties: {
stage: ((Math.random() < 0.5) ? 0 : 1),
},
behavior: behaviors.WALL,
state: "solid",
category: "apioform game",
density: 2000,
maxSize: 1,
hardness: 0.8,
flippableY: true,
tick: function(pixel) {
if(isNaN(pixel.stage)) {
pixel.stage = ((Math.random() < 0.5) ? 0 : 1);
};
pixel.stage = Math.min(1,Math.max(0,Math.round(pixel.stage))); //stage validation
var moveCoords = (pixel.flipY ? [pixel.x, pixel.y+1] : [pixel.x, pixel.y-1]);
//direction is randomized by flippableY
if(pixel.stage === 0) { //color
pixel.color = "rgb(128,128,32)";
} else if(pixel.stage === 1) {
pixel.color = "rgb(160,160,80)";
};
if(pixelTicks - pixel.start > 0) { //don't move on first tick, to allow color to normalize
if(pixel.stage === 0) { //if in still stage
pixel.stage = 1; //change to moving stage
} else if(pixel.stage === 1) { //else if in moving stage
apioTryMove(pixel,moveCoords[0],moveCoords[1]); //move
pixel.flipY = !pixel.flipY; //flip that
pixel.stage = 0; //change to still stage
};
};
},
}
elements.apioform = {
color: "#A08020",
behavior: behaviors.WALL,
state: "solid",
category: "apioform game",
density: 2000,
maxSize: 1,
hardness: 0.8,
rotatable: true,
tick: function(pixel) {
if(isNaN(pixel.r)) {
pixel.r = Math.floor(Math.random() * 4);
};
pixel.r = Math.round(pixel.r) % 4; //rotation validation, probably redundant since rotation is from the base game
var moveCoords;
switch (pixel.r) {
case 0:
moveCoords = [pixel.x+1, pixel.y+0];
break;
case 1:
moveCoords = [pixel.x+0, pixel.y-1];
break;
case 2:
moveCoords = [pixel.x-1, pixel.y+0];
break;
case 3:
moveCoords = [pixel.x+0, pixel.y+1];
break;
};
//rotation is randomized by rotatable
if(pixelTicks - pixel.start > 0) { //maintained for consistency
apioTryMove(pixel,moveCoords[0],moveCoords[1]); //move
pixel.r++; //increment rotation
};
},
}
elements.apiodiagoform = {
color: "#A080A0",
behavior: behaviors.WALL,
state: "solid",
category: "apioform game",
density: 2000,
maxSize: 1,
hardness: 0.8,
rotatable: true,
tick: function(pixel) {
if(isNaN(pixel.r)) {
pixel.r = Math.floor(Math.random() * 4);
};
pixel.r = Math.round(pixel.r) % 4; //rotation validation, probably redundant since rotation is from the base game
var moveCoords;
switch (pixel.r) {
case 0:
moveCoords = [pixel.x-1, pixel.y-1];
break;
case 1:
moveCoords = [pixel.x-1, pixel.y+1];
break;
case 2:
moveCoords = [pixel.x+1, pixel.y+1];
break;
case 3:
moveCoords = [pixel.x+1, pixel.y-1];
break;
};
//rotation is randomized by rotatable
if(pixelTicks - pixel.start > 0) { //maintained for consistency
apioTryMove(pixel,moveCoords[0],moveCoords[1]); //move
pixel.r++; //increment rotation
};
},
}
//AMOGUS ##
elements.amogus = {
name: "Amogus",
color: _cc.w.h,
cooldown: 6,
tick: function(pixel) {
pixel.arr=[["brick", "brick", "brick"],
["brick", "glass", "glass"],
["brick", "brick", "brick"],
["brick", "air", "brick"]];
pixel.carr=[[ "rgb(255,0,0)", "rgb(255,0,0)", "rgb(255,0,0)" ],
[ "rgb(255,0,0)", "rgb(0,255,255)", "rgb(0,255,255)"],
[ "rgb(255,0,0)", "rgb(255,0,0)", "rgb(255,0,0)" ],
[ "rgb(255,0,0)", "null", "rgb(255,0,0)" ]];
var aa = (0 - (Math.floor(pixel.arr[0].length / 2))) //Center align code
var na = Math.abs(aa)
if(pixel.arr[0].length % 2 == 1) {
var bb = ((Math.floor(pixel.arr[0].length / 2)) + 1)
} else if(pixel.arr[0].length % 2 == 0) {
var bb = (Math.floor(pixel.arr[0].length / 2))
}
var cc = (0 - (Math.floor(pixel.arr.length / 2)))
var nc = Math.abs(cc)
if(pixel.arr.length % 2 == 1) {
var dd = ((Math.floor(pixel.arr.length / 2)) + 1)
} else if(pixel.arr.length % 2 == 0) {
var dd = (Math.floor(pixel.arr.length / 2))
}
for (let j = cc; j < dd; j++) { //Iterative placing and coloring of pixels
for (let i = aa; i < bb; i++) {
if(!isEmpty(pixel.x+i,pixel.y+j,true)) {
if(pixel.arr[j+nc][i+na] !== "null") {
deletePixel(pixel.x+i,pixel.y+j)
}
}
if(pixel.arr[j+nc][i+na]) {
if(isEmpty(pixel.x+i,pixel.y+j,false) && pixel.arr[j+nc][i+na] !== "null" && pixel.arr[j+nc][i+na] !== "air") {
createPixel(pixel.arr[j+nc][i+na],pixel.x+i,pixel.y+j)
if(pixel.carr[j+nc][i+na]) {
if(!isEmpty(pixel.x+i,pixel.y+j,true) && pixel.carr[j+nc][i+na] != "null") {
pixelMap[pixel.x+i][pixel.y+j].color = pixel.carr[j+nc][i+na]
}
}
}
}
}
}
},
category:"structures",
insulate: true,
state: "solid",
excludeRandom: true,
},
elements.amogus_seed = {
name: "Amogus Seed",
color: "#df2f47",
cooldown: 6,
behavior: [
"DL:amogus_seed|DL:amogus_seed AND M2|DL:amogus_seed",
"DL:amogus_seed|C2:amogus|DL:amogus_seed",
"DL:amogus_seed|SW:amogus_seed AND DL:amogus_seed AND M1|DL:amogus_seed"
],
category:"structures",
insulate: true,
state: "solid",
density: 2018,
}
//BACTERIA ##
elements.must = {
color: ["#0C433B","#2C3E2E","#173E2B","#053D20"],
behavior: behaviors.SUPPORTPOWDER,
category: "special",
state: "solid",
density: 1200,
conduct: 0.11
};
elements.water.reactions.bread = {
elem2: "must", chance: 0.005
};
elements.water.reactions.toast = {
elem2: "must", chance: 0.005
};
elements.water.reactions.must = {
elem2: "ripe_must", chance: 0.005
};
elements.ripe_must = {
color: ["#248f6d","#597a57","#3c8054","#1d8b40"],
behavior: behaviors.SUPPORTPOWDER,
category: "special",
state: "solid",
reactions: {
must: {elem1: "ripe_must", chance: 0.0004}
},
density: 1210,
conduct: 0.15,
breakInto: "bacteria_glob", //"the original name "bunch of bacteria" doesn't fit the sandboxels context IMO
hardness: 0.1
};
elements.bacteria_glob = {
color: ["#e34634","#c24332", "#d1703f"],
behavior: [
"XX|XX|XX",
"M2%25|XX|M2%25",
"M2|M1|M2"
],
reactions: {
"metal_scrap": {elem1: "bacteria", elem2: ["metal_scrap",null] }, //substituting for redstone torches, which will be implemented later alongside another mod
"charcoal": {elem1: "replacer_bacteria", elem2: ["charcoal",null] } //substituting for coal, which will also be added later
},
category: "special",
state: "liquid",
density: 1190,
conduct: 0.15,
breakInto: "bacteria_glob" //"the original name "bunch of bacteria" doesn't fit the sandboxels context IMO
};
bacteriaBlacklist = ["bacteria","replacer_bacteria","jammer_block"];
elements.bacteria = {
color: ["#e6d3f2", "#c098d9", "#6e318f", "#6e318f"],
behavior: behaviors.WALL,
tick: function(pixel) {
pixel.target ??= null;
if(pixel.charge) { //when shocked
if(!pixel.target) {
var elemsAbove = [];
var pX = pixel.x; var pY = pixel.y;
for(var counter = pY - 1; counter > 0; counter--) {
//console.log(pX,pY);
if(isEmpty(pX,counter,true)) {
break
};
var newPixel = pixelMap[pX][counter];
var newElement = newPixel.element;
if(bacteriaBlacklist.includes(newElement)) { break };
if(!(elemsAbove.includes(newElement))) {
elemsAbove.push(newElement)
};
};
if(elemsAbove.length == 0) {
return
} else {
pixel.target = elemsAbove
//console.log(pixel.target);
pixel.charge = 0;
}
};
if(!isEmpty(pixel.x,pixel.y+1,true)) { //check if a pixel exists below to convert
if(!pixel.active && !(bacteriaBlacklist.includes(pixelMap[pixel.x][pixel.y+1].element))) { //exclude certain blocks and only fire once
pixel.active = true
}
}
};
if(pixel.active) {
var pX = pixel.x; var pY = pixel.y;
if(pixel.target) { //safety
for(i = 0; i < adjacentCoords.length; i++) { //iterate through neighbor spots
var nX = pX + adjacentCoords[i][0]; var nY = pY + adjacentCoords[i][1];
if(!isEmpty(nX,nY,true)) { //check for neighbors
var newPixel = pixelMap[nX][nY];
if(pixel.target.includes(newPixel.element)) { //if neighbor element is the target
changePixel(newPixel,pixel.element) //change neighbors to itself
newPixel.target = pixel.target //set new bacteria target
newPixel.active = true //activate new bacteria
}
}
}
}
if(Math.random() < 0.02) { //decay
if(!isEmpty(pixel.x,pixel.y)) { //check if position is empty
deletePixel(pixel.x,pixel.y)
}
}
}
},
category: "special",
state: "solid",
density: 1200,
conduct: elements.water.conduct + 0.1,
},
elements.replacer_bacteria = {
color: ["#fcbbc0", "#f28089", "#f04f5c", "#f04f5c"],
behavior: behaviors.WALL,
tick: function(pixel) {
pixel.target ??= null;
pixel.replacement ??= null;
if(pixel.charge) { //when shocked
if(!pixel.target) {
if(!isEmpty(pixel.x,pixel.y+1,true)) {
pixelBelowElement = pixelMap[pixel.x][pixel.y+1].element;
if(!(bacteriaBlacklist.includes(pixelBelowElement))) {
pixel.target = pixelBelowElement;
}
}
};
if(!pixel.replacement) {
if(!isEmpty(pixel.x,pixel.y-1,true)) {
pixelAboveElement = pixelMap[pixel.x][pixel.y-1].element
if(!(bacteriaBlacklist.includes(pixelAboveElement))) {
pixel.replacement = pixelAboveElement;
}
}
};
if(!isEmpty(pixel.x,pixel.y+1,true)) { //check if a pixel exists below to convert
if((!pixel.active) && pixel.target && pixel.replacement) { //only fire once
pixel.active = true
}
}
};
if(pixel.active) {
var pX = pixel.x; var pY = pixel.y;
if(pixel.target) { //safety
for(i = 0; i < adjacentCoords.length; i++) { //iterate through neighbor spots
var nX = pX + adjacentCoords[i][0]; var nY = pY + adjacentCoords[i][1];
if(!isEmpty(nX,nY,true)) { //check for neighbors
var newPixel = pixelMap[nX][nY];
if(pixel.target == newPixel.element) { //if neighbor element is the target
changePixel(newPixel,pixel.element) //change neighbors to itself
newPixel.target = pixel.target //set new bacteria target
newPixel.replacement = pixel.replacement //set new bacteria replacement
newPixel.active = true //activate new bacteria
}
}
}
}
if(Math.random() < 0.05) { //decay
if(!isEmpty(pixel.x,pixel.y)) { //check if position is empty
changePixel(pixel,pixel.replacement)
}
}
}
},
category: "special",
state: "solid",
density: 1200,
conduct: elements.water.conduct + 0.1,
},
elements.jammer_block = {
color: "#c0cf7e",
behavior: behaviors.WALL,
tick: function(pixel) {
neighbors = [[-1,0],[0,-1],[1,0],[0,1]]
if(pixel.charge) { //when shocked
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
if(isEmpty(i,j,true) == false) {
if(pixelMap[i][j].element == "bacteria") {
if(isEmpty(i,j,true) == false) { deletePixel(i,j) }
} else if(pixelMap[i][j].element == "replacer_bacteria") {
if(pixelMap[i][j].replacement) {
if(isEmpty(i,j,true) == false) { changePixel(pixelMap[i][j],pixelMap[i][j].replacement) }
} else {
if(isEmpty(i,j,true) == false) { deletePixel(i,j) }
}
}
}
}
}
}
},
category: "special",
state: "solid",
density: 3000,
conduct: elements.water.conduct + 0.1,
}
//REPLACE ALL
elements.replacer_bacteria.tempHigh = 10000000000;
elements.replacer_bacteria.stateHigh = "replace_all";
elements.replace_all = {
color: "#ef7f3f",
behavior: behaviors.WALL,
tick: function(pixel) {
if(pixel.charge) { //when shocked
//console.log("ouch")
if(!outOfBounds(pixel.x,pixel.y+1) && !isEmpty(pixel.x,pixel.y+1) && !outOfBounds(pixel.x,pixel.y-1) && !isEmpty(pixel.x,pixel.y-1)) { //check if pixels exists above and below to store the elements of
//console.log("elems stored")
if(pixelMap[pixel.x][pixel.y-1].element != pixel.element) { //exclude self and only fire once
//console.log("self excluded from replacement")
pixel.target = pixelMap[pixel.x][pixel.y+1].element
//console.log("target set to " + pixel.target)
pixel.replacement = pixelMap[pixel.x][pixel.y-1].element
//console.log("replacement set to " + pixel.replacement)
pixel.active = true
//console.log("replacer activated")
}
}
}
if(pixel.active) {
//console.log("is this on now?")
if(pixel.target && pixel.replacement) { //safety
//console.log("target and replacement exist, iterating...")
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
if(isEmpty(i,j,true) == false) {
//console.log("pixel at (" + i + "," + j + ") exists")
if(pixelMap[i][j].element == pixel.target) {
//console.log(pixel.target + " detected, replacing")
if(isEmpty(i,j,true) == false) { changePixel(pixelMap[i][j],pixel.replacement) }
}
}
}
}
}
pixel.active = false //de-activate
if(pixel.charge) { delete pixel.charge}
if(pixel.chargeCD) { delete pixel.chargeCD}
}
},
category: "special",
state: "solid",
density: 1,
conduct: elements.water.conduct + 0.1,
};
//CONFIGURABLE PIXEL SIZE ##
//The "pixelSize" query parameter sets the size of the pixels; this is inversely proportional to the pixel "resolution", so bigger numbers mean less pixels fit on the screen and smaller numbers mean that more pixels will fit.
//Depending on your screen's size, the default pixelSize is either 5 or 6 (6 on larger screens).
//Making the pixels twice as big will decrease the pixel capacity by *slightly over* 4, and the reverse is also true. (I don't know why that is.)
if(urlParams.get('pixelSize') != null) { //null check
pixelSize = urlParams.get('pixelSize')
if(isNaN(pixelSize) || pixelSize === "" || pixelSize === null) { //NaN check
//Vanilla code
pixelSize = settings.pixelsize || 6;
if (window.innerWidth < 700) {
pixelSize--;
}
}
pixelSize = parseFloat(pixelSize)
pixelSize = Math.min(194.73749999999999,Math.max(pixelSize,0.05))
} else {
//Vanilla code
pixelSize = settings.pixelsize || 6;
if (window.innerWidth < 700) {
pixelSize--;
}
}
//OLD SAVE SYSTEM MOD ##
//used for reasons unrelated to dependencies
try {
if(typeof(rebuildCurrentPixels) !== "function") {
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;
};
};
//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
);
}
}
function zeroToNull(val) {
if(val === 0) { return null };
return val;
};
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,
pixelTicks: pixelTicks,
pixelSize: pixelSize,
settings: settings,
version: 1,
enabledMods: localStorage.enabledMods
};
if(settings.dopressure) {
simulationState.pressureMap = pressureMap
};
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(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);
};
};
};
};
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());
};
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,suppressModdedSaveLoadWarning=false) {
var save = localStorage.getItem("quicksave");
if(!save) {
if(doFailAlert) { alert("No save exists") };
return false;
} else {
clearAll();
rebuildCurrentPixels();
importJsonState(JSON.parse(save),suppressModdedSaveLoadWarning);
if(doSuccessAlert) { alert("Quicksave loaded") };
if(pause) {
paused = true;
document.getElementById("pauseButton").setAttribute("on","true");
} else {
paused = false;
document.getElementById("pauseButton").setAttribute("on","false");
};
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("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,suppressModdedSaveLoadWarning=false) {
//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;
pixelTicks = (json.pixelTicks ?? 0);
//currentPixels = json.currentPixels;
for(i = 0; i < json.pixelMap.length; i++) {
json.pixelMap[i] = json.pixelMap[i].map(x => zeroToNull(x));
};
pixelMap = json.pixelMap;
var settingsExcludedKeys = ["unlocked","suppressModdedSaveLoadWarning"];
if(json.settings) {
for(var key in json.settings) {
if(settingsExcludedKeys.includes(key)) { continue };
settings[key] = json.settings[key];
}
saveSettings
};
if((settings.dopressure) && json.pressureMap) { pressureMap = json.pressureMap };
//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) {
if(!(suppressModdedSaveLoadWarning || settings.suppressModdedSaveLoadWarning)) {
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 simulationAlternatively, copy simulation JSONNo file loader status
One file, please:
Or paste JSONNo text loader statusNo size setter status
Pixel size (rendering only): (Use if the save looks cut off)
`;
elements.save_loader = {
behavior: behaviors.SELFDELETE,
excludeRandom: true,
color: _cc.w.h,
desc: saveLoaderDescription,
};
function formatTempWithAbbreviation(temp) { // temp is Celcius
var _temp;
var suffix;
var unitSetting = settings?.["units"] ?? "m";
switch(unitSetting) {
default:
case "m":
_temp = temp;
suffix = "°C";
break;
case "i":
if(settings.userankine == true) {
_temp = (temp*1.8)+491.67;
suffix = "°R";
} else {
_temp = temp*1.8+32;
suffix = "°F"
};
break;
case "s":
_temp = temp+273.15;
suffix = "°K";
break;
};
var displayTemp = Math.round(_temp);
if(displayTemp > 999999999) {
var shrinkage = (10 ** (Math.floor(Math.log10(_temp)) - 2));
displayTemp = [Math.floor(_temp/shrinkage),"e",Math.log10(shrinkage),suffix].join("");
} else {
displayTemp = Math.round(_temp).toString() + suffix;
};
return displayTemp
};
//Somehow, for some illogical reason, quicksaving causes updateStats to somehow disregard its if-statement and fucking TypeError when you mouse over an empty space; this is an attempt to fix it with overkill-level existence checks.
function updateStats() {
var statsDiv = document.getElementById("stats");
var stats = "x"+mousePos.x+",y"+mousePos.y+"";
stats += "Pxls:" + currentPixels.length+"";
stats += "" + tps+"tps";
if(enabledMods.includes("mods/betterStats.js") && typeof(realTps) !== "undefined") { stats += "" + realTps + "tps" }; //i'm sorry but there's no other way to add compatibility
//THAT CODE WAS MADE BY MOLLTHECODER FROM THEIR betterStats.js MOD
stats += "" + pixelTicks+"";
if((settings.dopressure) && (typeof(width) == "number") && (!(outOfBounds(mousePos.x,mousePos.y)))) {
let _p = getPressureAtPixelCoords(mousePos.x,mousePos.y);
if(_p) {
stats += "P:" + getPressureAtPixelCoords(mousePos.x,mousePos.y).toFixed(2).replace(/\.?0+$/,"")+""
}
};
if ((typeof pixelMap).length === 9) { return; }
if (pixelMap[mousePos.x] !== undefined) {
var currentPixel = pixelMap[mousePos.x][mousePos.y];
if (typeof(currentPixel) !== "undefined" && currentPixel && currentPixel !== undefined && currentPixel.element) {
var displayName = ((elements[currentPixel?.element]?.name || currentPixel?.element) ?? "undefined").toUpperCase();
if(currentPixel?.displayText) { //old way that might have predated vanilla hoverText but now I'm not sure... kept for compatibility just in case
displayName += ` (${currentPixel?.displayText})`
};
stats += "Elem:"+displayName+"";
stats += "Temp:"+formatTempWithAbbreviation(currentPixel.temp)+"";
if (currentPixel.charge) {
stats += "C"+currentPixel.charge+"";
}
if (currentPixel.burning) {
stats += "Burning";
}
if (elements[currentPixel.element].hoverStat) {
stats += ""+elements[currentPixel.element].hoverStat(currentPixel)+"";
}
else if (elements[currentElement].toolHoverStat) {
stats += ""+elements[currentElement].toolHoverStat(currentPixel).toString().replaceAll("<","<")+"";
}
else if (currentPixel.clone) {
stats += ""+currentPixel.clone.toUpperCase()+"";
}
else if (currentPixel.con && currentPixel.con.element) {
stats += ""+currentPixel.con.element.toUpperCase()+"";
}
}
}
if (shiftDown) {
stats += ""+shiftDownTypes[shiftDown]+"";
}
// If the view is not null, show the view in all caps
if (view !== null) {
stats += ""+(viewInfo[view] ? viewInfo[view].name : view)+"";
}
statsDiv.innerHTML = stats;
var _width = getComputedStyle(statsDiv).width;
if(_width !== null) {
_width = parseFloat(_width.match(/[\d\/]+/));
if(_width <= 752) {
statsDiv.style["font-size"] = "50%"
} else if(_width <= 940) {
statsDiv.style["font-size"] = "75%"
}
}
//Force stats bar to be 2 lines tall so it never hides info
var statsBar = document.getElementById("stats");
statsBar.style.height = "3em";
}
//Moved to window.onload where gameDiv should be guaranteed to exist
} catch (error) {
alert(`save_loading error: ${error.toString()}`);
};
//ASSORTED EXPERIMENTS
function radialTest(centerX,centerY,integer,chosenElement,createPixels=true,replacePixels=true,radialColor=false) {
if(!elements[chosenElement]) {
alert("Element " + chosenElement + " doesn't exist!");
return false;
};
integer = Math.round(integer);
for(i = 1; i < width; i++) {
for(j = 1; j < height; j++) {
var distance = pyth(centerX,centerY,i,j);
if(Math.round(distance) % integer == 0) {
if(isEmpty(i,j,false) && createPixels) {
createPixel(chosenElement,i,j);
} else if(!isEmpty(i,j,true) && !outOfBounds(i,j) && replacePixels) {
changePixel(pixelMap[i][j],chosenElement);
};
};
};
};
return true;
};
function rctest(centerX,centerY,integer,chosenElement,createPixels=true,replacePixels=true,distanceScale=1,saturation=50,lightness=50) {
saturation = Math.max(0,Math.min(100,saturation))
lightness = Math.max(0,Math.min(100,lightness))
if(!elements[chosenElement]) {
alert("Element " + chosenElement + " doesn't exist!");
return false;
};
integer = Math.round(integer);
for(i = 1; i < width; i++) {
for(j = 1; j < height; j++) {
var distance = pyth(centerX,centerY,i,j);
if(Math.round(distance) % integer == 0) {
if(isEmpty(i,j,false) && createPixels) {
createPixel(chosenElement,i,j);
var distancePrevariable = Math.round(distance * distanceScale) % 360
pixelMap[i][j].color = `hsl(${distancePrevariable},${saturation}%,${lightness}%)`;
} else if(!isEmpty(i,j,true) && !outOfBounds(i,j) && replacePixels) {
changePixel(pixelMap[i][j],chosenElement);
var distancePrevariable = Math.round(distance * distanceScale) % 360
pixelMap[i][j].color = `hsl(${distancePrevariable},${saturation}%,${lightness}%)`;
};
};
};
};
return true;
};
function canSupportWithEdge(x,y) {
if(outOfBounds(x,y)) { //count edges
return true;
} else {
if(!isEmpty(x,y,true)) { //if there is a pixel
if(elements[pixelMap[x][y].element]?.state === "solid") {
return true;
} else {
return false;
};
};
};
};
/*var csweCharacter = function(x,y) { //Debug function
if(canSupportWithEdge(x,y)) {
return "X";
} else {
return ".";
};
};*/
var powderMovementSnippet = function(pixel) { //Unused
if (!tryMove(pixel, pixel.x, pixel.y+1)) {
if (Math.random() < 0.5) {
if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
tryMove(pixel, pixel.x-1, pixel.y+1);
};
} else {
if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
tryMove(pixel, pixel.x+1, pixel.y+1);
};
};
};
};
var sturdyMovementSnippet = function(pixel) { //readability wrapper
tryMove(pixel, pixel.x, pixel.y+1);
};
if(typeof(includesArray) === "undefined") {
function includesArray(parentArray, testArray) { //from portals.js
for (let i = 0; i < parentArray.length; i++) {
if (parentArray[i].every(function(value, index) { return value === testArray[index]})) {
return true;
};
};
return false;
};
};
ddAnchorArray = [];
distanceScale = 15;
elements.hsl_tool_test = { //with help from ryan
color: ["#cf3030","cf7f30","#cfcf30"],
tool: function(pixel) {
pixel.color = "hsl("+(pixelTicks%360)+",50%,50%)"
},
customColor: true,
category: "color tools", //the toolbar is getting cluttered
excludeRandom: true, //the toolbar is getting cluttered
};
elements.temporal_wall_test = {
color: ["#8f8f8f","3f3f3f"],
behavior: behaviors.WALL,
properties: {
counter: 1,
active: true
},
tick: function(pixel) {
for(i = 0; i < 1; i++) { //dummy for
if(!pixel) {
break;
};
if(pixel.active) {
if(pixel.counter == width) {
pixel.active = false;
};
if(!isEmpty(pixel.counter,pixel.y) || outOfBounds(pixel.counter,pixel.y)) {
pixel.counter++;
} else {
createPixel("wall",pixel.counter,pixel.y);
pixel.counter++;
};
};
};
},
state: "solid",
density: 1000,
category: "special",
};
elements.steel_silk = {
color: ["#DCDEDF", "#C7C9CA", "#B9BBBC"],
tick: function(pixel) {
var px = pixel.x;
var py = pixel.y;
var supportCondition1 = (canSupportWithEdge(px-1,py-1) && canSupportWithEdge(px+1,py-1)) // V shape
var supportCondition2 = (canSupportWithEdge(px-1,py) && canSupportWithEdge(px+1,py)) // - shape
var supportCondition3 = (canSupportWithEdge(px-1,py+1) && canSupportWithEdge(px+1,py+1)) // Λ shape
var supportCondition4 = (canSupportWithEdge(px-1,py+1) && canSupportWithEdge(px+1,py-1)) // / shape
var supportCondition5 = (canSupportWithEdge(px-1,py-1) && canSupportWithEdge(px+1,py+1)) // \ shape
var supportCondition6 = (canSupportWithEdge(px-1,py-1) && canSupportWithEdge(px+1,py)) // '- shape
var supportCondition7 = (canSupportWithEdge(px-1,py+1) && canSupportWithEdge(px+1,py)) // ,- shape
var supportCondition8 = (canSupportWithEdge(px+1,py-1) && canSupportWithEdge(px-1,py)) // -' shape
var supportCondition9 = (canSupportWithEdge(px+1,py+1) && canSupportWithEdge(px-1,py)) // -, shape
//var supportCondition6 = xor(canSupportWithEdge(px-1,py-1),canSupportWithEdge(px+1,py+1)) // one-side support
var supports = (supportCondition1 || supportCondition2 || supportCondition3 || supportCondition4 || supportCondition5 || supportCondition6 || supportCondition7 || supportCondition8 || supportCondition9);
/*if(pixelTicks % 10 == 0) {
console.log(`Pixel at (${px},${py})`);
console.log(`> ${csweCharacter(px-1,py-1)} ${csweCharacter(px+1,py-1)}\n> ${csweCharacter(px-1,py*1)} ${csweCharacter(px+1,py*1)}\n> ${csweCharacter(px-1,py+1)} ${csweCharacter(px+1,py+1)}`);
};*/
if (pixel.start === pixelTicks) {return}
if (pixel.charge && elements[pixel.element].behaviorOn) {
pixelTick(pixel)
};
if(!supports) {
powderMovementSnippet(pixel);
};
},
tempHigh: 1455.5,
stateHigh: ["molten_steel", "molten_steel", "molten_steel", "molten_steel", "molten_steel", "molten_steel", "molten_steel", "molten_steel", "molten_steel", null],
category: "solids",
conduct: 0.48,
hardness: 0.79,
movable: true,
category: "solids",
state: "solid",
density: 6850,
breakInto: "metal_scrap",
};
function distanceScalePrompt() {
var _distanceScale = prompt("Enter the value you want to use");
//value check
if(isNaN(parseFloat(_distanceScale))) {
//empty string
if(_distanceScale === "" || _distanceScale === null) {
alert("No value was specified! Defaulting to 15");
_distanceScale = 15;
} else {
alert("Invalid value! The value must be a number (defaulting to 15)");
_distanceScale = 15;
};
};
_distanceScale = parseFloat(_distanceScale);
distanceScale = _distanceScale;
updateDistanceDisplayDescription();
};
elements.distance_display = {
color: "#00FFFF",
properties: {
distanceGetter: null
},
tick: function(pixel) {
var distance = Infinity;
var oldDistance = Infinity;
//if(!ddAnchorArray) { ddAnchorArray = [] }
/*if(!Array.isArray(ddAnchorArray)) { ddAnchorArray = [] }
for (var i = 1; i < width; i++) { //Find and store all anchor pixels
for (var j = 1; j < height; j++) {
};
};*/
var px = pixel.x;
var py = pixel.y;
if(ddAnchorArray.length > 0) {
for(i = 0; i < ddAnchorArray.length; i++) {
var newX = ddAnchorArray[i][0];
var newY = ddAnchorArray[i][1];
if(isEmpty(newX,newY)) {
ddAnchorArray.splice(i,1);
} else {
var checkPixel = pixelMap[newX][newY];
if(checkPixel.element !== "distance_display_anchor") {
ddAnchorArray.splice(i,1);
} else {
distanceCandidate = pyth(px,py,newX,newY);
if(distanceCandidate < distance) {
distance = pyth(px,py,newX,newY);
};
};
};
};
} else {
distance = null;
};
pixel.distanceGetter = distance;
if(distance !== null) {
var processedDistance = Math.min(255,Math.max(0,Math.round(distance * distanceScale)));
pixel.color = `rgb(0,${processedDistance},255)`;
} else {
pixel.color = `rgb(0,255,255)`;
};
},
category: "machines",
state: "solid",
desc: `It gets more blue the closer it gets to a distance display anchor. The current scale factor is ${distanceScale} (bigger number = smaller blue radius). Click here to open the scale prompt. Note: Info pages do not update automatically and must be closed and reopened to show the changed scale.`,
};
elements.distance_display_anchor = {
color: "#0000FF",
behavior: behaviors.WALL,
tick: function(pixel) {
var px = pixel.x;
var py = pixel.y;
if(!includesArray(ddAnchorArray,[px,py])) {
ddAnchorArray.push([px,py]);
};
pixel.color = "rgb(0,0,255)";
},
category: "machines",
state: "solid",
desc: `Distance display pixels get blue in its distance.`,
};
/*
blackObject = _cc.b.j;
pinkObject = {r: 255, g: 148, b: 255};
elements.black_pink_test = {
color: [_cc.b.h,"#FF94FF"],
behavior: behaviors.WALL,
properties: {
offset: Math.floor(Math.random() * (Math.random() > 0.5 ? -1 : 1) * Math.random() * 15)
},
tick: function(pixel) {
if(typeof(pixel.offset) !== "number") {
pixel.offset = Math.floor(Math.random() * (Math.random() > 0.5 ? -1 : 1) * Math.random() * 15);
};
var fraction = Math.min(1.0,Math.max(0.0,scale(pixel.y,1,height-1,0.0,1.0)));
var color = averageColorObjects(pinkObject,blackObject,fraction);
var offsettedColor = lightenColor(color,pixel.offset,"rgb");
pixel.color = offsettedColor;
},
category: "machines",
state: "solid",
desc: "blackpink in your area",
};
*/
function updateDistanceDisplayDescription() {
elements.distance_display.desc = `It gets more blue the closer it gets to a distance display anchor. The current scale factor is ${distanceScale} (bigger number = smaller blue radius). Click here to open the scale prompt. Note: Info pages do not update automatically and must be closed and reopened to show the changed scale.`;
};
function createDownAtFirstAvailableSpace(element,x) {
//Get the Y of the first empty pixel on a row which is on a full pixel or the bottom of the canvas
//1. map(x => !x) coerces empty pixels' `undefined` values to !false = true, while full pixels are coerced to !true = false
//2. spread with false adds a sentinel value for the bottom of the canvas
//3. slice(1) removes empty (OOB) position at y=0
//4. indexOf(false) always shows the first matching item
//5. an offset I don't understand (probably from that slice) shifts the first match to the empty spot above the first full pixel
var firstEmptyY = [...pixelMap[x].map(obj => !obj),false].slice(1).indexOf(false);
if(firstEmptyY == -1) {
return false;
};
createPixel(element,x,firstEmptyY);
return true;
};
function createReplacingGases(element,x,y) {
if(isEmpty(x,y,false)) {
createPixel(element,x,y);
return true;
};
if(!isEmpty(x,y,true)) {
var isGas = (elements[pixelMap[x][y].element].state == "gas");
if(isGas) {
deletePixel(x,y);
createPixel(element,x,y);
};
return isGas;
};
};
function cdafasIgnoringGas(element,x) {
//Get the Y of the first empty pixel on a row which is on a full pixel or the bottom of the canvas
//1. map(x => !x) coerces empty pixels' `undefined` values to !false = true, while full pixels are coerced to !true = false
//2. spread with false adds a sentinel value for the bottom of the canvas
//3. slice(1) removes empty (OOB) position at y=0
//4. indexOf(false) always shows the first matching item
//5. an offset I don't understand (probably from that slice) shifts the first match to the empty spot above the first full pixel
var firstEmptyY = [...pixelMap[x].map(obj =>!obj || elements[obj.element].state == "gas"),false].slice(1).indexOf(false);
if(firstEmptyY == -1) {
return false;
};
createReplacingGases(element,x,firstEmptyY);
return true;
};
elements.temporal_fire_test = {
color: ["#8f8f8f","3f3f3f"],
behavior: behaviors.WALL,
properties: {
direction: 1,
counter: 1,
active: true,
fromX: null
},
tick: function(pixel) {
if(pixel.fromX == null) {
pixel.fromX = pixel.x;
};
if(!pixel) {
return;
};
if(!pixel.active) {
return;
};
var newX = pixel.fromX + pixel.counter;
if(outOfBounds(newX,1)) {
pixel.active = false;
newX = pixel.fromX + pixel.counter; //reset
pixel.counter = 1;
return;
};
cdafasIgnoringGas("fire",newX);
pixel.counter += pixel.direction;
},
state: "gas",
category: "special",
};
//ASSORTED ORGANIC COMPOUNDS ##
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\
%TODO: Pentyl line physical properties%
\%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
//Most hydrocarbons are fantastically colored for convenience
//Benzene ring
//Benzene is actually yellowish
//For combinations, it will represent a + shift in hue
//Isomerism
//Isomers like isopropane have slightly increased hue and sat
//L/S (left) isomers are darkened and hued up, while D/R (right) isomers are lightened and hued down
//Cis- isomers are darkened and trans- isomers are lightened
//Chain length
//Methyl line is purple
//plus benzene = pink
//Ethyl line is rose
//plus benzene = red
//Propyl line is green
//plus benzene = mint
//Butyl line is cyan
//plus benzene = blue
//Pentyl line is vermillion
//plus benzene = orange
//Alcohols
//Alcohols are paler
//Bond type
//Alkanes are lightest
//Alkenes are darker
//Alkynes are darkest
//Benzene is non-ternary with respect to single vs double bond
//Benzene
elements.benzene = {
color: "#edf099",
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 876,
burn: 80,
burnTime: 20,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","dirty_water","dirty_water"],
reactions: {
"head": { elem2: "cancer", chance: 0.0017},
"body": { elem2: "cancer", chance: 0.0017},
},
tempLow: 5.53,
tempHigh: 80.1,
};
elements.benzene_gas = {
density: 2.77 * airDensity,
};
elements.benzene_ice = {
density: 1012,
};
//Alk*nes and their substituted benzenes
//Single carbon line
//Lowest bond order
//1 carbon = purple
elements.methane.color = "#bfabc9";
elements.liquid_methane ??= {};
elements.liquid_methane.density = 423;
//Methene and methyne don't make sense
//Methanol
elements.methanol = {
color: "#d5ced9",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
"head": { "elem2":"rotten_meat", "chance": 0.8 },
"body": { "elem2":"rotten_meat", "chance": 0.8 },
},
viscosity: 0.56,
//tempHigh: 64.7,
burn: 100,
burnTime: 2,
fireColor: "#b2c5d1",
category: "liquids",
state: "liquid",
density: 792,
stain: -0.25,
}
//Benzene ver.
elements.toluene = {
//meth- purple + benzene hue up = pink
//liquid initial = more vivid
color: "#de76cf",
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 862,
burn: 80,
burnTime: 20,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam"],
reactions: {
"head": { elem2: "cancer", chance: 0.001 }, //unknown/unclassifiable carcinogenicity
"body": { elem2: "cancer", chance: 0.001 },
},
tempHigh: 110.6,
tempLow: -95,
};
elements.toluene_gas = {
density: 3.1 * airDensity,
};
//Double carbon line
//Lowest bond order
//Rose
elements.ethane = {
color: "#cfa3bb",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 872, //artifically raised by 400 degrees to prevent interference with ethylbenzene dehydrogenation
stateHigh: "fire",
reactions: {
"head": { elem2: "rotten_meat", chance: 0.00015},
"body": { elem2: "rotten_meat", chance: 0.00015},
},
tempLow: -88.5,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 1.3562, //absolute density
};
elements.liquid_ethane = {
tempLow: -182.8,
density: 544,
};
//Double bonds
//ethylene = ethene
elements.ethylene = {
color: "#c991b0",
behavior: behaviors.GAS,
state: "gas",
category: "gases",
tempHigh: 425,
stateHigh: "fire",
density: 1.18,
burn: 80,
burnTime: 20,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","steam","steam"],
reactions: {
"head": { elem2: "rotten_meat", chance: 0.0001}, //no mechanism for prolonged exposure causing harm
"body": { elem2: "rotten_meat", chance: 0.0001},
"benzene_gas": { tempMin: 220, elem1: null, elem2: "ethylbenzene_gas" },
},
tempLow: -103.7
};
elements.liquid_ethylene = {
tempLow: -169.2,
density: 577, //unknown solid density
};
//Triple bonds
//acetylene = ethyne
elements.acetylene = {
color: "#b8819f",
behavior: behaviors.GAS,
state: "gas",
category: "gases",
reactions: {
oxygen: { elem1: ["acetylene","oxy_fuel"], elem2: null },
},
tick: function(pixel) { //tick-based autoignition point to trigger acetylene fire properties
if(pixel.temp > 325 && !pixel.burning) {
pixel.burning = true;
};
},
density: 1.1772, //absolute
burn: 100,
burnTime: 10,
burnTempChange: 20,
fireSpawnTemp: 2700, //overheat by 500 degrees to compensate for natural cooling effects
fireSpawnChance: 5, //reduce own flame to reduce said effects from smoke
fireColor: "#5da8fc",
burnInto: ["fire","plasma","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam"],
tempLow: -84,
stateLow: "acetylene_ice",
};
elements.acetylene_ice = {
color: "#ffa8d8",
behavior: behaviors.POWDER,
state: "solid",
category: "states",
reactions: {
liquid_oxygen: { elem1: ["acetylene_ice","oxy_fuel_slush"], elem2: null, changeTemp: false },
oxygen_ice: { elem1: ["acetylene_ice","oxy_fuel_snow"], elem2: null, changeTemp: false },
},
tick: function(pixel) {
if(pixel.temp > 325 && !pixel.burning) {
pixel.burning = true;
};
},
density: 720,
burn: 25, //cold
burnTime: 5,
burnTempChange: 20,
fireSpawnTemp: 2700,
fireSpawnChance: 5,
fireColor: "#5da8fc",
burnInto: ["fire","plasma","fire","fire","fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam"],
"temp": -100,
"tempHigh": -84,
"stateHigh": "acetylene",
hidden: true,
};
//Ethanol (Vanilla)
elements.alcohol.name = "ethanol";
elements.alcohol.color = "#d4b9c8";
elements.alcohol.viscosity = 1.144;
elements.water.viscosity = 1; //define reference viscosity of 1
//Benzene ver.
elements.ethylbenzene = {
color: "#de7676",
//ethene's rose plus benzene's yellow = red
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 867,
burn: 75,
burnTime: 25,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
tempHigh: 136,
tempLow: -95,
};
elements.ethylbenzene_gas = {
density: 3.7 * airDensity,
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
"steam": { tempMin: 600, elem1: ["styrene","hydrogen","styrene","hydrogen","styrene","hydrogen","styrene","hydrogen","styrene","hydrogen","styrene","hydrogen","styrene","hydrogen","styrene","hydrogen","toluene","benzene","methane","ethane"], elem2: "steam", temp1: -3, temp2: -3 },
},
};
//Triple carbon line
//Single bond
elements.propane.color = "#b8d4a5";
elements.propane.tempHigh = 493;
//Double bond
elements.propylene = { //propene
color: "#a4c48d",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 458,
stateHigh: "fire",
tempLow: -47.6,
burn: 100,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 1.745, //abs. at 25*C
};
elements.liquid_propylene = {
tempLow: -185.2,
density: 613.9,
};
//Triple bond
elements.propyne = { //also methylacetylene
color: "#8bad72",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 340,
stateHigh: "fire",
tempLow: -25.15,
burn: 85,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 1.6656, //abs. at 25*C
};
elements.liquid_propylene = {
tempLow: -102.7,
density: 671.963,
};
//Propanol
//Linear
elements.propanol = {
color: "#d4e0cc",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 2.23, //EXERCISE 8: VISCOSITY OF PURE LIQUIDS AND SOLUTIONS
//tempHigh: 97,
burn: 100,
burnTime: 3,
fireColor: "#ced8de",
category: "liquids",
state: "liquid",
density: 803,
stain: -0.25,
}
//Triangular
elements.isopropanol = {
color: "#d1e4c8",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 2.38, //http://www.ddbst.com/en/EED/PCP/VIS_C95.php (293K is close enough)
//tempHigh: 82.5,
burn: 100,
burnTime: 3,
fireColor: "#d1c958",
category: "liquids",
state: "liquid",
density: 786,
stain: -0.25,
}
//Benzene ver.
//more obscure organic compound
elements.propylbenzene = {
color: "#92debd",
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 862,
burn: 75,
burnTime: 25,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
reactions: {
//we can probably still assume that it's carcinogenic because it has the phenyl group
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
tempHigh: 159.2,
tempLow: -99.5,
};
elements.propylbenzene_gas = {
density: 4.14 * airDensity,
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
};
//Quadruple carbon line
//Single bond
elements.butane = {
color: "#a7dbd9",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 287,
stateHigh: "fire",
reactions: {
"head": { elem2: "rotten_meat", chance: 0.00015},
"body": { elem2: "rotten_meat", chance: 0.00015},
},
tempLow: 1,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.076 * airDensity,
};
elements.liquid_butane = {
tempLow: -134,
density: 604,
};
elements.isobutane = {
color: "#9cbddb",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 460,
stateHigh: "fire",
reactions: {
"head": { elem2: "rotten_meat", chance: 0.00015},
"body": { elem2: "rotten_meat", chance: 0.00015},
},
tempLow: -11.7,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.51,
};
elements.liquid_isobutane = {
tempLow: -159.42,
density: 563,
};
//Double bond
elements.butylene = { //butene
name: "1-butylene",
color: "#95cfcd",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 385,
stateHigh: "fire",
tempLow: -6.47,
burn: 100,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
burnInto: ["fire","carbon_dioxide","carbon_dioxide","steam","steam"],
state: "gas",
density: 1.93 * airDensity,
};
elements.liquid_butylene = {
tempLow: -185.3,
density: 625.63,
};
elements.water.reactions.butylene = {
elem1: ["l_secbutanol","r_secbutanol"], elem2: ["l_secbutanol","r_secbutanol"]
}; elements.water.reactions.liquid_butylene = elements.water.reactions.butylene;
elements.trans_2_butylene = {
name: "t-butylene-2",
color: "#a1c9d4",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 324,
stateHigh: "fire",
tempLow: 0.8,
burn: 85,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2 * airDensity,
};
elements.liquid_trans_2_butylene = {
tempLow: -105.5,
density: 626,
};
elements.water.reactions.trans_2_butylene = {
elem1: ["l_secbutanol","r_secbutanol"], elem2: ["l_secbutanol","r_secbutanol"]
}; elements.water.reactions.liquid_trans_2_butylene = elements.water.reactions.trans_2_butylene;
elements.cis_2_butylene = {
name: "c-butylene-2",
color: "#8cbcca",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 324,
stateHigh: "fire",
tempLow: 3.7,
burn: 85,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2 * airDensity,
};
elements.liquid_cis_2_butylene = {
tempLow: -138.9,
density: 641,
};
elements.water.reactions.cis_2_butylene = {
elem1: ["l_secbutanol","r_secbutanol"], elem2: ["l_secbutanol","r_secbutanol"]
}; elements.water.reactions.liquid_cis_2_butylene = elements.water.reactions.cis_2_butylene;
//Triple bond
elements.butyne = {
color: "#81a2b3",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 444, //Unknown autoignition
stateHigh: "fire",
tempLow: 8.08,
burn: 100,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.12 * airDensity, //made-up due to also unknown vapor density
};
elements.liquid_butyne = {
tempLow: -125.7,
density: 678.3,
};
//Alcohol
//Line
elements.butanol = {
color: "#d0e7e6",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 3.0011, //https://www.sciencedirect.com/science/article/abs/pii/S0021961416301446?via%3Dihub
tempHigh: 117.7,
tempLow: -89.8,
burn: 100,
burnTime: 3,
category: "liquids",
state: "liquid",
density: 810,
stain: -0.25,
}
//Hydroxyl in internal carbon (like isopropanol)
//Left
elements.l_secbutanol = {
color: "#b9dbe4",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 3.0011, //https://www.sciencedirect.com/science/article/abs/pii/S0021961416301446?via%3Dihub
tempHigh: 100,
tempLow: -115,
burn: 100,
burnTime: 3,
category: "liquids",
state: "liquid",
density: 810,
stain: -0.25,
}
//Right
elements.r_secbutanol = {
color: "#def1f2",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 3.0011, //https://www.sciencedirect.com/science/article/abs/pii/S0021961416301446?via%3Dihub
tempHigh: 100,
tempLow: -115,
burn: 100,
burnTime: 3,
category: "liquids",
state: "liquid",
density: 810,
stain: -0.25,
};
//Racemic
elements.secbutanol = {
color: "#cce7ea",
behavior: [
"XX|XX|XX",
"M2|CH:r_secbutanol,l_secbutanol|M2",
"M1|M1|M1"
],
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 3.0011, //https://www.sciencedirect.com/science/article/abs/pii/S0021961416301446?via%3Dihub
tempHigh: 100,
stateHigh: ["l_secbutanol_gas","r_secbutanol_gas"],
tempLow: -115,
stateLow: ["l_secbutanol_ice","r_secbutanol_ice"],
burn: 100,
burnTime: 3,
category: "liquids",
state: "liquid",
density: 810,
stain: -0.25,
};
//Branched chain
elements.isobutanol = {
color: "#c9e3ee",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 3.0011, //https://www.sciencedirect.com/science/article/abs/pii/S0021961416301446?via%3Dihub
tempHigh: 107.89,
tempLow: -108,
burn: 100,
burnTime: 3,
category: "liquids",
state: "liquid",
density: 810,
stain: -0.25,
}
//Branched with internal hydroxyl
elements.tertbutanol = {
color: "#c5def1",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 3.0011, //https://www.sciencedirect.com/science/article/abs/pii/S0021961416301446?via%3Dihub
tempHigh: 83,
temp: 40,
tempLow: 25,
burn: 100,
burnTime: 3,
category: "liquids",
state: "liquid",
density: 810,
stain: -0.25,
}
//Benzene ver.
elements.butylbenzene = {
color: "#7b8ae0",
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 860.1,
burn: 75,
burnTime: 25,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
tempHigh: 183.3,
tempLow: -87.9,
};
elements.butylbenzene_gas = {
density: 4.6 * airDensity,
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
};
elements.cumene = {
color: "#8873e6",
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 862,
burn: 75,
density: 0.777,
burnTime: 25,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam"],
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
tempHigh: 152,
tempLow: -96,
};
elements.cumene_gas = {
density: 4.1 * airDensity,
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
},
};
//Quintuple carbon line
//Single bond
elements.pentane = {
color: "#b5685b",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 533,
stateHigh: "fire",
reactions: {
"head": { elem2: "rotten_meat", chance: 0.00015},
"body": { elem2: "rotten_meat", chance: 0.00015},
},
tempLow: 36.1,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.48 * airDensity,
};
elements.liquid_pentane = {
color: "#a62711",
tempLow: -130.2,
density: 626,
};
elements.isopentane = {
color: "#bb6c54",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 427,
stateHigh: "fire",
reactions: {
"head": { elem2: "rotten_meat", chance: 0.00015},
"body": { elem2: "rotten_meat", chance: 0.00015},
},
tempLow: -11.7,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.48 * airDensity,
};
elements.liquid_isopentane = {
color: "#ab320d",
tempLow: -160,
density: 616,
};
elements.neopentane = {
color: "#c1724e",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 427,
stateHigh: "fire",
reactions: {
"head": { elem2: "rotten_meat", chance: 0.00015},
"body": { elem2: "rotten_meat", chance: 0.00015},
},
tempLow: 9.5,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 3.255,
};
elements.liquid_neopentane = {
color: "#af3d08",
tempLow: -16.5,
density: 601.172,
};
//Double bond
elements.pentylene = { //pentene
name: "1-pentylene",
color: "#af5a4b",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 527,
stateHigh: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
tempLow: 30,
temp: 40,
burn: 100,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.4 * airDensity,
};
elements.liquid_pentylene = {
tempLow: -165.2,
density: 640,
};
elements.trans_2_pentylene = {
name: "t-pentylene-2",
color: "#924b3f",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 324, //Unknown
stateHigh: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
tempLow: 36.3,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.4 * airDensity,
};
elements.liquid_trans_2_pentylene = {
tempLow: -140.2,
density: 643.1,
};
elements.cis_2_pentylene = {
name: "c-pentylene-2",
color: "#9d5143",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 324, //Unknown
stateHigh: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
tempLow: 36.9,
burn: 85,
burnTime: 5,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","steam","steam"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2 * airDensity,
};
elements.liquid_cis_2_pentylene = {
tempLow: -151.4,
density: 655.6,
};
//Triple bond
elements.pentyne = {
name: "1-pentyne",
color: "#9d5143",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 454, //Unknown
stateHigh: ["fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","oxygen","oxygen","oxygen"],
tempLow: 40.2,
temp: 55,
burn: 100,
burnTime: 5,
burnInto: ["fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","oxygen","oxygen","oxygen"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.6 * airDensity, //made-up due to also unknown vapor density
};
elements.liquid_1_pentyne = {
tempLow: -105.5,
density: 691,
};
elements.pentyne_2 = {
name: "2-pentyne",
color: "#9d5143",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 454, //Unknown
stateHigh: ["fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","oxygen","oxygen","oxygen"],
tempLow: 56.5,
temp: 65,
burn: 70,
burnTime: 5,
burnInto: ["fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","oxygen","oxygen","oxygen"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.6 * airDensity, //made-up due to also unknown vapor density
};
elements.liquid_pentyne_2 = {
tempLow: -109,
density: 710,
};
elements.isopentyne = {
color: "#a6533a",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 454, //Unknown
stateHigh: ["fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","oxygen","oxygen","oxygen"],
tempLow: 29.5,
temp: 40,
burn: 70,
burnTime: 5,
burnInto: ["fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_dioxide","oxygen","oxygen","oxygen"],
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.6 * airDensity, //made-up due to also unknown vapor density
};
elements.liquid_isopentyne = {
tempLow: -89.7,
density: 666,
};
//Alcohol
//Fuck no I'm not doing 8 isomers
//Benzene ver.
//i'm tired
//Vodka
elements.alcohol.reactions.water = { //50% is close enough to the standard 40%
elem1: "vodka",
elem2: "vodka",
}
elements.vodka = {
color: "#9FAEC5",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null, chance: 0.05 }, //it still adds up over ticks
"plague": { "elem2":null, chance: 0.05 },
},
tick: function(pixel) {
//Thermal split
if(pixel.temp > elements.alcohol.tempHigh && exposedToAir(pixel)) {
var randomNeighbor = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)]
var rnx = randomNeighbor[0]
var rny = randomNeighbor[1]
if(isEmpty(pixel.x+rnx, pixel.y+rny, false)) {
createPixel("alcohol_gas", pixel.x+rnx, pixel.y+rny);
changePixel(pixel,pixel.temp >= 100 ? "steam" : "water",false);
}
}
},
tempLow: -36,
category: "liquids",
state: "liquid",
density: 914,
stain: -0.25,
}
//Other organic compounds
//Oxygen plus acetylene mixture
elements.oxy_fuel = {
color: "#ff5eb4",
behavior: behaviors.GAS,
state: "gas",
category: "gases",
tick: function(pixel) { //tick-based autoignition point to trigger acetylene fire properties
if(pixel.temp > 325 && !pixel.burning) {
pixel.burning = true;
};
},
density: 1.25,
burn: 100,
burnTime: 10,
burnTempChange: 330,
fireSpawnTemp: 3100,
fireSpawnChance: 5, //reduce own flame to reduce said effects from smoke
fireElement: ["fire","plasma"],
fireColor: "#5e91ff",
burnInto: ["fire","plasma"],
tempLow: -84,
stateLow: ["oxygen","oxygen","acetylene_ice"],
hidden: true,
};
elements.oxy_fuel_slush = {
color: "#d85fed",
behavior: behaviors.LIQUID,
viscosity: 100,
state: "liquid",
category: "liquids",
tick: function(pixel) { //tick-based autoignition point to trigger acetylene fire properties
if(pixel.temp > 325 && !pixel.burning) {
pixel.burning = true;
};
},
density: 873, //made-up
burn: 100,
burnTime: 10,
burnTempChange: 330,
fireSpawnTemp: 3100,
fireSpawnChance: 5, //reduce own flame to reduce said effects from smoke
fireElement: ["oxy_fuel","fire","plasma"],
fireColor: "#5e91ff",
burnInto: "oxy_fuel",
temp: -200,
tempLow: -218.8,
stateLow: "oxy_fuel_snow",
tempHigh: -183.94,
stateHigh: ["oxygen","oxygen","acetylene_ice"],
hidden: true,
};
elements.oxy_fuel_snow = {
color: "#dd9afc",
behavior: behaviors.POWDER,
state: "solid",
category: "powders",
tick: function(pixel) { //tick-based autoignition point to trigger acetylene fire properties
if(pixel.temp > 325 && !pixel.burning) {
pixel.burning = true;
};
},
density: 912, //made-up
burn: 100,
temp: -250,
burnTime: 10,
burnTempChange: 330,
fireSpawnTemp: 3100,
fireSpawnChance: 5, //reduce own flame to reduce said effects from smoke
fireElement: ["fire","plasma"],
fireColor: "#5e91ff",
burnInto: "oxy_fuel",
tempHigh: -218.8,
stateHigh: "oxy_fuel_slush",
hidden: true,
};
//Styrene and its polymer
elements.styrene = {
color: "#d9d6c3",
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
density: 909,
burn: 80,
burnTime: 25,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","steam"],
reactions: {
"head": { elem2: "cancer", chance: 0.0017 },
"body": { elem2: "cancer", chance: 0.0017 },
"hydrogen": { elem1: "ethylbenzene", elem2: null, chance: 0.005 },
"benzoyl_peroxide": { elem1: "polystyrene", elem2: "benzoic_acid" },
"polystyrene": { elem1: "polystyrene" },
"molten_polystyrene": { elem1: "polystyrene" },
},
tempLow: -30,
tempHigh: 145,
};
elements.styrene_gas = {
density: 3.6 * airDensity,
};
elements.polystyrene = {
color: "#f5f5f5",
behavior: behaviors.WALL,
state: "solid",
category: "solids",
density: 965,
tempHigh: 100,
//above this it does thermoplastic things
};
elements.molten_polystyrene = {
color: "#e3e3e3",
tempLow: 100,
behavior: behaviors.LIQUID,
viscosity: 1000,
reactions: {
"foam": { elem1: "styrofoam", elem2: ["styrofoam","molten_polystyrene","molten_polystyrene","molten_polystyrene"] },
},
};
elements.styrofoam = {
color: "#f5f5f5",
behavior: behaviors.WALL,
state: "solid",
category: "solids",
density: 50,
breakInto: ["packing_peanuts","polystyrene","foam","foam"],
cutInto: "packing_peanuts",
tempHigh: 160, //reaction grace period
stateHigh: [null,null,null,"molten_polystyrene"],
};
elements.packing_peanuts = {
color: "#f1f1f1",
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
breakInto: ["polystyrene","foam","foam"],
density: 40,
tempHigh: 160, //reaction grace period
stateHigh: [null,null,null,null,"molten_polystyrene"],
};
//Benzoyl peroxide
elements.benzoyl_peroxide = {
color: "#ededed",
behavior: behaviors.POWDER,
state: "solid",
category: "powders",
density: 1.334,
tempHigh: 103,
stateHigh: ["benzoic_acid","benzoic_acid","benzoic_acid","fire","explosion"],
};
//Benzoic acid
elements.benzoic_acid = {
color: "#c9c9c9",
behavior: behaviors.POWDER,
state: "solid",
category: "powders",
density: 1.2659,
tempHigh: 122,
};
elements.molten_benzoic_acid = {
behavior: behaviors.LIQUID,
color: "#b5b2b0",
tempHigh: 250,
density: 1074.9,
reactions: {
"molten_copper_sulfate": { tempMin: 200, elem1: ["phenol","phenol","carbon_dioxide"] }, //using air oxygen
},
};
elements.benzoic_acid_gas = {
density: 4.21 * airDensity,
reactions: {
"oxygen": { tempMin: 350, elem1: "phenol", elem2: "carbon_dioxide" },
"molten_copper_sulfate": { tempMin: 200, elem1: ["phenol","phenol","carbon_dioxide"] },
},
};
//Phenol
elements.phenol = {
color: "#dbd3d3",
behavior: behaviors.POWDER,
state: "solid",
category: "powders",
density: 1070,
burn: 40,
burnTime: 70,
burnInto: ["fire","fire","carbon_dioxide","carbon_dioxide","carbon_dioxide","steam","steam","steam","dioxin"],
reactions: {
"head": { elem2: "rotten_meat", chance: 0.003 },
"body": { elem2: "rotten_meat", chance: 0.003 },
},
tempHigh: 40.5,
tempLow: -95,
};
elements.molten_phenol = {
color: "#cfc2c2",
behavior: behaviors.LIQUID,
viscosity: 8,
reactions: {
"head": { elem2: "rotten_meat", chance: 0.003 },
"body": { elem2: "rotten_meat", chance: 0.003 },
},
tempHigh: 181.7,
};
elements.phenol_gas = {
reactions: {
"head": { elem2: "rotten_meat", chance: 0.003 },
"body": { elem2: "rotten_meat", chance: 0.003 },
},
density: 3.24,
};
//Inorganic compounds
runAfterAutogen(function() {
var waters = searchElements("water").filter(function(name) { return getState(name) == "liquid" });
var whitelistWaters = ["hail","rime","cloud","rain_cloud","thunder_cloud","snow_cloud","hail_cloud","rain_cloud_cloud","snow_cloud_cloud","hail_cloud_cloud","cloud_cloud","heaviest_water_cloud","heaviest_snow_cloud","snow_cloud_floater","jinsoulite","jinsoulite_gas","jinsoulite_powder","molten_jinsoulite"];
var jvoWaters = Object.keys(jinsouliteValueObject).filter(function(name) { return !(name.includes("bomb")) });
var coldWaters = (getStateLow(waters,true) ?? []).filter(
function(name) { return typeof(name) == "string" }
);
var colderWaters = (getStateLow(coldWaters,true) ?? []).filter(
function(name) { return typeof(name) == "string" }
);
var hotWaters = (getStateHigh(waters,true) ?? []).filter(
function(name) { return typeof(name) == "string" }
);
var brokenColdWaters = (getBreakInto(coldWaters,true) ?? []).filter(
function(name) { return typeof(name) == "string" }
);
var coldBrokenColdWaters = (getStateLow(brokenColdWaters,true) ?? []).filter(
function(name) { return typeof(name) == "string" }
);
wateroids = [waters,coldWaters,colderWaters,hotWaters,brokenColdWaters,coldBrokenColdWaters,whitelistWaters,jvoWaters].flat()
//moved vivite-related code to where it happens
for(var i = 0; i < wateroids.length; i++) {
if(elements[wateroids[i]]) { elements[wateroids[i]].noViviteSlag = true };
};
});
//Hydrogen sulfide (in chem.js)
_h_2s = ["hydrogen_sulfide","liquid_hydrogen_sulfide","hydrogen_sulfide_ice"];
runAfterLoad(function() {
elements.hydrogen_sulfide.density = 1.19 * airDensity;
elements.hydrogen_sulfide.reactions ??= {};
elements.hydrogen_sulfide.reactions.head = { elem2: "rotten_meat", chance: 0.4};
elements.hydrogen_sulfide.fireColor = { elem2: "rotten_meat", chance: 0.4};
elements.hydrogen_sulfide.tempHigh = 1200;
elements.hydrogen_sulfide.stateHigh = ["sulfur_gas","steam"];
delete elements.sulfur_dioxide.reactions.water;
delete elements.sulfur_dioxide.reactions.steam;
delete elements.water.reactions.sulfur;
elements.sulfur_dioxide.tick = function(pixel) {
var neighbors = adjacentCoords.map(offsetPair => pixelMap[pixel.x+offsetPair[0]]?.[pixel.y+offsetPair[1]]).filter(function(pixelOrUndefined) { return typeof(pixelOrUndefined) == "object" });
if(neighbors.length < 2) { return };
var neighboringElements = neighbors.filter(function(px) { return !!px }).map(x => x.element);
var waterNeighbor = null;
var sulfideNeighbor = null;
for(var i = 0; i < neighboringElements.length; i++) {
if(_h_2s.includes(neighboringElements[i])) {
sulfideNeighbor = adjacentCoords[i];
};
if(wateroids.includes(neighboringElements[i])) {
waterNeighbor = adjacentCoords[i];
};
if(sulfideNeighbor && waterNeighbor) {
if(sulfideNeighbor !== undefined && sulfideNeighbor?.x && sulfideNeighbor?.y) {
if(!sulfideNeighbor || isEmpty(sulfideNeighbor?.x,sulfideNeighbor?.y,true)) { return };
changePixel(sulfideNeighbor,getStateAtTemp("sulfur",pixel.temp));
changePixel(pixel,getStateAtTemp("water",pixel.temp));
}
}
}
}
});
//Carbon monoxide
elements.carbon_monoxide = {
color: "#8f8f8f",
behavior: behaviors.GAS,
state: "gas",
category: "gases",
density: 1.145,
reactions: {
"head": { elem2: "rotten_meat", chance: 0.0017},
"body": { elem2: "rotten_meat", chance: 0.0017},
},
tempLow: -191.5,
};
elements.liquid_carbon_monoxide = {
tempLow: -205.02,
density: 789, //unknown solid density
};
//Water
elements.steam.reactions ??= {};
elements.steam.reactions.charcoal = { tempMin: 680, elem1: "hydrogen", elem2: "carbon_monoxide" };
elements.steam.reactions.diamond = { tempMin: 680, elem1: "hydrogen", elem2: "carbon_monoxide" };
elements.diamond.tempHigh = 10000; elements.diamond.stateHigh = "carbon_dioxide" //not really that high
//Oil refining
delete elements.oil.tempHigh;
function liquidMoveCustomViscosity(pixel,viscosity) {
if (pixel.start === pixelTicks) {return}
if (pixel.charge && elements[pixel.element].behaviorOn) {
pixelTick(pixel)
}
var viscosityPass = ((Math.random()*100) < 100 / Math.pow(viscosity, 0.25));
if (!viscosityPass) {
var move1Spots = [
[pixel.x, pixel.y+1]
]
}
else {
var move1Spots = [
[pixel.x+1, pixel.y+1],
[pixel.x, pixel.y+1],
[pixel.x-1, pixel.y+1],
]
}
var moved = false;
for (var i = 0; i < move1Spots.length; i++) {
var coords = move1Spots[Math.floor(Math.random()*move1Spots.length)];
if (tryMove(pixel, coords[0], coords[1])) { moved = true; break; }
else { move1Spots.splice(move1Spots.indexOf(coords), 1); }
}
if (!moved) {
if (viscosityPass) {
if (Math.random() < 0.5) {
if (!tryMove(pixel, pixel.x+1, pixel.y)) {
tryMove(pixel, pixel.x-1, pixel.y);
}
} else {
if (!tryMove(pixel, pixel.x-1, pixel.y)) {
tryMove(pixel, pixel.x+1, pixel.y);
}
}
}
}
doDefaults(pixel);
};
elements.light_petroleum_fuel_gas = { //it's not liquified, and sandboxels doesn't even have a pressure system, and there is no generic name for uncompressed, gaseous "L"PG, so we need a different name
burn: 100,
burnTime: 10,
color: "#b5b5b3",
density: 3.5,
tempLow: -44,
tick: function(pixel) {
if (pixel.temp >= 495 && !pixel.burning) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
},
burnInto: "explosion,explosion,ignited_gas,fire,fire,fire,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(","),
state: "gas",
behavior: behaviors.GAS,
};
elements.liquid_light_petroleum_fuel = {
burn: 50,
burnTime: 165,
fireElement: ["light_petroleum_fuel_gas","fire","fire"],
burnInto: "ignited_gas,fire,fire,smoke,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(","),
tempLow: -180 //based off of ethane
}
elements.lamp_oil.tempHigh = 170;
elements.lamp_oil.stateHigh = "lamp_oil_gas";
elements.lamp_oil.density = 810;
elements.lamp_oil.name = "kerosene";
elements.lamp_oil.forceAutoGen = true;
elements.lamp_oil.burnInto = "smoke,smoke,fire,fire,fire,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",");
elements.lamp_oil_gas = {
name: "kerosene gas",
burn: 100,
density: 4.5,
tick: elements.lamp_oil.tick,
tempLow: 170,
stateLow: "lamp_oil",
burnInto: "explosion,smoke,smoke,fire,fire,fire,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",")
};
elements.gasoline = {
color: "#d1cf9d",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if (pixel.temp > 263 && !pixel.burning) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
},
reactions: {
"styrofoam": { elem1: ["gasoline","gasoline","gasoline","gasoline","napalm"], elem2: null }, //behold, the joke
"packing_peanuts": { elem1: ["gasoline","gasoline","gasoline","gasoline","napalm"], elem2: null },
"polystyrene": { elem1: "napalm", elem2: ["polystyrene","polystyrene",null] },
"molten_polystyrene": { elem1: "napalm", elem2: ["molten_polystyrene","molten_polystyrene",null] },
"glue": {elem2:null, chance:0.05},
"wax": {elem2:null, chance:0.005},
"melted_wax": {elem2:null, chance:0.025},
},
forceAutoGen: true,
category: "liquids",
tempHigh: 70,
tempLow: -60,
burn: 20,
temp: 20,
burnTime: 500,
burnInto: "fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(","),
viscosity: 7.04,
state: "liquid",
density: 755,
alias: "petrol"
};
elements.gasoline_gas = {
burn: 100,
burnTime: 10,
density: 3.5,
tick: elements.gasoline.tick,
burnInto: "explosion,fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",")
};
elements.naphtha = {
color: "#d1d1d1",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if (pixel.temp > 270 && !pixel.burning) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
},
reactions: {
"styrofoam": { elem1: ["naphtha","naphtha","naphtha","naphtha","napalm"], elem2: null },
"polystyrene": { elem1: "napalm", elem2: ["polystyrene","polystyrene",null] },
"molten_polystyrene": { elem1: "napalm", elem2: ["molten_polystyrene","molten_polystyrene",null] },
"glue": {elem2:null, chance:0.05},
"wax": {elem2:null, chance:0.005},
"melted_wax": {elem2:null, chance:0.025},
},
category: "liquids",
tempHigh: 120,
tempLow: -30,
forceAutoGen: true,
burn: 80,
burnTime: 500,
burnInto: "fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(","),
viscosity: 5.77,
state: "liquid",
density: 740
};
elements.naphtha_gas = {
burn: 100,
burnTime: 10,
density: 3.5,
tick: elements.naphtha.tick,
burnInto: "explosion,fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",")
};
elements.diesel = {
color: "#d3d9b4",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if (pixel.temp > 300 && !pixel.burning) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
},
reactions: {
"glue": {elem2:null, chance:0.05},
"wax": {elem2:null, chance:0.005},
"melted_wax": {elem2:null, chance:0.025},
},
category: "liquids",
tempHigh: 260,
forceAutoGen: true,
tempLow: -25,
burn: 20,
burnTime: 500,
burnInto: "fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(","),
viscosity: 7.04,
state: "liquid",
density: 755,
};
elements.diesel_gas = {
burn: 100,
burnTime: 12,
density: 3.5,
tick: elements.diesel.tick,
burnInto: "explosion,fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",")
};
elements.lubricating_oil = {
color: "#d3d9b4",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if (pixel.temp > 450 && !pixel.burning) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
},
category: "liquids",
tempHigh: 350,
tempLow: -40,
burn: 20,
burnTime: 600,
forceAutoGen: true,
burnInto: "fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(","),
viscosity: 7.04,
state: "liquid",
density: 800,
};
elements.lubricating_oil_gas = {
burn: 100,
burnTime: 13,
density: 3.5,
tick: elements.lubricating_oil.tick,
burnInto: "explosion,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",")
};
elements.heavy_fuel_oil = {
color: "#1c1a18",
stain: 0.3,
behavior: behaviors.LIQUID,
tick: function(pixel) {
if (pixel.temp > 407 && !pixel.burning) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
};
if(pixel.burning && Math.random() < 0.01) {
var emptyNeighbors = [];
for(i = 0; i < adjacentCoords.length; i++) {
if(isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],false)) {
emptyNeighbors.push(adjacentCoords[i]);
};
};
if(emptyNeighbors.length > 0) {
var randomEmptyNeighbor = emptyNeighbors[Math.floor(Math.random() * emptyNeighbors.length)];
createPixelReturn(["smoke","carbon_dioxide"],pixel.x+randomEmptyNeighbor[0],pixel.y+randomEmptyNeighbor[1]).temp = pixel.temp
};
}
},
reactions: {
"polystyrene": { elem1: "napalm", elem2: "napalm", chance:0.05 }, //the joke
"glue": {elem2:null, chance:0.05},
"wax": {elem2:null, chance:0.005},
"melted_wax": {elem2:null, chance:0.025},
},
category: "liquids",
tempHigh: 300,
forceAutoGen: true,
tempLow: 0,
burn: 10,
viscosity: 700,
burnTime: 800,
fireElement: ["fire","fire","fire","smoke","smoke","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_monoxide","carbon_monoxide","carbon_monoxide","sulfur_dioxide","sulfur_trioxide_gas","poison_gas"],
burnInto: "fire,fire,fire,fire,fire,fire,ash,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,poison_gas".split(","),
viscosity: 500,
state: "liquid",
density: 755,
alias: "petrol"
};
elements.heavy_fuel_oil_gas = {
burn: 80,
burnTime: 60,
density: 2.5,
tick: elements.heavy_fuel_oil.tick,
fireElement: ["explosion","fire","fire","fire","smoke","smoke","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_monoxide","carbon_monoxide","carbon_monoxide","sulfur_dioxide","sulfur_trioxide_gas","poison_gas"],
burnInto: "fire,fire,fire,fire,fire,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,steam,steam".split(",")
};
elements.bitumen = {
color: "#0d0c0c",
grain: 1/3,
tick: function(pixel) {
var viscosity = 1e16 / (1.09 ** pixel.temp);
liquidMoveCustomViscosity(pixel,viscosity)
},
reactions: {
"polystyrene": { elem1: "napalm", elem2: "napalm", chance:0.05 }, //the joke
"glue": {elem2:null, chance:0.05},
"wax": {elem2:null, chance:0.005},
"melted_wax": {elem2:null, chance:0.025},
},
category: "liquids",
tempHigh: 750,
stateHigh: ["bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","bitumen","fire","fire","fire","smoke","smoke","smoke","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_monoxide","carbon_monoxide","carbon_monoxide","sulfur_dioxide","sulfur_trioxide_gas","poison_gas"],
burn: 2,
burnTime: 800,
fireElement: ["fire","fire","fire","smoke","smoke","smoke","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_monoxide","carbon_monoxide","carbon_monoxide","sulfur_dioxide","sulfur_trioxide_gas","poison_gas"],
burnInto: "fire,fire,fire,fire,fire,fire,ash,ash,ash,carbon_monoxide,carbon_monoxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,carbon_dioxide,steam,steam,steam,poison_gas".split(","),
viscosity: 7.04,
state: "liquid",
density: 1050,
reactions: {
gravel: { elem1: "asphalt", elem2: "asphalt" }
}
};
elements.asphalt ={
color: "#191919",
behavior: behaviors.STURDYPOWDER,
tempHigh: 750,
stateHigh: ["asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","asphalt","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel",,"fire","fire","fire","smoke","smoke","smoke","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_monoxide","carbon_monoxide","carbon_monoxide","sulfur_dioxide","sulfur_trioxide_gas","poison_gas"],
category: "land",
state: "solid",
density: 2322,
burn: 0.5,
burnTime: 5000,
burnInto: ["gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel","gravel",,"fire","fire","fire","smoke","smoke","smoke","carbon_dioxide","carbon_dioxide","carbon_dioxide","carbon_monoxide","carbon_monoxide","carbon_monoxide","sulfur_dioxide","sulfur_trioxide_gas","poison_gas"],
fireElement: ["smoke","smoke","smoke","carbon_dioxide","carbon_monoxide","fire","fire","fire","fire","fire","fire"],
fireChance: 2,
hardness: 0.5,
breakInto: ["bitumen","gravel"],
reactions: {
light: { temp1: 0.25, elem2: null }
}
};
elements.oil.temp = 20;
delete elements.oil.behavior;
elements.oil.tick = function(pixel) {
if(!pixel.role) {
var value = Math.random();
if(value <= 0.03) {
pixel.role = "lpg";
} else if(value <= 0.45) { //42%
pixel.role = "gasoline";
} else if(value <= 0.60) { //15%
pixel.role = "naphtha";
} else if(value <= 0.70) { //10%
pixel.role = "kerosene"; //kerosene/lamp oil/jet fuel are apparently the same funny bunch of hydrocarbons
} else if(value <= 0.9) { //20%
pixel.role = "diesel";
} else if(value <= 0.91) { //1%
pixel.role = "lubricant";
} else if(value <= 0.97) { //6%
pixel.role = "heavy_fuel_oil"; //700 cP
} else if(value < 1) { //3%
pixel.role = "bitumen";
};
};
var _viscosity;
switch(pixel.role) {
case "lpg":
_viscosity = 1;
break
case "gasoline":
_viscosity = 28.16;
break
case "naphtha":
_viscosity = 23.08;
break
case "kerosene":
_viscosity = 12;
break
case "diesel":
_viscosity = 24;
break
default:
_viscosity = 250;
break
case "lubricant":
_viscosity = 300;
break
case "heavy_fuel_oil":
_viscosity = 600;
break
case "bitumen":
_viscosity = 100000;
break
};
_viscosity /= (1.09 ** pixel.temp);
liquidMoveCustomViscosity(pixel,_viscosity);
doDefaults(pixel);
if(pixel.temp > 35 && pixel.role == "lpg" && Math.random() < ((pixel.temp - 34) / 210)) { //https://www.crownoil.co.uk/guides/crude-oil-fractional-distillation/: Butane and propane and other petroleum gases are formed right at the top of the distillation tower, where it is coolest, a very mild 25°C: the temperature range that forms these gases is between 25°C and 50°C. These gases are the lightest products formed in crude oil distillation and are flammable gases.
changePixel(pixel,"light_petroleum_fuel_gas")
} else if(pixel.temp > 70 && pixel.role == "gasoline" && Math.random() < ((pixel.temp - 69) / 420)) { //The numbers in the equation are mathematical coincidence.
changePixel(pixel,"gasoline_gas")
} else if(pixel.temp > 120 && pixel.role == "naphtha" && Math.random() < ((pixel.temp - 119) / 720)) {
changePixel(pixel,"naphtha_gas")
} else if(pixel.temp > 170 && pixel.role == "kerosene" && Math.random() < ((pixel.temp - 169) / 770)) {
changePixel(pixel,"lamp_oil_gas")
} else if(pixel.temp > 270 && pixel.role == "diesel" && Math.random() < ((pixel.temp - 269) / 870)) {
changePixel(pixel,"diesel_gas")
} else if(pixel.temp > 300 && pixel.role == "heavy_fuel_oil" && Math.random() < ((pixel.temp - 299) / 1200)) {
changePixel(pixel,"heavy_fuel_oil_gas")
} else if(pixel.temp > 350 && Math.random() < ((pixel.temp - 349) / 1350)) {
changePixel(pixel,pixel.role == "lubricant" ? "lubricating_oil_gas" : "bitumen")
}
};
//UREA ##
elements.urea = {
color: "#fef7ee", //once again mapping UV absorbances to the visible range
//https://www.researchgate.net/publication/266458879
//http://depts.washington.edu/cmditr/modules/lum/color.html
behavior: behaviors.POWDER,
state: "solid",
density: 1320,
tempHigh: 133,
category: "powders",
},
elements.molten_urea = {
tempHigh: 350, //https://pubs.acs.org/doi/pdf/10.1021/ie034052j
stateHigh: ["ammonia","vaporized_isocyanic_acid"],
},
elements.liquid_isocyanic_acid = {
color: "#ffe5f0", //now it's an IR spectrum
//https://www.researchgate.net/publication/231057584
behavior: behaviors.LIQUID,
reactions: {
"water": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
"steam": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
"ice": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
},
state: "liquid",
density: 1140,
tempHigh: 23,
stateHigh: "vaporized_isocyanic_acid",
tempLow: -86,
stateLow: "frozen_isocyanic_acid",
category: "liquids",
},
elements.frozen_isocyanic_acid = {
color: "#ffe5f0",
behavior: behaviors.WALL,
reactions: {
"water": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
"steam": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
"ice": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
},
state: "solid",
density: 1267,
tempHigh: -86,
stateHigh: "liquid_isocyanic_acid",
category: "powders",
},
elements.vaporized_isocyanic_acid = {
color: "#ffe5f0",
behavior: behaviors.GAS,
reactions: {
"water": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
"steam": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
"ice": { "elem1": "carbon_dioxide", "elem2": "ammonia" },
},
state: "gas",
density: 1026,
tempLow: 23,
stateLow: "liquid_isocyanic_acid",
category: "gases",
}
//INVISIBLE WALL AND DYE ##
if(!settings) {
settings = {}
}
settings.bg ??= _cc.b.h;
function getBackgroundColorOrAverageAsJSON() {
if(!(settings?.bg)) {
return _cc.b.j;
} else if(!(settings.bg instanceof Array)) {
return convertColorFormats(settings.bg,"json")
} else {
return convertColorFormats(averageRgbPrefixedColorArray(settings.bg.map(color => convertColorFormats(color,"rgb"))),"json");
};
};
function makePixelInvisible(pixel) {
var backgroundColor = getBackgroundColorOrAverageAsJSON();
pixel.color = `rgba(${backgroundColor.r},${backgroundColor.g},${backgroundColor.b},0)`;
};
elements.invisible_wall = {
color: settings.bg,
behavior: behaviors.WALL,
alpha: 0,
renderer: function(pixel,ctx) {
if(view == 2) { viewInfo[2].pixel(pixel,ctx); return };
if(currentElement == pixel.element || shiftDown) {
ctx.globalAlpha = 0.6;
ctx.fillStyle = "#7f7f7f";
ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize);
}
},
insulate: true,
hardness: 1,
category: "special",
state: "solid",
};
elements.invisible_dye = {
color: settings.bg,
behavior: behaviors.LIQUID,
alpha: 0,
tick: function(pixel) { makePixelInvisible(pixel) },
renderer: function(pixel,ctx) {
if(view == 2) { viewInfo[2].pixel(pixel,ctx); return };
if(currentElement == pixel.element || shiftDown) {
ctx.globalAlpha = 0.6;
ctx.fillStyle = "#7f7f7f";
ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize);
}
},
hardness: 0.8,
breakInto: "invisible_dye_gas",
tempHigh: 110,
stateHigh: "invisible_dye_gas",
category: "special",
state: "liquid",
density: 1,
stain: elements.dye.stain,
};
elements.invisible_dye_gas = {
color: settings.bg,
behavior: behaviors.GAS,
alpha: 0,
tick: function(pixel) { makePixelInvisible(pixel) },
renderer: function(pixel,ctx) {
if(view == 2) { viewInfo[2].pixel(pixel,ctx); return };
if(currentElement == pixel.element || shiftDown) {
ctx.globalAlpha = 0.6;
ctx.fillStyle = "#7f7f7f";
ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize);
}
},
hardness: 0.5,
breakInto: "invisible_dye_gas",
tempLow: 109,
stateLow: "invisible_dye",
category: "special",
state: "liquid",
density: 1,
stain: elements.spray_paint.stain,
};
var _temporary = {
invisible_wall: "asdfg",
invisible_dye: 2,
invisible_dye_gas: false
};
for(var elemName in _temporary) {
elements[elemName].desc = "Note: Invisible dyes do not work (and are not supported) with gradient backgrouds";
};
//BANANAS AND BANANA PLANTS ##
randomNumberFromOneToThree = function() {
return 1 + Math.floor(Math.random() * 3)
};
bananaDebugSpeedGrowth = false;
logLeaves = false;
bananaAttachWhitelist = ["banana_pseudostem","banana_peduncle_1","banana_peduncle_2","petal","banana_leaf","banana_plant_top","banana"];
bananaDirtElements = ["dirt","mud","sand","wet_sand","clay_soil","mycelium","grass"];
function logPixelCoords(pixel) {
return `(${pixel.x}, ${pixel.y})`
};
function hasPixel(x,y,elementInput) {
if(isEmpty(x,y,true)) { //if empty, it can't have a pixel
return false;
} else {
if(elementInput.includes(",")) { //CSTA
elementInput = elementInput.split(",");
};
if(Array.isArray(elementInput)) { //if element list
return elementInput.includes(pixelMap[x][y].element);
} else { //if single element
return pixelMap[x][y].element === elementInput;
};
};
};
elements.banana_seed = {
color: "#3b3b2e",
tick: function(pixel) {
if(pixel.bananaRange === null) {
pixel.bananaRange = randomNumberFromOneToThree();
};
if (isEmpty(pixel.x,pixel.y+1)) {
movePixel(pixel,pixel.x,pixel.y+1);
} else {
if (Math.random() < (bananaDebugSpeedGrowth ? 0.09 : 0.03) && pixel.age > (bananaDebugSpeedGrowth ? 20 : 50) && pixel.temp < 100) {
if (!outOfBounds(pixel.x,pixel.y+1)) {
var dirtPixel = pixelMap[pixel.x][pixel.y+1];
if (bananaDirtElements.includes(dirtPixel.element)) {
changePixel(dirtPixel,"root");
};
};
if (isEmpty(pixel.x,pixel.y-1)) {
movePixel(pixel,pixel.x,pixel.y-1);
createPixel("banana_pseudostem",pixel.x,pixel.y+1);
pixelMap[pixel.x][pixel.y+1].bananaRange = pixel.bananaRange; //pass banana range down to pseudostem
};
} else if (pixel.age > (bananaDebugSpeedGrowth ? 500 : 1000)) {
changePixel(pixel,"banana_plant_top");
};
pixel.age++;
};
if(Math.random() < 0.01 && pixel.age > 200) {
changePixel(pixel,"banana_plant_top");
};
doDefaults(pixel);
},
properties: {
"age": 0,
"bananaRange": null
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
category: "life",
state: "solid",
density: 1500,
cooldown: defaultCooldown,
};
elements.banana_pseudostem = {
hidden: true,
color: "#d5e39f",
tick: function(pixel) {
if(pixel.bananaRange === null) {
pixel.bananaRange = randomNumberFromOneToThree();
};
if (pixel.age > 60 && pixel.temp < 100 && !pixel.grewPeduncle) {
var peduncleOffsets = [-1, 1]; //placed to the left, placed to the right
for(i = 0; i < peduncleOffsets.length; i++) {
if (isEmpty(pixel.x+peduncleOffsets[i],pixel.y,false)) {
if (Math.random() < 0.005) {
createPixel("banana_peduncle_1",pixel.x+peduncleOffsets[i],pixel.y);
pixelMap[pixel.x+peduncleOffsets[i]][pixel.y].dir = Math.sign(peduncleOffsets[i]);
pixelMap[pixel.x+peduncleOffsets[i]][pixel.y].bananaRange = pixel.bananaRange; //pass banana range down to peduncle
if(Math.random() < 0.8) { pixel.grewPeduncle = true; } //20% chance to not mark as true, allowing for a chance to try another peduncle
};
};
};
};
pixel.age++;
doDefaults(pixel);
},
properties: {
"age": 0,
"grewPeduncle": false,
"bananaRange": null
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
category: "life",
state: "solid",
density: 1500,
};
elements.banana = {
color: "#ede84c",
isFood: true,
tick: function(pixel) {
if(pixel.attached) {
var attachCoords = [pixel.x+Math.sign(pixel.attachDirection), pixel.y];
if(isEmpty(attachCoords[0],attachCoords[1],false)) {
pixel.attached = false;
};
} else { //Move if not attached
if (!tryMove(pixel, pixel.x, pixel.y+1)) {
if(Math.random() < 0.9) {
if (Math.random() < 0.5) {
if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
tryMove(pixel, pixel.x-1, pixel.y+1);
};
} else {
if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
tryMove(pixel, pixel.x+1, pixel.y+1);
};
};
};
};
};
doDefaults(pixel);
var shouldSpoil = true; //spoil by default
if(pixel.attached) { //if it's attached
if(!isEmpty(attachCoords[0],attachCoords[1],true)) { //if the attachment coords are a pixel and not OOB
var attachPixel = pixelMap[attachCoords[0]][attachCoords[1]];
var attachElement = attachPixel.element;
if(bananaAttachWhitelist.includes(attachElement)) {//if the element is a whitelisted "don't spoil" element
shouldSpoil = false; //then don't spoil
};
};
};
if(shouldSpoil) { //spoil if not attached
if(pixel.temp > -14 && pixel.temp <= 4) { //(no spoiling below 14C)
pixel.spoilage += Math.max(Math.min(scale(pixel.temp,-14,4,0,9),9),0)
} else if(pixel.temp > 4) {
pixel.spoilage += Math.max(Math.min(scale(pixel.temp,4,20,9,30),40),0)
};
};
if(pixel.spoilage > 14400) { //3600 = 120 ticks at 20C
if(Math.random() < 0.05) {
changePixel(pixel,"spoiled_banana");
};
};
},
properties: {
"spoilage":0,
"attached": false,
"attachDirection": (!Math.floor(Math.random() * 2)) ? 1 : -1
},
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
tempHigh: 200,
stateHigh: ["steam", "ash"],
onTryMoveInto: function(pixel,otherPixel) {
var otherInfo = elements[otherPixel.element]
if(typeof(otherInfo.state) === "string" && otherInfo.state !== "gas") {
pixel.attached = false;
};
},
};
elements.banana_peduncle_1 = {
hidden: true,
name: "banana peduncle (offshoot)",
color: "#acb55b",
tick: function(pixel) {
if(pixel.bananaRange === null) {
pixel.bananaRange = randomNumberFromOneToThree();
};
if (pixel.age > 20 && pixel.temp < 100) {
var peduncleCoords1 = [pixel.x + pixel.dir, pixel.y];
var peduncleCoords2 = [pixel.x + pixel.dir, pixel.y + 1];
if(isEmpty(peduncleCoords1[0],peduncleCoords1[1],false) && isEmpty(peduncleCoords2[0],peduncleCoords2[1],false)) {
if(Math.random() < 0.5) {
createPixel(pixel.element,peduncleCoords1[0],peduncleCoords1[1]);
pixelMap[peduncleCoords1[0]][peduncleCoords1[1]].dir = pixel.dir;
pixelMap[peduncleCoords1[0]][peduncleCoords1[1]].bananaRange = pixel.bananaRange; //pass banana range down to next pixel of peduncle horizontal
} else {
createPixel("banana_peduncle_2",peduncleCoords2[0],peduncleCoords2[1]);
pixelMap[peduncleCoords2[0]][peduncleCoords2[1]].bananaRange = pixel.bananaRange; //pass banana range down to diagonal offshoot
};
};
};
pixel.age++;
doDefaults(pixel);
},
properties: {
"dir": (!Math.floor(Math.random() * 2)) ? 1 : -1,
"age": 0,
//"bananaRange": (1 + (Math.floor(Math.random() * 3))), //1-3
"bananaRange": null
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
category: "life",
state: "solid",
density: 1500,
};
elements.banana_peduncle_2 = {
hidden: true,
name: "banana peduncle (hanging)",
color: "#9bad51",
tick: function(pixel) {
if(pixel.bananaRange === null) {
pixel.bananaRange = randomNumberFromOneToThree();
};
// Grow/Flower
if (pixel.age > 20 && pixel.temp < 100) {
var growthCoords = [pixel.x, pixel.y + 1];
if(isEmpty(...growthCoords)) {
if(Math.random() < 0.9) {
createPixel(pixel.element,...growthCoords);
pixelMap[growthCoords[0]][growthCoords[1]].bananaRange = pixel.bananaRange; //pass banana range down to next pixel of peduncle vertical
} else {
createPixel("petal",...growthCoords); //the sexual dimorphism of the banana plant has zonked me
};
};
};
//Make bananas
if (pixel.age > 40 && pixel.temp < 100) {
var bananaOffsets = [-1, 1]; //placed to the left, placed to the right
for(i = 0; i < bananaOffsets.length; i++) {
//console.log(`Looping through left and right positions: ${bananaOffsets}`);
for(j = 1; j < pixel.bananaRange + 1; j++) { //for max banana distance, using the banana range
//console.log(`Looping through banana offset multipliers: ${j}`);
if (isEmpty(pixel.x+(j * bananaOffsets[i]),pixel.y,false)) { //if there's an empty space
//console.log(`Banana position is empty: [${j * bananaOffsets[i]}, 0]\nTrying banana at (${pixel.x+(j * bananaOffsets[i])},${pixel.y})`);
if (Math.random() < (bananaDebugSpeedGrowth ? 0.05 : 0.005)) { //try to place the banana
//console.log(`Placing banana`);
createPixel("banana",pixel.x+(j * bananaOffsets[i]),pixel.y);
pixelMap[pixel.x+(j * bananaOffsets[i])][pixel.y].attached = true;
pixelMap[pixel.x+(j * bananaOffsets[i])][pixel.y].attachDirection = -1 * Math.sign(bananaOffsets[i]); //attach dir is the opposite of placement dir so it attaches towards the stem
} else {
//console.log(`NOT placing banana`);
};
//console.log(`Banana tried, stopping iteration`);
break; //and then stop iteration
} else {
//console.log(`Banana position is NOT empty: [${j * bananaOffsets[i]}, 0]\nSkipping this offset`);
continue; //if not empty, skip that pixel and move on the next distance
};
//console.log(`====End of side try====`);
};
//console.log(`%%%%End of side iterator%%%%`);
};
//console.log(`>>>>End of banana iterator<<<<`);
};
pixel.age++;
doDefaults(pixel);
//console.log(`\nEnd of peduncle tick\n`);
},
properties: {
"age": 0,
//"bananaRange": (1 + (Math.floor(Math.random() * 3))), //1-3
"bananaRange": null
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
category: "life",
state: "solid",
density: 1500,
};
elements.spoiled_banana = {
hidden: true,
color: "#594b29",
behavior: [
"XX|CR:stench,fly%0.1|XX",
"M2%0.5|CH:dirty_water,fly,fly%0.007|M2%0.5",
"M2|M1|M2"
],
stain: 0.01,
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
tempHigh: 200,
stateHigh: ["steam", "ash"],
};
elements.fly.reactions.spoiled_banana = { "elem2":null, chance:0.15, func:behaviors.FEEDPIXEL };
elements.banana_leaf = {
hidden: true,
color: "#9df24e",
tick: function(pixel) {
if(pixel.bananaRange === null) {
pixel.bananaRange = randomNumberFromOneToThree();
};
if(pixel.attached) {
var attachCoords = [pixel.x + pixel.attachOffsets[0], pixel.y + pixel.attachOffsets[1]];
if(isEmpty(attachCoords[0],attachCoords[1],false)) { //consider OOB full
pixel.attached = false;
};
} else { //Move if not attached
if(Math.random() < 0.2) {
if (!tryMove(pixel, pixel.x, pixel.y+1)) {
if(Math.random() < 0.4) {
if (Math.random() < 0.5) {
if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
tryMove(pixel, pixel.x-1, pixel.y+1);
};
} else {
if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
tryMove(pixel, pixel.x+1, pixel.y+1);
};
};
};
};
};
};
doDefaults(pixel);
},
properties: {
"attached": false,
"attachOffsets": [(!Math.floor(Math.random() * 2)) ? 1 : -1, 0],
"bananaRange": null
},
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
tempHigh: 200,
stateHigh: ["steam", "ash"],
onTryMoveInto: function(pixel,otherPixel) { //Move through
var otherElement = otherPixel.element; //var element for readability
var otherInfo = elements[otherElement]; //var info
var otherState = "solid"; //consider things solid by default
if(typeof(otherInfo.state) === "string") {
otherState = otherInfo.state; //get actual state if it exists
};
var otherDensity = 1000; //consider density 1000 by default
if(typeof(otherInfo.density) === "number") {
otherDensity = otherInfo.density; //get actual density if it exists
};
var react = false; //default to no reaction
if(typeof(otherInfo.reactions) === "object") { //look for reactions
if(typeof(otherInfo.reactions[pixel.element]) === "object") { //look for reactions involving this element
react = true; //if there are any, set reaction flag to true
};
};
if(otherElement.endsWith("head") || otherElement.endsWith("body")) {
//i don't want to make general MPL handling so I'll just try to exclude them;
if(otherElement !== "antibody") {
//exclude antibody from exclusion
return false;
};
};
if(otherElement !== pixel.element) { //allow this element from piling on itself
if(logLeaves) { console.log("Other element is not banana leaves") }; //yes, this code is for banana leaves
if(react) { //if there was a reaction in that previous step
if(logLeaves) { console.log("Reacting pixels") };
reactPixels(otherPixel,pixel); //react
} else { //if no such reaction existed, move through
if(logLeaves) { console.log("Moving pixels") };
if((otherState !== "solid") || (otherState === "solid" && otherDensity > 100)) { //admit any non-solid, or any solid with a density over 100
var pX = pixel.x; //var pixel coords for no particular reason
var pY = pixel.y;
var oX = otherPixel.x; //var other pixel's coords for no particular reason
var oY = otherPixel.y;
if(logLeaves) { console.log(`${otherElement} pixel (${oX},${oY}) trying to move info leaf block (${pX},${pY})`) };
var dX = oX - pX; //get the difference between this's X and other's X; if the other pixel is moving from the space immediately to the right, this dX value should be 1
var dY = oY - pY;
var iDX = -1 * dX; //get the additive inverse; if we want to move such a pixel from the right to the left, we would change its +1 X offset to a -1 X offset for the coord sto move it to
var iDY = -1 * dY;
if(logLeaves) { console.log(`Old offset (relative to leaf): [${dX},${dY}], new offset [${iDX},${iDY}]`) };
var fX = pX + iDX; //combine this pixel's X with the inverted offset we just made;
//assuming this pixel is (23,31) and the other pixel is trying to move in to the left into this from (24,31),
//the dX would be [1, 0], signifying that the other pixel is 1 pixel to the right of this
//the space to the left of this, where it would go, is (22,31), and the offset for that pixel relative to this is [-1, 0]
//to get the [-1, 0], we'd need to flip that [1, 0] offset (lmao flip that the song by loona), hence the inverse
var fY = pY + iDY;
if(logLeaves) { console.log(`Calculated final position: (${fX},${fY}), moving other pixel from (${oX},${oY})`) };
tryMove(otherPixel,fX,fY);
};
};
};
},
};
/*if(!elements.diamond.reactions) { //test reaction
elements.diamond.reactions = {};
};
elements.diamond.reactions.banana_leaf = { "elem2": "dead_plant" };*/
elements.banana_plant_top = {
hidden: true,
color: "#d5e39f",
tick: function(pixel) {
if(pixel.bananaRange === null) {
pixel.bananaRange = randomNumberFromOneToThree();
};
if (pixel.age > 30 && pixel.temp < 100) {
if(!pixel.grewLeftLeaves) {
for(i = (0 - pixel.leafRange); i < 0; i++) { //left half
if(i == 0) {
continue;
};
var leafOffset = i; //readability
var leafX = pixel.x + leafOffset; //set X to banana_plant_top pixel's X + offset/index
var leafAttachOffset = [1, 0]; //difference 1: attaches rightwards (+) for leaves left (-) of center
var leafY = pixel.y; //set Y to default banana_plant_top pixel's Y
if(Math.abs(leafOffset) == pixel.leafRange) {
leafY++; //place edge leaves 1 pixel downwards;
leafAttachOffset[1] = -1; //compensate by subtracting 1 from Y attach offset (less Y = higher position, so they attach diagonally up-right or up-left)
};
if(outOfBounds(leafX,leafY)) {
continue;
};
if (isEmpty(leafX,leafY,false)) {
createPixel("banana_leaf",leafX,leafY);
pixelMap[leafX][leafY].attached = true; //set leaf's attached to true
pixelMap[leafX][leafY].attachOffsets = leafAttachOffset; //array of 2 numbers
pixelMap[leafX][leafY].bananaRange = pixel.bananaRange;
pixel.grewLeftLeaves = true; //difference 2: separate flag for left side
} else {
break;
};
};
};
if(!pixel.grewRightLeaves) {
for(i = 1; i < (pixel.leafRange + 1); i++) { //right half
if(i == 0) {
continue;
};
var leafOffset = i; //readability
var leafX = pixel.x + leafOffset; //set X to banana_plant_top pixel's X + offset/index
var leafAttachOffset = [-1, 0]; //difference 1: attaches leftwards (-) for leaves right (+) of center
var leafY = pixel.y; //set Y to default banana_plant_top pixel's Y
if(Math.abs(leafOffset) == pixel.leafRange) {
leafY++; //place edge leaves 1 pixel downwards;
leafAttachOffset[1] = -1; //compensate by subtracting 1 from Y attach offset (less Y = higher position, so they attach diagonally up-right or up-left)
};
if(outOfBounds(leafX,leafY)) {
continue;
};
if (isEmpty(leafX,leafY,false)) {
createPixel("banana_leaf",leafX,leafY);
pixelMap[leafX][leafY].attached = true; //set leaf's attached to true
pixelMap[leafX][leafY].attachOffsets = leafAttachOffset; //array of 2 numbers
pixelMap[leafX][leafY].bananaRange = pixel.bananaRange;
pixel.grewRightLeaves = true; //difference 2: separate flag for right side
} else {
break;
};
};
};
};
pixel.age++;
doDefaults(pixel);
},
properties: {
"age": 0,
"leafRange": 2 + (Math.floor(Math.random() * 3)), //2-4
"grewLeftLeaves": false,
"grewRightLeaves": false,
"bananaRange": null
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
category: "life",
state: "solid",
density: 1500,
};
/*elements.cocoa_bean = {
color: ["#f2ede9", "#f0dfce", "#e8cfb5"],
behavior: behaviors.SOLID,
category: "liquids",
viscosity: 100000,
state: "liquid",
density: 593,
tick: function
};*/
//THERMAL FOUNDATION LIQUIDS, FU BIO-OOZE, AND SOME PYROGENIC MATERIALS
nonAdjacentCoords = [
[1, 1],
[1, -1],
[-1, 1],
[-1, -1]
];
//pyrotheum
elements.blazing_pyrotheum = {
color: "#ffdd55",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if(pixel.temp >= -273 && pixel.temp <= 3707) { //temperature minimum of 3727
pixel.temp += 50
} else if(pixel.temp > 3677 && pixel.temp < 3727) {
pixel.temp = 3727
}
var pX = pixel.x;
var pY = pixel.y;
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pX+oX;
var fY = pY+oY;
if(!isEmpty(fX,fY,true)) {
var checkPixel = pixelMap[fX][fY];
var thisElementName = pixel.element;
var otherElementName = checkPixel.element;
var thisElement = elements[pixel.element];
var otherElement = elements[checkPixel.element];
thisElementName === otherElementName ? checkPixel.temp+=0.1 : checkPixel.temp==10;
} else if(isEmpty(fX,fY,false)) {
if(Math.random() < 0.05) {
createPixel("fire",fX,fY);
var checkPixel = pixelMap[fX][fY];
checkPixel.temp = pixel.temp;
}
};
};
},
viscosity: 1.2**4,
category: "liquids",
state: "liquid",
density:1994,
insulate:false,
temp: 3727,
},
elements.gelid_cryotheum = {
color: "#00ddff",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if(pixel.temp >= -223) { //temperature maximum of -223
pixel.temp -= 50
} else if(pixel.temp > -223 && pixel.temp < -273) {
pixel.temp = -223
}
var pX = pixel.x;
var pY = pixel.y;
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pX+oX;
var fY = pY+oY;
if(!isEmpty(fX,fY,true)) {
var checkPixel = pixelMap[fX][fY];
var thisElementName = pixel.element;
var otherElementName = checkPixel.element;
var thisElement = elements[pixel.element];
var otherElement = elements[checkPixel.element];
thisElementName === otherElementName ? checkPixel.temp-=0.1 : checkPixel.temp-=10;
};
};
/*for(i = 0; i < nonAdjacentCoords.length; i++) {
var oX = nonAdjacentCoords[i][0];
var oY = nonAdjacentCoords[i][1];
var fX = pX+oX;
var fY = pY+oY;
if(isEmpty(fX,fY,false)) {
if(Math.random() < 0.025) {
createPixel("snow",fX,fY);
var checkPixel = pixelMap[fX][fY];
checkPixel.temp = pixel.temp;
};
};
};*/ //It should create snow, but the snow freezes into ice and it leaves unsightly floating ice everywhere.
},
viscosity: 3**4,
category: "liquids",
state: "liquid",
density:3988,
insulate:false,
temp: -223,
},
elements.tectonic_petrotheum = {
color: ["#342414","#3C2414","#2C1C14","#543424","#643C28","#74442C"],
behavior: [
"XX|XX|XX",
"M2|XX|M2",
"M1|SW:dust AND M1|M1",
],
tick: function(pixel) { //Code from R74n/vanilla "smash" tool
var pX = pixel.x;
var pY = pixel.y;
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pX+oX;
var fY = pY+oY;
if(!isEmpty(fX,fY,true)) {
var checkPixel = pixelMap[fX][fY];
var otherElement = elements[checkPixel.element];
if (typeof(otherElement.breakInto) !== "undefined") {
var hardness = otherElement.hardness ?? 0;
if (Math.random() < (1 - hardness)) {
var breakInto = otherElement.breakInto;
// if breakInto is an array, pick one
if (Array.isArray(breakInto)) {
breakInto = breakInto[Math.floor(Math.random() * breakInto.length)];
};
changePixel(checkPixel,breakInto);
}
}
};
};
},
temp: 120,
viscosity: 1.5**4,
category: "liquids",
state: "liquid",
density:3988,
insulate:false,
};
elements.zephyrean_aerotheum = {
color: ["#FFFCD9","#FEFFFC","#FDFFDB","#FFFFE8","#FBF6D3","#F1EDD0"],
behavior: behaviors.AGLIQUID,
viscosity: 0.1**4,
category: "liquids",
state: "liquid",
density:-800,
insulate:false,
tick: function(pixel) {
//"Projectiles that come into contact with zephyrean aerotheum are sent flying in a random direction away from the fluid."
var pX = pixel.x;
var pY = pixel.y;
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pX+oX;
var fY = pY+oY;
if(!isEmpty(fX,fY,true)) {
var checkPixel = pixelMap[fX][fY];
var thisElementName = pixel.element;
var otherElementName = checkPixel.element;
var thisElement = elements[pixel.element];
var otherElement = elements[checkPixel.element];
if(otherElement.movable) {
if(typeof(checkPixel.vx) === "undefined") {
checkPixel.vx = 0;
};
if(typeof(checkPixel.vy) === "undefined") {
checkPixel.vy = 0;
};
if(Math.random() < 1/3) {
var randomVxChange = Math.floor(Math.random() * 9) - 4; //random value from -3 to 3
var randomVyChange = Math.floor(Math.random() * 9) - 4; //different random value from -3 to 3
//Notes
/*
Positive vx = right
Positive vy = down
adjacentCoords[0]: [0, 1] is downward; when it is detected, the pixel there should be sent farther down (positive vy).
adjacentCoords[1]: [0, -1] is upward; when it is detected, the pixel there should be sent farther up (negative vy).
adjacentCoords[2]: [1, 0] is rightward; when it is detected, the pixel there should be sent farther right (positive vx).
adjacentCoords[3]: [-1, 0] is leftward; when it is detected, the pixel there should be sent farther left (negative vx).
*/
switch(i) {
case 0:
randomVyChange = Math.abs(randomVyChange);
break;
case 1:
randomVyChange = (Math.abs(randomVyChange) * -1) - 1;
break;
case 2:
randomVxChange = Math.abs(randomVxChange);
break;
case 3:
randomVxChange = Math.abs(randomVxChange) * -1;
break;
default:
console.log("Uh-oh, i was somehow above 3!")
};
if(otherElementName !== thisElementName) {
checkPixel.vx += randomVxChange;
checkPixel.vy += randomVyChange;
}
}
}
}
}
}
};
elements.energized_glowstone = {
color: ["#fbb204", "#fcf605", "#fce704", "#f8c414", "#f8e814"],
behavior: [
"M1 AND SW:light|M1 AND CR:light%40 AND SW:light|M1 AND SW:light",
"M2 AND CR:light%40|XX|M2 AND CR:light%40",
"XX|CR:light%40|XX",
],
viscosity: 0.1**4,
category: "liquids",
state: "liquid",
density:-500,
insulate:false, //TODO: > Energized glowstone source blocks will gradually float upwards if there are no blocks above them. If they float at high levels (layers 120 and above by default) they will condense back into solid glowstone. They will also condense at 80% of this height if the fluid has no space to flow.
},
elements.resonant_ender = {
color: ["#062c2c", "#062c2c", "#19a8a8", "#0a4646", "#1f8c8e", "#0c5c54", "#0c5c54"],
behavior: behaviors.LIQUID,
tick: function(pixel) {
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (lifeArray.includes(pixelMap[pixel.x+j][pixel.y+i].element)) {
pixel.eeex = pixel.x + Math.floor(Math.random() * ((2 * 8) + 1)) - 8
pixel.eeey = pixel.y + Math.floor(Math.random() * ((2 * 8) + 1)) - 8
//if human
//handle heads
if(pixelMap[pixel.x+j][pixel.y+i].element == "head") {
if(isEmpty(pixel.eeex,pixel.eeey) && !outOfBounds(pixel.eeex,pixel.eeey) && isEmpty(pixel.eeex,pixel.eeey+1) && !outOfBounds(pixel.eeex,pixel.eeey+1)) {
tryMove(pixelMap[pixel.x+j][pixel.y+i],pixel.eeex,pixel.eeey)
tryMove(pixelMap[pixel.x+j][pixel.y+i+1],pixel.eeex,pixel.eeey+1)
}
} else if(pixelMap[pixel.x+j][pixel.y+i].element == "body") {
} else {
if(isEmpty(pixel.eeex,pixel.eeey) && !outOfBounds(pixel.eeex,pixel.eeey)) {
tryMove(pixelMap[pixel.x+j][pixel.y+i],pixel.eeex,pixel.eeey)
}
}
}
}
}
}
},
category: "liquids",
density: 3000,
state: "liquid",
viscosity: 3**4,
}
eLists.JUICEMIXABLE.push("blazing_pyrotheum","gelid_cryotheum","tectonic_petrotheum","zephyrean_aerotheum","energized_glowstone","resonant_ender","destabilized_redstone") //canonically you can drink them, but it's a very bad idea
elements.redstone_dust.tempHigh = 2500;
elements.redstone_dust.stateHigh = "destabilized_redstone";
elements.redstone_dust.conduct = 0.9;
elements.redstone_dust.colorOn = ["#FF2424","#FF0000","#FF1200"];
elements.redstone_dust.color = ["#7f0000","#5f0000","#5f0500"];
elements.destabilized_redstone = {
color: ["#9e0303", "#98061a", "#b80704", "#c4020c", "#f70008", "#9e0303", "#98061a", "#b80704", "#e3020a", "#8c0303", "#8c0303"],
behavior: [
"XX|SH|XX",
"M2 AND SH|XX|M2 AND SH",
"M1|M1 AND SH|M1",
],
viscosity: 1.5**4,
category: "liquids",
state: "liquid",
density:1200,
}
elements.signalum = {
color: "#ff9321",
behavior: behaviors.WALL,
category: "solids",
density: 10500,
conduct: 1,
tempHigh: 1550,
stateHigh: "molten_signalum",
state: "solid",
}
elements.molten_sterling ??= {};
elements.molten_sterling.reactions ??= {};
elements.molten_sterling.reactions.destabilized_redstone = { "elem1": null, "elem2": "molten_signalum" }
elements.molten_signalum = {
color: "#f17414",
behavior: behaviors.MOLTEN,
density: 10500*0.9,
conduct: 0.30,
temp:600,
tempLow: 550,
stateLow: "signalum",
category: "liquids",
state: "liquid",
hidden: true,
}
elements.energized_glowstone.reactions ??= {};
elements.energized_glowstone.reactions.gelid_cryotheum = { "elem1":"glowstone_dust" };
elements.glowstone_dust.behavior = [ //it should emit light, right?
"CR:light%0.025|CR:light%0.025|CR:light%0.025",
"CR:light%0.025|XX|CR:light%0.025",
"CR:light%0.025|CR:light%0.025|CR:light%0.025"
];
runAfterLoad(function() {
lifeArray = Object.keys(elements).filter(function(e) {
return elements[e].category == "life";
})
});
elements.bio_ooze = { //a.k.a. the water in the River Thames during July and August of 1858
name: "Bio-Ooze",
color: ["#53FF4F", "#53FF4F", "#06DE00", "#04A600", "#036E00"],
behavior: behaviors.LIQUID,
tempHigh: 100,
stateHigh: ["plague","slime","steam","poison"],
tempLow: -4,
category: "liquids",
heatCapacity: 3.52, //unimplemented feature
name: "bio-ooze",
reactions: {
"water": { "elem1":"slime", "elem2":"poison" }, //balance
//"acid": { "elem1":"wastestone" }, //acid should be sulfuric acid and product should be wastestone
//"elder_fluid": { "elem1":"corrupt_slime" }, //acid should be sulfuric acid and product should be wastestone
//"mercury": { "elem1":"liquid_protocite" }, //acid should be sulfuric acid and product should be wastestone
//"blue_grav_liquid": { "elem1":"blue_grav_liquid" }, //bgl would set gravity to upwards gravity
"blood": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "infection" },
"soap": { "elem1": "slime", "chance": 0.02 },
"plant": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"grass": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"algae": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"mushroom_spore": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"lichen": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"rat": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"frog": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"fish": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"bird": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"head": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"body": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"ant": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
"worm": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
"fly": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
"firefly": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
"bee": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
"slug": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
"snail": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "calcium" },
"sapling": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"root": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"flower_seed": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"pistil": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"petal": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"grass_seed": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
"meat": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
"wood": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "sawdust", "chance": 0.25 }
},
/*reactions: {
"dirt": { // React with (water reacts with dirt to make mud)
"elem1": null, // First element transforms into; in this case, water deletes itself
"elem2": "mud", // Second element transforms into; in this case, dirt turns to mud
},
"sand": { "elem1": null, "elem2": "wet_sand", },
"salt": { "elem1": "salt_water", "elem2": null },
"sugar": { "elem1": "sugar_water", "elem2": null, },
"dust": { "elem1": "dirty_water", "elem2": null, },
"ash": { "elem1": "dirty_water", "elem2": null, },
"cyanide": { "elem1": "dirty_water", "elem2": null, },
"carbon_dioxide": { "elem1": "seltzer", "elem2": null, "oneway":true },
"sulfur": { "elem1": "dirty_water", "elem2": null, },
"rat": { "elem1": "dirty_water", chance:0.005 },
"plague": { "elem1": "dirty_water", "elem2": null, },
"rust": { "elem1": "dirty_water", chance:0.005 },
"fallout": { "elem1": "dirty_water", chance:0.25 },
"radiation": { "elem1": "dirty_water", chance:0.25 },
"uranium": { "elem1": "dirty_water", chance:0.25 },
"quicklime": { "elem1": null, "elem2": "slaked_lime", },
"rock": { "elem2": "wet_sand", "chance": 0.00035 },
"ruins": { "elem2": "rock", "chance": 0.00035 },
"mudstone": { "elem2": "mud", "chance": 0.00035 },
"methane": { "elem1":"primordial_soup", "elem2":"primordial_soup", tempMin:60, charged:true },
"ammonia": { "elem1":"primordial_soup", "elem2":"primordial_soup", tempMin:60, charged:true }
},*/
state: "liquid",
density: 1.03,
conduct: 0.0008,
stain: 0.2,
viscosity: 60,
description: "A particularly potent toxic sludge loaded with parasites and ickiness.",
};
function threshholdedPyrogen(pixel,threshholdTemp,baseHeat,divisor) {
if(pixel.temp < threshholdTemp) {
pixel.temp += Math.max(baseHeat,(threshholdTemp - pixel.temp) / divisor);
} else {
pixel.temp += baseHeat;
};
};
function tpHeatCalc(startTemp,threshholdTemp,baseHeat,divisor) {
if(startTemp < threshholdTemp) {
return Math.max(baseHeat,(threshholdTemp - startTemp) / divisor);
} else {
return baseHeat;
};
};
function itfChanceCalc(baseHeat,divisor,chanceLimit) {
return Math.min(chanceLimit,(baseHeat / divisor))
};
function inferniumTempFire(pixel,divisor,chanceLimit) {
if(Math.random() < Math.min(chanceLimit,(pixel.temp / divisor))) { //fire depending on temp
var randomCoord = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)]; //random place
var nx = pixel.x+randomCoord[0];
var ny = pixel.y+randomCoord[1];
if(isEmpty(nx,ny)) { //if empty
createPixel("fire",nx,ny); //create fire at coord coords
pixelMap[nx][ny].temp = pixel.temp; //set temp
};
};
};
elements.pyreite = {
color: ["#cc674b","#e06e41","#f77320","#f77320","#fa9b28","#fac228"],
behavior: behaviors.WALL,
tempHigh: 5500, //Instead of making my own headcanons, I'm using Omniblog Of Starbound's headcanons :eggTF:
category: "solids",
density: 14600,
conduct: 0.66,
hardness: 0.79,
tick: function(pixel) {
threshholdedPyrogen(pixel,1722,0.25,512);
},
};
elements.infernium = {
color: ["#bf4b39","#e68453","#f7994d","#f7994d","#ffa154","#ffe875"],
behavior: [
"XX|CR:fire%0.01|XX",
"XX|XX|XX",
"XX|XX|XX"
],
tempHigh: 5526, //I have no headcanon to turn to for this mod so have multiples of 2763
category: "solids",
density: 13815,
conduct: 0.691,
hardness: 0.79,
tick: function(pixel) {
threshholdedPyrogen(pixel,1763,0.32,512);
inferniumTempFire(pixel,40000,0.2);
},
};
elements.molten_pyreite = {
tick: function(pixel) {
pixel.temp += 0.25;
},
reactions: {
molten_infernium: { elem1: "molten_infernyrite", elem2: "molten_infernyrite", temp1: 304, temp2: 304 }
},
};
elements.molten_infernium = {
tick: function(pixel) {
pixel.temp += 0.32;
inferniumTempFire(pixel,40000,0.2);
},
};
elements.infernyrite = {
color: ["#d45f2c","#f59449","#f7994d","#fcaa4c","#fab973","#ffea8c"],
behavior: [
"XX|CR:fire%0.01|XX",
"XX|XX|XX",
"XX|XX|XX"
],
tempHigh: 9901,
category: "solids",
density: 14197,
conduct: 0.63,
hardness: 0.8,
tick: function(pixel) {
threshholdedPyrogen(pixel,2501,0.79,480);
inferniumTempFire(pixel,40000,0.2);
},
};
elements.molten_infernyrite = {
tick: function(pixel) {
pixel.temp += 0.79;
inferniumTempFire(pixel,40000,0.2); //"canonically", the dilution and the pyrogenic synergy or whatever you want to call it just so happen to cancel out
},
reactions: {
blazing_pyrotheum: {
elem1: "molten_infernyreitheum",
elem2: ["blazing_pyrotheum","molten_infernyreitheum"],
temp1: 1043,
temp2: 1043
}
},
};
elements.infernyreitheum = {
color: ["#f2a863","#faaf4d","#ffb547","#fcaa4c","#fcd64c","#fff6ba"],
behavior: [
"XX|CR:fire%0.08|XX",
"XX|XX|XX",
"XX|XX|XX"
],
tempHigh: 11052,
category: "solids",
density: 15064,
conduct: 0.52,
hardness: 0.8,
tick: function(pixel) {
threshholdedPyrogen(pixel,8932,2.03,416);
inferniumTempFire(pixel,25000,0.4); //pyrotheum makes a lot of fire
},
};
function pyrestoneInfernyreitheumReaction(pyrestoneName) {
return {
elem1: "molten_pyrinfernyreitheum",
elem2: [pyrestoneName,pyrestoneName,"molten_pyrinfernyreitheum"],
temp1: 3085,
temp2: 3085
};
};
elements.molten_infernyreitheum = {
tick: function(pixel) {
pixel.temp += 2.03;
inferniumTempFire(pixel,25000,0.4);
},
reactions: {
unignited_pyrestone: pyrestoneInfernyreitheumReaction("unignited_pyrestone"),
ignited_pyrestone: pyrestoneInfernyreitheumReaction("ignited_pyrestone"),
heated_pyrestone: pyrestoneInfernyreitheumReaction("heated_pyrestone"),
burning_pyrestone: pyrestoneInfernyreitheumReaction("burning_pyrestone"),
blazing_pyrestone: pyrestoneInfernyreitheumReaction("blazing_pyrestone"),
fiery_pyrestone: pyrestoneInfernyreitheumReaction("fiery_pyrestone")
}
};
elements.pyrinfernyreitheum = {
color: ["#e6c087","#f7c76d","#ffd79c","#ffd79c","#ffe387","#ffffd9"],
behavior: [
"XX|CR:fire%2|XX",
"XX|XX|XX",
"XX|XX|XX"
],
tempHigh: 18254,
category: "solids",
density: 17042,
conduct: 0.25,
hardness: 0.8,
tick: function(pixel) {
threshholdedPyrogen(pixel,15944,7.01,352);
inferniumTempFire(pixel,15000,0.8); //pyrotheum makes a lot of fire
},
};
elements.molten_pyrinfernyreitheum = {
tick: function(pixel) {
pixel.temp += 7.01;
inferniumTempFire(pixel,15000,0.8); //pyrotheum makes a lot of fire
}
};
//MORE MORTAL PLANTS ##
var killerArray = ["radiation", "alcohol", "soap", "acid", "ammonia", "acid_gas", "bleach", "poison", "ice_nine", "methanol", "propanol", "butanol", "isopropanol", "phenol"]; //https://pubmed.ncbi.nlm.nih.gov/16986801/
var plantArray = ["plant", "frozen_plant", "grass", "algae", "sapling", "seeds", "grass_seed", "wheat_seed", "wheat", "flower_seed", "pistil", "petal", "vine", "bamboo", "bamboo_plant", "corn_seed", "potato_seed", "root", "berry_seed", "old_berry_leaf", "berry_leaf", "berry", "banana_pseudostem", "banana_peduncle_1", "banana_peduncle_2", "petal", "banana_leaf", "banana_plant_top"];
runAfterAutogen(function() {
//Try to detect radioactive elements (it's not perfect, but it's better than nothing)
var rads = Object.keys(elements).filter(function(name) {
return !!((elements[name].behavior ?? "undefined").toString().match(/C[RH]:[A-Za-z0-9_,]*radiation/))
});
killerArray = killerArray.concat(rads);
for(i = 0; i < killerArray.length; i++) {
if(!elements[killerArray[i]].reactions) {
elements[killerArray[i]].reactions = {}
}
for(j = 0; j < plantArray.length; j++) {
elements[killerArray[i]].reactions[plantArray[j]] = { "elem1":null, "elem2":"dead_plant" }
};
};
});
//PAINT EVENT ##
randomEvents.paint = function() {
// set the color of a random circle to a random color
var x = Math.floor(Math.random()*(width-1))+1;
var y = Math.floor(Math.random()*(height-1))+1;
var randomR = Math.floor(Math.random() * 256);
var randomG = Math.floor(Math.random() * 256);
var randomB = Math.floor(Math.random() * 256);
var radius = Math.floor(Math.random()*5)+2;
var rColor = "rgb(" + randomR + "," + randomG + "," + randomB + ")";
var coords = circleCoords(x,y,radius);
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];
if (!outOfBounds(coord.x,coord.y) && !isEmpty(coord.x,coord.y)) {
pixelMap[coord.x][coord.y].color = rColor;
};
};
};
//CONFIGURABLE PAGE BACKGROUND COLOR ##
var backgroundUseStrings = ["bg","background","settings.bg"]
if(urlParams.get('pageColor') != null) { //null check
//Old method (as a query parameter)
color = urlParams.get('pageColor');
if(color === "" || color === null) { //NaN check
color = "black";
};
if(backgroundUseStrings.includes(color.toLowerCase())) {
!settings.bg ? color = "black" : color = settings.bg;
color = settings.bg;
};
color_Would_Be_A_Triplet_If_It_Started_With_An_Octothorpe = null;
color_Is_Supported_As_A_Background_By_The_Browser = null;
if( /^#([0-9A-F]{3}){1,2}$/i.test("#" + color) ) {
color_Would_Be_A_Triplet_If_It_Started_With_An_Octothorpe = true
} else {
color_Would_Be_A_Triplet_If_It_Started_With_An_Octothorpe = false
}
if( CSS.supports('background',color) ) {
color_Is_Supported_As_A_Background_By_The_Browser = true
} else {
color_Is_Supported_As_A_Background_By_The_Browser = false
}
if(color_Is_Supported_As_A_Background_By_The_Browser == false && color_Would_Be_A_Triplet_If_It_Started_With_An_Octothorpe == true) {
color = "#" + color
}
document.body.style.background = color;
} else {
//As a setting
runAfterLoad(function() {
var settingsMenu = document.getElementById("settingsMenu").getElementsByClassName("menuText")[0];
var settingNodes = [...settingsMenu.childNodes].filter(function(node) { return node.nodeType == 1 });
var lastSetting = settingNodes[settingNodes.length - 1];
//console.log(lastSetting);
//console.log(lastSetting.getAttribute("style"));
//console.log(lastSetting.getAttribute("style"));
//Shape setting
var bgSettingSpan = document.createElement("span");
bgSettingSpan.setAttribute("setting","pageBG");
bgSettingSpan.setAttribute("class","setting-span");
bgSettingSpan.textContent = "Page Background ";
var settingPicker = document.createElement("input");
settingPicker.setAttribute("type","color");
settingPicker.setAttribute("value",settings.pageBG ?? _cc.b.h);
settingPicker.setAttribute("onchange","settings.pageBG = this.value; document.body.style.background = this.value; saveSettings();");
bgSettingSpan.appendChild(settingPicker);
settingsMenu.appendChild(bgSettingSpan);
});
settings.pageBG ??= _cc.b.h; saveSettings();
document.body.style["background-color"] = settings.pageBG;
};
//GASEOUS FORMS AND BOILING OF SOME ELEMENTS ##
//glass {
elements.molten_glass ??= {};
elements.molten_glass.tempHigh = 2200,
elements.molten_glass.stateHigh = "vaporized_glass",
elements.molten_rad_glass ??= {};
elements.molten_rad_glass.tempHigh = 2200,
elements.molten_rad_glass.stateHigh = "vaporized_rad_glass",
elements.molten_stained_glass.tempHigh = 2200,
elements.vaporized_glass = {
color: ["#D6B049","#E8D957","#E8AE57"],
behavior: [
"M2|M1 AND CR:fire%0.5|M2",
"M1 AND CR:fire%0.4|XX|M1 AND CR:fire%0.4",
"M2|M1 AND CR:fire%0.3|M2",
],
reactions: {
"vaporized_glass": { "elem1": null, "elem2": "hot_glass_cloud", "chance":0.3, "y":[0,15] },
"hot_glass_cloud": { "elem1": "hot_glass_cloud", "chance":0.4, "y":[0,15] },
},
density: 2, //very rough approximation based on https://nvlpubs.nist.gov/nistpubs/jres/46/jresv46n3p176_A1b.pdf
temp: 2300, //https://www.sciencealert.com/did-this-piece-of-glass-really-break-a-law-of-thermodynamics
tempLow: 2200,
stateLow: "molten_glass",
category: "gases",
state: "gas",
hidden: true
},
elements.vaporized_rad_glass = {
color: ["#D7D74A","#D6F58A","#ECD96C"],
behavior: [
"M2|M1 AND CR:radiation%0.1 AND CR:fire%0.5|M2",
"M1 AND CR:radiation%0.1 AND CR:fire%0.4|XX|M1 AND CR:radiation%0.1 AND CR:fire%0.4",
"M2|M1 AND CR:radiation%0.1 AND CR:fire%0.3|M2",
],
reactions: {
"vaporized_rad_glass": { "elem1": null, "elem2": "hot_rad_glass_cloud", "chance":0.3, "y":[0,15] },
"hot_rad_glass_cloud": { "elem1": "hot_rad_glass_cloud", "chance":0.4, "y":[0,15] },
"vaporized_glass": { "elem1": null, "elem2": "hot_rad_glass_cloud", "chance":0.3, "y":[0,15] },
"hot_glass_cloud": { "elem1": "hot_rad_glass_cloud", "chance":0.4, "y":[0,15] },
},
density: 2,
temp: 2300,
tempLow: 2200,
stateLow: "molten_rad_glass",
category: "gases",
state: "gas",
hidden: true
},
elements.hot_glass_cloud = {
color: ["#B69089","#C8B997","#C88E77"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_glass%0.05|M1%7",
"XX|XX|XX",
],
density: 2,
temp: 2300,
tempLow: 2200,
stateLow: "cold_glass_cloud",
category: "gases",
state: "gas"
},
elements.cold_glass_cloud = {
color: ["#967089","#A89997","#A86E77"],
behavior: [
"XX|XX|XX",
"M1%7|CH:glass_shard%0.05|M1%7",
"XX|XX|XX",
],
density: 2,
temp: 2000,
tempHigh: 2200,
stateHigh: "hot_glass_cloud",
category: "gases",
state: "gas"
},
elements.hot_rad_glass_cloud = {
color: ["#B9B389","#CED994","#D1C087"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_rad_glass%0.05|M1%7",
"XX|XX|XX",
],
density: 2,
temp: 2300,
tempLow: 2200,
stateLow: "cold_rad_glass_cloud",
category: "gases",
state: "gas"
},
elements.cold_rad_glass_cloud = {
color: ["#A99FAD","#BDBB87","#BB8C77"],
behavior: [
"XX|XX|XX",
"M1%7|CH:rad_glass_shard%0.05|M1%7",
"XX|XX|XX",
],
density: 2,
temp: 2000,
tempHigh: 2200,
stateHigh: "hot_rad_glass_cloud",
category: "gases",
state: "gas"
},
//}
// nitroglycerin {
elements.nitro_gas = {
color: "#89d162",
behavior: behaviors.GAS,
behaviorOn: [
"XX|XX|XX",
"XX|EX:10|XX",
"XX|XX|XX",
],
conduct: 1,
category: "weapons",
tempHigh: 218,
stateHigh: "explosion",
tempLow: 50,
stateLow: "nitro",
burn: 100,
burnTime: 1,
burnInto: "explosion",
breakInto: "explosion",
viscosity: 36,
state: "liquid",
density: 1600,
excludeRandom: true,
alias: "nitroglycerin gas"
};
elements.nitro.tempHigh = 50;
elements.nitro.stateHigh = "nitro_gas";
//}
// ash {
elements.ash.tempHigh = 1200 //https://www.quora.com/Can-you-melt-ashes
elements.ash.stateHigh = "molten_ash" //https://www.sciencedirect.com/science/article/pii/S1877705817326772
elements.molten_ash = {
color: ["#df6f30","#df8c30","#df4d30"],
behavior: behaviors.MOLTEN,
temp: 1300,
tempLow: 1200,
stateLow: "ash",
tempHigh: 1700, //https://authors.library.caltech.edu/58447/1/018-Senior.pdf
//https://pubs.acs.org/doi/10.1021/ef049693l
stateHigh: "vaporized_ash",
viscosity: 10000,
category: "liquids",
state: "liquid",
density: 2725
},
elements.vaporized_ash = {
color: ["#df9f50","#dfbc50","#df7d50"],
behavior: [
"M2|M1|M2",
"M1|XX|M1",
"M2|M1|M2",
],
reactions: {
"vaporized_ash": { "elem1": null, "elem2": "hot_ash_cloud", "chance":0.3, "y":[0,15] },
"hot_ash_cloud": { "elem1": "hot_ash_cloud", "chance":0.4, "y":[0,15] },
},
temp: 1800,
tempLow: 1700,
stateLow: "molten_ash",
category: "gases",
state: "gas",
hidden: true,
density: 3
},
elements.hot_ash_cloud = {
color: ["#bf8f50","#bfac50","#bf7d50"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_ash%0.05|M1%7",
"XX|XX|XX",
],
density: 0.7,
temp: 1800,
tempLow: 1700,
stateLow: "cold_ash_cloud",
category: "gases",
state: "gas"
},
console.log("3/8 loaded");
elements.cold_ash_cloud = {
color: ["#af8f50","#ab9c50","#af6d50"],
behavior: [
"XX|XX|XX",
"M1%7|CH:ash%0.05|M1%7",
"XX|XX|XX",
],
density: 0.7,
temp: 1600,
tempHigh: 1700,
stateHigh: "hot_ash_cloud",
category: "gases",
state: "gas"
},
//}
//carbon dioxide {
/*fuck this, i can't work out the offset-infested math
function carbonDioxideDecompRatio(temp) {
//
// K is the ratio of O_2 to CO_2
// If K = 100, there is 100 times more O_2
// If K = 1, there is a 1:1 ratio
//
return Math.E**(((1110190+(13.083*(temp-298)))-(temp*(149.498+(13.083*(Math.log(temp/298))))))/(-8.31446*temp))
}
function carbonDioxideDecompChance(temp) {
//Expected 0.5 at 6275.6434478747902
if(typeof(temp) === "undefined") {
throw new Error("Temp must be specified~");
};
if(typeof(temp) == "string") {
temp = parseFloat(temp);
};
if(isNaN(temp)) {
throw new TypeError(typeof(temp) == "number" ? "Temp cannot be NaN~" : "Temp must be a number~");
};
if(temp == Infinity) {
return 1;
};
if(temp <= 0) {
return 0;
};
var K = carbonDioxideDecompRatio(temp);
return 1-(1/(K+1));
};
*/
//Mass given is the molar mass of O_2 molecule (31.999 g)
//O_2 bond energy is 495 kJ/mol
//Heat capacity is 0.918 J/(g*K)
//in case the link goes down: c = Q/(m * delta-T); c = capacity, m = mass, delta-T = temp change, energy = Q
//https://www.calctool.org/thermodynamics/specific-heat
tupleAdverbs = ['Nullly', 'Singly', 'Doubly', 'Triply', 'Quadruply', 'Quintuply', 'Sextuply', 'Septuply', 'Octuply', 'Nonuply', 'Decuply', 'Undecuply', 'Duodecuply', 'Tredecuply', 'Quattuordecuply', 'Quindecuply', 'Sexdecuply', 'Septendecuply', 'Octodecuply', 'Novemdecuply', 'Vigintuply', 'Unvigintuply', 'Duovigintuply', 'Trevigintuply', 'Quattuorvigintuply', 'Quinvigintuply', 'Sexvigintuply', 'Septenvigintuply', 'Octovigintuply', 'Novemvigintuply', 'Trigintuply'].map(x => x.toLowerCase());
//}
// baking soda {
elements.baking_soda.tempHigh = 150,
elements.baking_soda.stateHigh = ["water","carbon_dioxide","calcined_soda"]
// decomposition result {
elements.calcined_soda = { //TODO: decomposition?
color: "#ededed",
behavior: behaviors.POWDER,
reactions: {
"water": { "elem1": "washing_soda", "elem2": null } //should be 10x water
//"carbon_dioxide": not possible: Na_{2}CO_{3} + CO_{2} + H_{2}O → 2NaHCO_{3}
},
category: "powders",
state: "solid",
density: 2540,
tempHigh: 851,
}
if(!elements.molten_calcined_soda) {
elements.molten_calcined_soda = {}
}
elements.molten_calcined_soda.temp = 1700
elements.molten_calcined_soda.tempHigh = 1600
elements.molten_calcined_soda.stateHigh = "vaporized_calcined_soda"
elements.molten_calcined_soda.density = 1920
elements.vaporized_calcined_soda = {
color: ["#ffbf60","#ffdc60","#ff9d60"],
behavior: [
"M2|M1|M2",
"M1|XX|M1",
"M2|M1|M2",
],
reactions: {
"vaporized_calcined_soda": { "elem1": null, "elem2": "hot_calcined_soda_cloud", "chance":0.3, "y":[0,15] },
"hot_calcined_soda_cloud": { "elem1": "hot_calcined_soda_cloud", "chance":0.4, "y":[0,15] },
},
temp: 1700,
tempLow: 1600,
stateLow: "molten_calcined_soda",
category: "gases",
state: "gas",
hidden: true,
density: 1.5, //bs
},
elements.hot_calcined_soda_cloud = {
color: ["#cfbf70","#cfcc70","#cf9d70"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_calcined_soda%0.05|M1%7",
"XX|XX|XX",
],
density: 0.7,
temp: 1700,
tempLow: 1600,
stateLow: "cold_calcined_soda_cloud",
category: "gases",
state: "gas",
},
elements.cold_calcined_soda_cloud = {
color: ["#afaf70","#afac70","#af8d70"],
behavior: [
"XX|XX|XX",
"M1%7|CH:calcined_soda%0.05|M1%7",
"XX|XX|XX",
],
density: 0.7,
temp: 1500,
tempHigh: 1600,
stateHigh: "hot_calcined_soda_cloud",
category: "gases",
state: "gas",
},
//}
// decomp hydrate {
elements.washing_soda = {
color: "#ededed",
behavior: behaviors.POWDER,
//no reactions because it always requires ******* water
category: "powders",
state: "solid",
density: 1460,
tempHigh: 400,
stateHigh: ["water","calcined_soda"],
}
//}
//alkalinities {
elements.acid.reactions.baking_soda = { "elem1":"neutral_acid", "elem2":null }
elements.acid.reactions.calcined_soda = { "elem1":"neutral_acid", "elem2":null }
elements.acid.reactions.washing_soda = { "elem1":"neutral_acid", "elem2":null }
//}
//}
// calcium {
elements.molten_calcium = {
tempHigh: 2200,
stateHigh: "vaporized_calcium",
}
elements.vaporized_calcium = {
color: ["#ffc94a", "#fcd34c", "#ffae36", "#ff9c40","#ffcd90","#cf8d50"],
behavior: [
"M2|M1|M2",
"M1|XX|M1",
"M2|M1|M2",
],
reactions: {
"vaporized_calcium": { "elem1": null, "elem2": "hot_calcium_cloud", "chance":0.3, "y":[0,15] },
"hot_calcium_cloud": { "elem1": "hot_calcium_cloud", "chance":0.4, "y":[0,15] },
},
density: 1.5, //most of these density values are complete bullshit due to a lack of research
temp: 1550,
tempLow: 1484,
stateLow: "molten_calcium",
category: "gases",
state: "gas",
hidden: true
},
elements.hot_calcium_cloud = {
color: ["#dfa98a", "#dcb38c", "#df8e76", "#ef8c60","#efbdb0","#af8d70"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_calcium%0.05|M1%7",
"XX|XX|XX",
],
density: 1.5,
temp: 1550,
tempLow: 842,
stateLow: "cold_calcium_cloud",
category: "gases",
state: "gas"
},
elements.cold_calcium_cloud = {
color: ["#bf998a", "#bca38c", "#bf8e76", "#cf8c60","#cfadb0","#9f8d70"],
behavior: [
"XX|XX|XX",
"M1%7|CH:calcium%0.05|M1%7",
"XX|XX|XX",
],
density: 2,
temp: 800,
tempHigh: 842,
stateHigh: "hot_calcium_cloud",
category: "gases",
state: "gas",
}
//}
// clay {
if(!elements.baked_clay) {
elements.baked_clay = {}
}
elements.baked_clay.tempHigh = 1600 //the range of melting points online is so fucking wide
elements.baked_clay.stateHigh = "molten_clay"
elements.molten_clay = {
color: ["#ff6d23","#ff5723","#ff4100"],
behavior: [
"XX|CR:fire%2.5|XX",
"M2|XX|M2",
"M1|M1|M1",
],
temp: 1700,
tempLow: 1600,
stateLow: "baked_clay",
viscosity: 10000,
hidden: true,
state: "liquid",
density: 1800,
tempHigh: 2980,
stateHigh: "vaporized_clay",
category: "liquids",
}
elements.vaporized_clay = {
color: ["#ff8d43","#ff7743","#ff6120"],
behavior: [
"M2|M1|M2",
"M1|XX|M1",
"M2|M1|M2",
],
reactions: {
"vaporized_clay": { "elem1": null, "elem2": "hot_clay_cloud", "chance":0.3, "y":[0,15] },
"hot_clay_cloud": { "elem1": "hot_clay_cloud", "chance":0.4, "y":[0,15] },
},
density: 1.6,
temp: 1700,
tempLow: 1600,
stateLow: "molten_clay",
category: "gases",
state: "gas",
hidden: true
},
elements.hot_clay_cloud = {
color: ["#ff9945", "#fca347", "#ff7e31"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_clay%0.05|M1%7",
"XX|XX|XX",
],
density: 1.5,
temp: 1550,
tempLow: 842,
stateLow: "cold_clay_cloud",
category: "gases",
state: "gas"
},
elements.cold_clay_cloud = {
color: ["#ef7945", "#ec8347", "#ef5e31"],
behavior: [
"XX|XX|XX",
"M1%7|CH:baked_clay%0.05|M1%7",
"XX|XX|XX",
],
density: 2,
temp: 800,
tempHigh: 842,
stateHigh: "hot_clay_cloud",
category: "gases",
state: "gas"
},
//}
// salt {
elements.molten_salt = {
tempHigh: 1465,
stateHigh: "vaporized_salt",
}
elements.vaporized_salt = {
color: ["#ff9f60","#ffbc60","#ff7d60"],
behavior: [
"M2|M1|M2",
"M1|XX|M1",
"M2|M1|M2",
],
reactions: {
"vaporized_salt": { "elem1": null, "elem2": "hot_salt_cloud", "chance":0.3, "y":[0,15] },
"hot_salt_cloud": { "elem1": "hot_salt_cloud", "chance":0.4, "y":[0,15] },
},
density: 1946,
temp: 1550,
tempLow: 1465,
stateLow: "molten_salt",
category: "gases",
state: "gas",
hidden: true
},
elements.hot_salt_cloud = {
color: ["#ef8f30","#efac60","#ef6d60"],
behavior: [
"XX|XX|XX",
"M1%7|CH:molten_salt%0.05|M1%7",
"XX|XX|XX",
],
density: 2.2,
temp: 1550,
tempLow: 801,
stateLow: "cold_salt_cloud",
category: "gases",
state: "gas"
},
elements.cold_salt_cloud = {
color: ["#cf7f60","#cf9c60","#cf7d60"],
behavior: [
"XX|XX|XX",
"M1%7|CH:salt%0.05|M1%7",
"XX|XX|XX",
],
density: 2.2,
temp: 700,
tempHigh: 801,
stateHigh: "hot_salt_cloud",
category: "gases",
state: "gas",
}
//}
runAfterLoad(function() {
if(elements.acid_gas.tempHigh) {
delete elements.acid_gas.tempHigh
}
if(elements.acid_gas.stateHigh) {
delete elements.acid_gas.stateHigh
}
elements.acid.stateHigh = "acid_gas"
elements.acid_gas.tempLow = 400
elements.acid_gas.stateLow = "acid"
elements.yogurt.tempHigh = 400
elements.yogurt.stateHigh = "ash"
elements.dust.tempHigh = 400
elements.dust.stateHigh = "fire"
elements.concoction.reactions.vaporized_glass = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.hot_glass_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.cold_glass_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.molten_ash = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.vaporized_ash = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.hot_ash_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.cold_ash_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.calcined_soda = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.molten_calcined_soda = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.vaporized_calcined_soda = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.hot_calcined_soda_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.cold_calcined_soda_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.washing_soda = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.vaporized_calcium = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.hot_calcium_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.cold_calcium_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.molten_clay = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.vaporized_clay = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.hot_clay_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.cold_clay_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.vaporized_salt = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.hot_salt_cloud = { "elem1": "mistake", "elem2": null }
elements.concoction.reactions.cold_salt_cloud = { "elem1": "mistake", "elem2": null }
});
//CHLORINE TRIFLUORIDE ##
function finishBurn(pixel) {
var info = elements[pixel.element];
var burnInto = info.burnInto;
if (burnInto == undefined) {
burnInto = 'fire';
}
else if (burnInto instanceof Array) {
burnInto = burnInto[Math.floor(Math.random()*burnInto.length)];
}
if (burnInto == undefined) {
burnInto = 'fire';
}
changePixel(pixel,burnInto,(burnInto !== "smoke"));
if (info.fireColor != undefined && burnInto == "fire") {
pixel.color = pixelColorPick(pixel,info.fireColor);
}
else {
pixel.color = pixelColorPick(pixel)
}
};
function clf3Tick(pixel) {
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pixel.x+oX;
var fY = pixel.y+oY;
if(!isEmpty(fX,fY,true)) {
var otherPixel = pixelMap[fX][fY];
var otherElement = otherPixel.element;
if(otherElement === "water") {
explodeAt(otherPixel.x,otherPixel.y,7,"fire,hydrofluoric_acid,oxygen,acid,chlorine")
};
if(!elements.chlorine_trifluoride.ignore.includes(otherElement)) {
if(!otherPixel.burning) { otherPixel.burning = true };
if(!otherPixel.burnStart) { otherPixel.burnStart = pixelTicks };
var instaburnChance = 0.05 + (pixelTicks - otherPixel.burnStart) / 1000
if(Math.random() < instaburnChance) {
finishBurn(otherPixel);
};
};
};
};
};
var clf3IgnoreList = ["foof","solid_foof","oxygen","liquid_oxygen","oxygen_ice","chlorine","liquid_chlorine","liquid_hydrogen_fluoride","liquid_fluorine","fluorine","fluorine_ice","hydrogen_fluoride","hydrofluoric_acid","hydrofluoric_acid_gas","fire","acid_gas","neutral_acid","acid","acid_cloud","nitrogen","helium","liquid_helium","tralphium","liquid_tralphium","neon","liquid_neon","solid_neon","neon_ice","neon_snow","argon","liquid_argon","solid_argon","argon_ice","argon_snow", "krypton","liquid_krypton","solid_krypton","krypton_ice","krypton_snow", "xenon","liquid_xenon","solid_xenon","xenon_ice","xenon_snow", "radon","liquid_radon","solid_radon","radon_ice","radon_snow","ionized_helium","ionized_tralphium","wall","chlorine_trifluoride","chlorine_trifluoride_ice","chlorine_trifluoride_gas","quartz"];
//todo: PTFE, passivation
elements.chlorine_trifluoride = {
color: "#8aa65b",
behavior: behaviors.LIQUID,
//ignore list copied from chem.js
ignore: clf3IgnoreList, //the elements that don't exist won't trigger any error here becuase the code's just checking pixels' elements against this list
tick: function(pixel) {
clf3Tick(pixel);
},
category:"liquids",
state: "liquid",
density: 1770,
tempLow: -76.34,
tempHigh: 11.75,
temp: 5,
};
elements.chlorine_trifluoride_gas = {
tick: function(pixel) {
clf3Tick(pixel);
},
density: 3.78, //variously or 3.18,
//tempHigh: 220, //variously or 180,
//stateHigh: ["chlorine_fluoride","fluorine"],
};
elements.chlorine_trifluoride_ice = {
tick: function(pixel) {
clf3Tick(pixel);
},
};
//GLENN'S GASES PARTIAL PORT ##
//Glenn's Gases is licensed under the GNU LGPL.
//http://www.gnu.org/licenses/lgpl.html
//https://www.jamieswhiteshirt.com/minecraft/mods/gases/information/?Licensing
//Coal exists in NM
runAfterLoad(function() {
elements.coal.breakInto = "coal_dust"
});
elements.coal_dust = {
color: "#363023",
behavior: behaviors.GAS,
tick: function(pixel) {
if(pixel.burning) {
explodeAt(pixel.x,pixel.y,5,"fire,ignited_gas")
}
},
category: "gases",
density: 561,
state: "gas",
burn: 132,
burnTime: 10,
burnInto: ["ash", "fire", "carbon_dioxide"],
};
//Chlorine exists.
//Natural gas is mostly ammonia, which exists.
elements.red_gas = {
color: "#c74c52",
behavior: behaviors.GAS,
tick: function(pixel) {
if(pixel.burning) {
explodeAt(pixel.x,pixel.y,8,"fire,ignited_gas")
}
},
category: "gases",
density: 1.5,
state: "gas",
burn: 300,
burnTime: 10,
burnInto: ["fire", "explosion", "explosion"],
};
elements.nitrous_gas = {
color: "#854428",
behavior: behaviors.GAS,
reactions: {
"water": {"elem1": "acidic_vapour", "elem2": "acidic_vapour"}
},
category: "gases",
density: 1.5,
state: "gas",
};
elements.acidic_vapour = {
color: ["#5282d1", "#4e6fad"],
behavior: [
"M2|M1 AND DB|M2",
"M1 AND DB|XX|M1 AND DB",
"M2%50|M1%50 AND DB|M2%50",
],
ignore: elements.acid.ignore,
category: "gases",
density: 1.5,
state: "gas",
};
elements.void_gas = {
color: "#111111",
behavior: behaviors.GAS,
reactions: {
"light": { "elem1": null, "chance": 0.1 },
"fire": { "elem1": null, "chance": 0.08 }
},
category: "gases",
density: 1.5,
state: "gas",
};
elements.electric_gas = {
color: ["#3693b3", "#246e64"],
behavior: [
"M2%33.3 AND CR:electric%1 AND CR:lightning%0.005|M1%33.3 AND CR:electric%1 AND CR:lightning%0.005|M2%33.3 AND CR:electric%1 AND CR:lightning%0.005",
"M1%33.3 AND CR:electric%1 AND CR:lightning%0.005|XX%000000000000000000000000000000000000000000000|M1%33.3 AND CR:electric%1 AND CR:lightning%0.005",
"M2%33.3 AND CR:electric%1 AND CR:lightning%0.005|M1%33.3 AND CR:electric%1 AND CR:lightning%0.005|M2%33.3 AND CR:electric%1 AND CR:lightning%0.005",
],
hardness: 0.8,
reactions: {
"corrosive_gas": { "elem2": "turquoise_dust", "elem1": "blue_dust", "chance": 0.5 },
"blue_dust": { "elem1": null, "elem2": "turquoise_dust", "chance": 0.5 }
},
category: "gases",
density: 1.225,
state: "gas"
};
corrosiveGasMaxHardness = 0.6
elements.corrosive_gas = {
color: ["#2929e6", "#151cad"],
behavior: [
"M2%33.3|M1%33.3|M2%33.3",
"M1%33.3|XX%0000|M1%33.3",
"M2%33.3|M1%33.3|M2%33.3",
],
hardness: 0.8,
tick: function(pixel) {
//delete neighbors
for(i = 0; i < adjacentCoords.length; i++) {
nx = pixel.x + adjacentCoords[i][0];
ny = pixel.y + adjacentCoords[i][1];
if(!isEmpty(nx,ny,true)) {
if((elements[pixelMap[nx][ny].element].hardness || 0) <= corrosiveGasMaxHardness) {
if(Math.random() < 0.2) {
if(Math.random() < 1 - ((pixel.hardness || 0))) {
deletePixel(nx,ny);
};
};
};
};
};
},
reactions: {
"electric_gas": { "elem2": "blue_dust", "elem1": "turquoise_dust", "chance": 0.5 },
"turquoise_dust": { "elem1": null, "elem2": "blue_dust", "chance": 0.5 }
},
category: "gases",
density: 1.225,
state: "gas",
};
elements.blue_dust = {
color: ["#063ca1", "#042d94", "#063ca1", "#042d94", "#1d66ff"],
behavior: behaviors.POWDER,
hardness: 0.6,
category: "powders",
state: "solid",
density: 1600,
}
elements.turquoise_dust = {
color: ["#12a6a6","#1aa3a3","#12a6a6","#1aa3a3","#00ffff"],
behavior: behaviors.POWDER,
hardness: 0.6,
category: "powders",
state: "solid",
density: 1600,
}
if(!settings) {
settings = {}
}
if(!settings.bg) {
settings.bg = _cc.b.h
}
elements.black_damp = {
behavior: behaviors.GAS,
reactions: {
"fire": { elem2: null }
},
renderer: function(pixel,ctx) {
if(view == 2) { viewInfo[2].pixel(pixel,ctx); return };
if(currentElement == pixel.element || shiftDown) {
ctx.globalAlpha = 0.6;
ctx.fillStyle = "#000000";
//ctx.fillRect((pixel.x + 0.25) * pixelSize, (pixel.y + 0.25) * pixelSize, 0.5 * pixelSize, 0.5 * pixelSize);
ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize);
}
},
hardness: 0.6,
category: "gases",
density: 1.225,
state: "gas",
};
if(!elements.torch.reactions) {
elements.torch.reactions = {}
}
elements.torch.reactions.black_damp = { elem1: "wood" }
elements.rock_dust = {
color: "#878783",
behavior: behaviors.GAS,
reactions: {
"water": {"elem1": "dirty_water", "elem2": null }
},
category: "gases",
density: 2.45,
state: "gas",
tempHigh: 950,
stateHigh: [null,null,null,null,"magma"],
}
elements.rock.breakInto.push("rock_dust")
lightArray = ["fire", "plasma", "cold_fire", "light", "laser", "electric", "radiation", "mystic_fire", "liquid_fire", "liquid_plasma", "liquid_cold_fire", "le_liquid_light", "liquid_laser", "liquid_electric", "liquid_radiation", "liquid_mystic_fire", "magma", "liquid_light", "solid_light"]
ledArray = ["led_r", "led_g", "led_b"]
elements.iocalfaeus_gas = {
color: ["#562173", "#481b61"],
behavior: behaviors.GAS,
tick: function(pixel) {
if(!pixel.hot) {
pixel.hot = false
}
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if ((lightArray.includes(pixelMap[pixel.x+j][pixel.y+i].element)) || (pixelMap[pixel.x+j][pixel.y+i].temp >= 525) || (ledArray.includes(pixelMap[pixel.x+j][pixel.y+i].element) && pixelMap[pixel.x+j][pixel.y+i].charge)) {
pixel.hot = true
}
}
}
}
if(pixel.hot == true) {
pixel.temp += 16
}
if(pixel.hot == true && Math.random() < 0.02) {
pixel.hot = false
}
},
category: "gases",
density: 0.97,
state: "gas",
}
//Helium exists.
finineRange = 6
elements.finine = {
color: ["#ffffec", "#fafade", "#ebebd5", "#c9c9b7", "#80806f"],
behavior: [
"M2%33.3|M1%33.3|M2%33.3",
"M1%33.3|XX%0000|M1%33.3",
"M2%33.3|M1%33.3|M2%33.3",
],
tick: function(pixel) {
for(i = 0; i < adjacentCoords.length; i++) {
nx = pixel.x + adjacentCoords[i][0];
ny = pixel.y + adjacentCoords[i][1];
if(!isEmpty(nx,ny,true)) {
if (lifeArray.includes(pixelMap[nx][ny].element)) {
pixel.eeex = pixel.x + Math.floor(Math.random() * ((2 * finineRange) + 1)) - finineRange
pixel.eeey = pixel.y + Math.floor(Math.random() * ((2 * finineRange) + 1)) - finineRange
//if human
//handle heads
if(pixelMap[nx][ny].element == "head") {
if(isEmpty(pixel.eeex,pixel.eeey,false) && isEmpty(pixel.eeex,pixel.eeey+1,false)) {
tryMove(pixelMap[nx][ny],pixel.eeex,pixel.eeey)
tryMove(pixelMap[nx][ny+1],pixel.eeex,pixel.eeey+1)
};
} else if(pixelMap[nx][ny].element == "body") {
if(isEmpty(pixel.eeex,pixel.eeey,false) && isEmpty(pixel.eeex,pixel.eeey-1,false)) {
tryMove(pixelMap[nx][ny],pixel.eeex,pixel.eeey)
tryMove(pixelMap[nx][ny-1],pixel.eeex,pixel.eeey-1)
};
} else {
if(isEmpty(pixel.eeex,pixel.eeey,false)) {
tryMove(pixelMap[nx][ny],pixel.eeex,pixel.eeey)
};
};
};
};
};
},
category: "gases",
density: 1.225,
state: "gas",
}
//Smoke exists.
elements.ignited_gas = {
color: ["#fc9a58", "#faae3c", "#ffef3d"],
behavior: [
"M2|M1 AND CR:fire%0.5|M2",
"M1 AND CR:fire%0.5|XX|M1 AND CR:fire%0.5",
"M2|M1 AND CR:fire%0.5|M2",
],
category: "gases",
state: "gas",
density: 0.306,
burning: true,
burnTime: 30,
temp: elements.fire.temp,
burnInto: ["fire","smoke"],
hidden: true,
}
//Diabaline
elements.diabaline = {
color: "#7e4e9c",
behavior: behaviors.POWDER,
tick: function(pixel) {
if(!pixel.glow) {
pixel.glow = false
}
if(!pixel.oldColor) {
pixel.oldColor = pixel.color
}
if(!pixel.rA) {
pixel.rA = 0
}
if(!pixel.gA) {
pixel.gA = 0
}
if(!pixel.bA) {
pixel.bA = 0
}
if(!pixel.rB) {
pixel.rB = 0
}
if(!pixel.gB) {
pixel.gB = 0
}
if(!pixel.bB) {
pixel.bB = 0
}
if(!pixel.finalR) {
pixel.finalR = 0
}
if(!pixel.finalG) {
pixel.finalG = 0
}
if(!pixel.finalB) {
pixel.finalB = 0
}
if(!pixel.finalColor) {
pixel.finalColor = ""
}
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
if (elements[pixelMap[pixel.x+j][pixel.y+i].element].category == "gases") {
pixel.glow = true
}
}
}
}
if(pixel.glow == true) {
if(pixel.oldColor.split(",")) {
pixel.rA = pixel.oldColor.split(",")[0].slice(4)
pixel.gA = pixel.oldColor.split(",")[1]
pixel.bA = pixel.oldColor.split(",")[2].slice(0,-1)
pixel.finalR = parseInt(pixel.rA) + 86
pixel.finalG = parseInt(pixel.gA) + 93
pixel.finalB = parseInt(pixel.bA) + 81
pixel.finalColor = "rgb(" + pixel.finalR + "," + pixel.finalG + "," + pixel.finalB + ")"
pixel.color = pixel.finalColor
};
}
if(pixel.glow == true && Math.random() < 0.02) {
pixel.glow = false
}
if(pixel.glow == false) {
pixel.color = pixel.oldColor
}
},
category: "solids",
density: 1500,
state: "solid",
}
runAfterLoad(function() {
lifeArray = Object.keys(elements).filter(function(e) {
return elements[e].category == "life";
});
if(!elements.void_gas.reactions) {
elements.void_gas.reactions = {}
};
for(i = 0; i < lifeArray.length; i++) {
elements.void_gas.reactions[lifeArray[i]] = { "elem2": null, "chance": 0.7 }
};
for(i = 0; i < lifeArray.length; i++) {
elements.black_damp.reactions[lifeArray[i]] = { "elem2": null, "chance": 0.7 }
};
elements.acidic_vapour.ignore = elements.acid.ignore
/*
elements.radioactive_rock_dust = {
color: "#839e78",
behavior: behaviors.RAD_GAS,
reactions: {
"water": {"elem1": "radioactive_water", "elem2": null }
},
category: "gases",
density: 2.45,
state: "gas",
tempHigh: 950,
stateHigh: [null,null,null,null,"radioactive_magma"],
}
elements.radioactive_rock.breakInto.push("radioactive_rock_dust")
*/
elements.rock_dust.tempHigh = 3000
elements.rock_dust.stateHigh = "vaporized_rock"
/*
elements.radioactive_rock_dust.tempHigh = 3000
elements.radioactive_rock_dust.stateHigh = "vaporized_rock"
*/
});
//IOCALFAEUS CLONES
elements.iorefrius_gas = {
color: ["#217349", "#1b5f3c"],
behavior: behaviors.GAS,
tick: function(pixel) {
if(!pixel.cold) {
pixel.cold = false
}
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i,true)) {
var newPixel = pixelMap[pixel.x+j][pixel.y+i];
if ((lightArray.includes(newPixel.element)) || (newPixel.temp >= 525) || (ledArray.includes(newPixel.element) && newPixel.charge) || (newPixel.cold && Math.random() < 0.04)) {
pixel.cold = true;
};
};
};
};
if(pixel.cold == true) {
pixel.temp -= 16;
};
if(pixel.cold == true && Math.random() < 0.02) {
pixel.cold = false;
};
},
category: "gases",
density: 0.97,
state: "gas",
};
elements.iolucius_gas = {
color: ["#e9c5ed", "#e2b0e8"],
behavior: behaviors.GAS,
tick: function(pixel) {
if(!pixel.lit) {
pixel.lit = false
}
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i,true)) {
var newPixel = pixelMap[pixel.x+j][pixel.y+i];
if ((lightArray.includes(newPixel.element)) || (newPixel.temp >= 525) || (ledArray.includes(newPixel.element) && newPixel.charge) || (newPixel.lit && Math.random() < 0.04)) {
pixel.lit = true;
};
};
};
};
if(Math.random() < 0.05) {
if(pixel.lit == true) {
var randomLightOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var lightX = pixel.x + randomLightOffset[0];
var lightY = pixel.y + randomLightOffset[1];
if(isEmpty(lightX,lightY,false)) {
createPixel("light",lightX,lightY);
};
};
};
if(pixel.lit == true && Math.random() < 0.02) {
pixel.lit = false;
};
},
category: "gases",
density: 0.97,
state: "gas",
};
elements.ioradius_gas = {
color: ["#a6a258", "#97944e"],
behavior: behaviors.GAS,
tick: function(pixel) {
if(!pixel.rlit) {
pixel.rlit = false
}
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i,true)) {
var newPixel = pixelMap[pixel.x+j][pixel.y+i];
if ((lightArray.includes(newPixel.element)) || newPixel.element === "radiation" || (newPixel.temp >= 525) || (ledArray.includes(newPixel.element) && newPixel.charge) || (newPixel.rlit && Math.random() < 0.04)) {
pixel.rlit = true;
};
};
};
};
if(Math.random() < 0.05) {
if(pixel.rlit == true) {
var randomRadiationOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var radiationX = pixel.x + randomRadiationOffset[0];
var radiationY = pixel.y + randomRadiationOffset[1];
if(isEmpty(radiationX,radiationY,false)) {
createPixel("radiation",radiationX,radiationY);
};
};
};
if(pixel.rlit == true && Math.random() < 0.02) {
pixel.rlit = false;
};
},
category: "gases",
density: 0.97,
state: "gas",
};
//SOME METALS AND OTHER ASSORTED SUBSTANCES ##
elements.iron.hardness = 0.74
//https://www.engineeringtoolbox.com/bhn-brinell-hardness-number-d_1365.html
//https://en.wikipedia.org/wiki/Hardnesses_of_the_elements_(data_page)
//"Annealed chissel steel" hardness and then divided by iron hardness (Brinell)
//sqrt()ed like IACS-derived conductivities and scaled to the 0.8 hardness of steel
//and because 1 means infinite hardness, the others are derived using
//1-(0.26/(otherThingBHN/200))
//it doesn't matter much anyway but I'd like to have some semblance/veneer of accuracy
//Then I nerfed and buffed some of them with inconsistent rounding.
elements.chromium = {
color: ["#c8cccb", "#dce3e0", "#ebedeb"],
behavior: behaviors.WALL,
reactions: {
},
tempHigh: 1907,
category: "solids",
density: 7190,
conduct: 0.35,
hardness: 0.985,
state: "solid",
};
//Makes thinner nichrome wires get hotter
nichromeDoNeighborCount = true;
function nichromeNeighborLogic(count) {
if(count < 3) { return 2.5 };
return count == 3 ? 1.25 : 0;
};
elements.nichrome = {
color: ["#d1cfcb", "#dbd7ce", "#e8e2d5"],
behavior: behaviors.WALL,
tempHigh: 1400,
category: "solids",
density: 8300,
conduct: 0.75,
hardness: 0.7, //???
state: "solid",
tick: function(pixel) {
if(nichromeDoNeighborCount) {
var neighbors = 0;
for(i = 0; i < adjacentCoords.length; i++) {
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
var newPixel = pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]];
if(elements[newPixel.element].conduct) { neighbors++ };
};
};
};
if(pixel.charge) {
pixel.temp += ((1.1 + nichromeNeighborLogic(neighbors)) * pixel.charge);
};
},
};
elements.molten_chromium = {
density: 6300,
temp: 2000,
reactions: { //(test.hello ??= {}).world
molten_nichrome: { elem1: "molten_nichrome", elem2: "molten_chromium", chance: 0.4, changeTemp: false, oneway: true }
},
};
elements.molten_nichrome = {
reactions: { //(test.hello ??= {}).world
molten_nickel: { elem1: "molten_nickel", elem2: "molten_nichrome", chance: 0.4, changeTemp: false, oneway: true },
molten_haseulite: { elem2: "molten_hanichrite", elem1: ["molten_nichrome","molten_nichrome","molten_nichrome","molten_nichrome","molten_nichrome","molten_nichrome","molten_nichrome","molten_nichrome","molten_nichrome","molten_hanichrite"], changeTemp: false }
},
tick: function(pixel) {
if(nichromeDoNeighborCount) {
var neighbors = 0;
for(i = 0; i < adjacentCoords.length; i++) {
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
var newPixel = pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]];
if(elements[newPixel.element].conduct) { neighbors++ };
};
};
};
if(pixel.charge) {
pixel.temp += ((1.1 + nichromeNeighborLogic(neighbors)) * pixel.charge) * 1.1;
};
},
};
elements.gold.reactions ??= {};
elements.molten_gold.reactions.molten_nickel = {
elem1: "molten_white_gold",
elem2: new Array(9).fill("molten_nickel").concat("molten_white_gold"),
changeTemp: false
};
elements.molten_copper.reactions.molten_gold = {
elem1: ["molten_copper","molten_copper","molten_rose_gold"],
elem2: "molten_rose_gold",
changeTemp: false
};
elements.white_gold = {
color: ["#c2c2c2","#9e9e9e","#e8e8e8"],
behavior: behaviors.WALL,
tempHigh: 937,
category: "solids",
density: 15900,
conduct: 0.83, //Has never been measured x>:(
hardness: 0.48,
};
elements.rose_gold.color = ["#f58eb1","#d06c7d","#f58eb1"];
elements.molten_copper.reactions.molten_rose_gold = {
elem1: ["molten_copper","molten_red_gold"],
elem2: "molten_red_gold",
changeTemp: false
};
elements.red_gold = {
color: ["#d97b6a","#c95c49","#d97b6a"],
behavior: behaviors.WALL,
tempHigh: 975, //https://www.researchgate.net/figure/Gold-copper-phase-diagram-with-melting-points-of-gold-and-copper-adapted-from-AMS_fig51_233765846
category: "solids",
density: 12220, //https://www.handymath.com/cgi-bin/density.cgi?naym1=Gold&weight1=10&den1=19.3&naym2=Copper&weight2=10&den2=8.94&aloynaym=Red+Gold&submit=Calculate&numnum=2&moreless=1&decimal=5
conduct: 0.85, //Has never been measured x>:(
hardness: 0.5, //???
};
worldgentypes.test = {
layers: [[0.3, "pointer"], [0, "molten_nickel"]],
temperature: 2000
};
runAfterAutogen(function() {
if(!elements.molten_nickel.reactions) {
elements.molten_nickel.reactions = {};
};
elements.molten_nickel.reactions.molten_chromium = { elem1: "molten_nichrome", elem2: ["molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_nichrome"], changeTemp: false };
});
//Copper exists
elements.ruthenium = {
color: ["#e8ebca","#eaebd5"], //color pulled from my ass because I don't want another gray metal
behavior: behaviors.WALL,
tempHigh: 2334,
category: "solids",
state: "solid",
density: 12450,
conduct: 0.45,
hardness: 0.97,
},
elements.molten_ruthenium = {
density: 10650,
tempHigh: 4150
},
elements.rhodium = {
color: ["#f0e4df","#f7eae4"], //it looked slightly reddish on Wikipedia
behavior: behaviors.WALL,
tempHigh: 1964,
category: "solids",
state: "solid",
density: 12410,
conduct: 0.59,
hardness: 0.95,
},
elements.molten_rhodium = {
density: 10700,
tempHigh: 3695
},
elements.palladium = {
color: ["#fff8ed","#f5e6ce","#faeccf"], //Terraria reference
behavior: behaviors.WALL,
tempHigh: 1555,
category: "solids",
state: "solid",
density: 12023,
conduct: 0.38,
hardness: 0.83,
},
elements.molten_palladium = {
density: 10380,
tempHigh: 2963
},
//Silver exists
elements.rhenium = {
color: ["#e5f0d1","#e6edda"], //it looks like almost every other metal but in some pictures the lighting makes it look ever-so-slightly greenish
behavior: behaviors.WALL,
tempHigh: 3186,
category: "solids",
state: "solid",
density: 21020,
conduct: 0.29,
hardness: 0.96,
},
elements.molten_rhenium = {
density: 18900,
tempHigh: 5630
},
elements.osmium = {
color: ["#d8e1eb","#cee1f0"], //it looks bluish
behavior: behaviors.WALL,
tempHigh: 3033,
category: "solids",
state: "solid",
density: 22590,
conduct: 0.40,
hardness: 0.98,
},
elements.molten_osmium = {
density: 2e4,
tempHigh: 5008
},
elements.iridium = {
color: ["#dfb9f0","#d6a9eb","#dfd1ed","#eeeeee"], //Minecraft and Stardew Valley reference
behavior: behaviors.WALL,
tempHigh: 2446,
category: "solids",
state: "solid",
density: 22560,
conduct: 0.54,
hardness: 0.97,
},
elements.molten_iridium = {
density: 19000,
tempHigh: 4130
},
elements.platinum = {
color: ["#dddddd","#d7d7d7"],
behavior: behaviors.WALL,
tempHigh: 1768,
category: "solids",
state: "solid",
density: 21450,
conduct: 0.38,
hardness: 0.83226,
},
elements.molten_platinum = {
density: 19770,
tempHigh: 3825
},
//Gold exists
elements.molten_gold ??= {};
elements.molten_gold.density = 17310;
elements.molten_gold.tempHigh = 2970;
elements.mercury = {
color: ["#d1d1d1", "#bababa"],
behavior: behaviors.LIQUID,
tempHigh: 357,
stateHigh: "mercury_gas",
tempLow: -39,
stateLow: "frozen_mercury",
state: "solid",
category: "liquids",
density: 13534,
conduct: 0.13,
breakInto: "mercury_gas",
},
elements.frozen_mercury = {
color: ["#d1d1d1", "#bababa"],
density: 14184,
behavior: behaviors.WALL,
conduct: 0.13,
tempHigh: -39,
temp: -50,
stateHigh: "mercury",
category: "solids",
state: "solid",
state: "solid",
hidden: true,
hardness: 0.2775, //(desperately scaled Mohs hardness)
},
elements.mercury_gas = { //hg d@bp extrapolated from density change with temperature: 12743
density: 8.477,
color: ["#d1d1d1", "#bababa"],
colorOn: ["#96ffbf", "#9cffc2", "#9effe7"],
conduct: 0.13,
behavior: behaviors.GAS,
tempLow: 357,
temp: 400,
stateLow: "mercury",
category: "gases",
state: "gas",
hidden: true,
}
var mooreNeighborhood = [[-1,-1],[0,-1],[1,1],[-1,0],[1,0],[-1,1],[0,1],[1,1]];
var bismuthCrystalColorArray = [
"#f58887",
"#fcd19a",
"#fcf588",
"#aef29d",
"#9af5e4",
"#b3bef5",
"#dbb9f0",
"#f2acdb"
]
var bismuthCrystalElements = ["amba_bismuth","amba_molten_bismuth"];
quadriCoords = [[-1,1],[0,1],[1,1],[1,0]];
//i'm not replacing pixelTick for this shit
/*function mooreDoHeat(pixel) {
// Check right and bottom adjacent pixels
for (var i = 0; i < quadriCoords.length; i++) {
var x = pixel.x+quadriCoords[i][0];
var y = pixel.y+quadriCoords[i][1];
if (!isEmpty(x,y,true)) {
var newPixel = pixelMap[x][y];
// Skip if both temperatures are the same
if (pixel.temp == newPixel.temp || elements[newPixel.element].insulate == true) {
continue;
}
// Set both pixel temperatures to their average
var avg = (pixel.temp + newPixel.temp)/2;
pixel.temp = avg;
newPixel.temp = avg;
pixelTempCheck(pixel);
pixelTempCheck(newPixel);
};
};
};*/
function bismuthCrystallization(pixel) {
if(pixel.temp < elements.amba_bismuth.tempHigh) { //initial crystal on cool
//pixel.color = "rgb(255,0,0)";
//initialize CCC
pixel.crystalColorCounter ??= Math.floor(Math.random() * 8); //initialize CCC
//pixel.crystalColorCounter ??= 0;
if(pixel.element !== "amba_bismuth") {
pixel.temp -= 0.05; //incentivize cooling
pixel.element = "amba_bismuth"
//console.log(`pixel (${pixel.x},${pixel.y}) frozen by bismuthCrystallization`)
pixel.color = pixelColorPick(pixel,bismuthCrystalColorArray[pixel.crystalColorCounter % 8]);
}; //solidify
};
if(pixel.crystalColorCounter !== undefined) {
for(i = 0; i < mooreNeighborhood.length; i++) {
var newX = pixel.x + mooreNeighborhood[i][0];
var newY = pixel.y + mooreNeighborhood[i][1];
if(isEmpty(newX,newY,true)) {
continue;
} else {
var newPixel = pixelMap[newX][newY];
if(bismuthCrystalElements.includes(newPixel.element)) {
if(newPixel.temp < elements.amba_bismuth.tempHigh) {
newPixel.temp -= 0.05;
newPixel.element = "amba_bismuth";
newPixel.crystalColorCounter = (pixel.crystalColorCounter + 1) % 8;
newPixel.color = pixelColorPick(pixel,bismuthCrystalColorArray[pixel.crystalColorCounter % 8]);
};
};
};
};
};
//mooreDoHeat(pixel);
};
elements.amba_molten_bismuth = {
color: "#d1c6b0", //not really hot enough to be red
behavior: behaviors.LIQUID,
tempLow: -Infinity, //suppress normal freezing mechanism
stateLow: "amba_molten_bismuth",
tick: function(pixel) {
bismuthCrystallization(pixel);
},
density: 10050,
state: "liquid",
category: "liquids",
temp: 300,
tempHigh: 1560,
fireColor: "#4275db",
};
runAfterAutogen(function() {
delete elements.amba_molten_bismuth.tempLow;
delete elements.amba_molten_bismuth.stateLow;
});
elements.amba_bismuth = {
color: "#d1c6b0",
behavior: behaviors.WALL,
/*reactions: {
},*/
tempHigh: 271.5,
category: "solids",
density: 9780,
conduct: 0.12,
hardness: 0.22,
state: "solid",
fireColor: "#4275db",
};
elements.amba_bismuth_gas = {
density: 9, //made-up number
fireColor: "#4275db",
};
zirconoids = ["zirconium","molten_zirconium","zirconium_gas"];
function zirconiumMoveContainedNeutron(pixelFrom,pixelTo) {
if(!pixelFrom || !pixelTo) {
return false
};
pixelFrom.neutrons ??= 0;
if(pixelFrom.neutrons < 1) {
return false;
};
pixelTo.neutrons ??= 0;
pixelFrom.neutrons--;
pixelTo.neutrons++;
};
function neutronAbsorbency(pixel,otherPixel) {
if(isNaN(pixel.neutrons)) {
pixel.neutrons = 0;
};
pixel.neutrons ??= 0; //probably redundant with the above
if(!otherPixel) {
return null;
};
if(otherPixel.element === "neutron") {
/*var otherIndex = currentPixels.indexOf(otherPixel);
if(otherIndex !== -1) { currentPixels.splice(otherIndex,1) };
pixelMap[otherPixel.x][otherPixel.y] = undefined;*/
deletePixel(otherPixel.x,otherPixel.y);
pixel.neutrons++;
return true;
} else {
return false;
};
};
function neutronMovement(pixel,whitelist=null) {
if(!pixel.oldColor) {
pixel.oldColor = pixel.color;
};
if(isNaN(pixel.neutrons)) {
pixel.neutrons = 0;
};
pixel.neutrons ??= 0; //probably redundant with the above
if(pixel.oldColor === null) { pixel.oldColor = pixel.color };
var color = convertColorFormats(pixel.oldColor,"json");
//color.g += (pixel.neutrons * 4);
//color.b += (pixel.neutrons * 6);
color.g += (pixel.neutrons * 32);
color.b += (pixel.neutrons * 48);
color = convertColorFormats(color,"rgb");
pixel.color = color;
for(i = 0; i < pixel.neutrons; i++) {
if(pixel.neutrons < 1) { break };
var vx = Math.floor(Math.random() * 3) - 1;
var vy = Math.floor(Math.random() * 3) - 1;
if (vx===0 && vy===0) {
if (Math.random() < 0.5) { vx = Math.random() < 0.5 ? 1 : -1; }
else { vy = Math.random() < 0.5 ? 1 : -1; }
};
var newPos = {x: pixel.x+vx, y: pixel.y+vy};
if(outOfBounds(newPos.x,newPos.y)) {
continue;
};
if(isEmpty(newPos.x,newPos.y,false)) {
createPixelReturn("neutron",newPos.x,newPos.y).temp = pixel.temp;
pixel.neutrons--;
if(pixel.neutrons < 1) { break };
} else if(!isEmpty(newPos.x,newPos.y,true)) {
var newPixel = pixelMap[newPos.x][newPos.y];
if(whitelist == null || whitelist.includes(newPixel.element)) {
zirconiumMoveContainedNeutron(pixel,newPixel);
if(pixel.neutrons < 1) { break };
};
};
};
};
elements.neutron = {
color: "#a6ffff",
behavior: [
"XX|XX|XX",
"XX|CH:proton%0.25 AND DL%0.25|XX", //"b nnnnnnnnn" - the dog stepping on the keyboard
"XX|XX|XX"
],
tick: behaviors.BOUNCY,
rotatable: true,
reactions: {
uranium: {
temp2: 100
},
plant: {
elem2: "wood",
chance: 0.05
},
gunpowder: {
elem2: "dust",
chance: 0.05
},
yeast: {
elem2: "bread",
chance: 0.05
},
silver: {
elem1: null,
chance: 0.25
},
firework: {
chance: 0.01,
func: function(pixel1,pixel2) {
pixel2.burning=true;
pixel2.burnStart=pixelTicks
}
},
hydrogen: {
elem1: null,
elem2: "deuterium",
chance: 0.02 //nerfs not in original NM
},
deuterium: {
elem1: null,
elem2: "tritium",
chance: 0.01
},
heavy_water: {
elem1: null,
elem2: "heavy_water"
},
heavy_steam: {
elem1: null,
elem2: "heavy_steam"
},
heavy_ice: {
elem1: null,
elem2: "heavy_ice"
},
heavy_snow: {
elem1: null,
elem2: "heavy_snow"
},
plutonium: {
temp2: 100
},
molten_plutonium: {
temp2: 100
}
},
temp: 35,
category: "energy",
state: "gas",
density: 0.00003,
ignoreAir: true,
nellfireImmune: true
};
elements.zirconium = {
color: ["#ccc59b", "#dbd3a4"],
behavior: behaviors.WALL,
properties: {
oldColor: null
},
burnInto: "zirconia",
onTryMoveInto: function(pixel,otherPixel) {
neutronAbsorbency(pixel,otherPixel);
},
tick: function(pixel) {
neutronMovement(pixel,zirconoids);
},
tempHigh: 1855,
category: "solids",
density: 6520,
conduct: 0.19,
hardness: 0.5,
forceAutoGen: true
},
eLists.NUCLEARFUEL = ['uranium', 'molten_uranium', 'enriched_uranium', 'molten_enriched_uranium', 'uranium_dioxide', 'enriched_uranium_dioxide', 'molten_uranium_dioxide', 'molten_enriched_uranium_dioxide', 'uranium233', 'uranium235', 'uranium_gas', 'plutonium', 'molten_plutonium', 'enriched_plutonium', 'molten_enriched_plutonium', 'plutonium_dioxide', 'molten_plutonium_dioxide', 'enriched_plutonium_dioxide', 'molten_enriched_plutonium_dioxide', 'uranium_gas', 'plutonium_gas'];
elements.molten_zirconium = {
tick: function(pixel) {
var neighbors = getVonNeumannNeighbors(pixel);
var lavaNeighbors = neighbors.filter(p => (eLists.MAGMA.includes(p.element)) || p.element.includes("molten_dirt"));
var fuelNeighbors = neighbors.filter(p => (eLists.NUCLEARFUEL.includes(p.element)));
if((lavaNeighbors.length > 0) && (fuelNeighbors.length > 0)) {
var aLavaNeighbor = randomChoice(lavaNeighbors);
var aFuelNeighbor = randomChoice(fuelNeighbors);
var coria = [pixel,aLavaNeighbor,aFuelNeighbor];
for(var i = 0; i < coria.length; i++) {
var newPixel = coria[i];
if(!newPixel) { continue };
changePixel(newPixel,"corium",false);
if(newPixel.temp < elements.corium.temp) { newPixel.temp = elements.corium.temp }; //changeTemp upwards only
}
}
}
}
newPowder("zirconia",["#F0ECDB","#FBF8EC"],5680,2715)
elements.solid_zirconia = newPowder("zirconia",["#F0ECDB","#FBF8EC"],5680,2715,null,"zirconia",0.85,true);
elements.molten_magnesium ??= {}; elements.molten_magnesium.tempHigh = 1090;
elements.molten_zirconia = {
tempHigh: 4300,
viscosity: 13,
density: 4700, //https://pmc.ncbi.nlm.nih.gov/articles/PMC6658727/#:~:text=The%20density%20of%20liquid%20ZrO2%20was%20found%20to%20be,mPa%20at%20its%20melting%20point. it's surprising that someone could be arsed to measure it, even more so with the whole extremely high temperature thing
stateLow: "solid_zirconia",
reactions: {
"calcium": { elem1: "cubic_zirconia_solution", elem2: ["calcium","calcium","calcium","calcium",null], tempMin: 2760 },
"molten_calcium": { elem1: "cubic_zirconia_solution", elem2: ["molten_calcium","molten_calcium","molten_calcium","molten_calcium",null], tempMin: 2760 },
"vaporized_calcium": { elem1: "cubic_zirconia_solution", elem2: ["vaporized_calcium","vaporized_calcium","vaporized_calcium","vaporized_calcium",null], tempMin: 2760 },
"magnesium": { elem1: "cubic_zirconia_solution", elem2: ["magnesium","magnesium","magnesium","magnesium",null], tempMin: 2760 },
"molten_magnesium": { elem1: "cubic_zirconia_solution", elem2: ["molten_magnesium","molten_magnesium","molten_magnesium","molten_magnesium",null], tempMin: 2760 },
"magnesium_gas": { elem1: "cubic_zirconia_solution", elem2: ["magnesium_gas","magnesium_gas","magnesium_gas","magnesium_gas",null], tempMin: 2760 }
}
};
runAfterAutogen(function() {
elements.cubic_zirconia_solution = JSON.parse(JSON.stringify(elements.molten_zirconia));
elements.cubic_zirconia_solution.stateLow = "cubic_zirconia"
});
elements.cubic_zirconia = {
color: ["#03FCEC","#03C6FC","#B3EEFF","#8AB0E6","#03FCEC","#03C6FC","#B3EEFF","#8AB0E6","#5EF5C5","#88BBEE","#D0AAEF","#E9BECE","#FECC98","#F8F894"],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 5800,
hardness: 0.8,
tempHigh: elements.zirconia.tempHigh,
stateHigh: "molten_zirconia"
};
elements.molten_zircon = {
density: 5803,
tempHigh: 2800,
stateHigh: ["molten_zirconia","silica_gas"],
behavior: behaviors.MOLTEN,
onTryMoveInto: function(pixel,otherPixel) {
neutronAbsorbency(pixel,otherPixel);
},
tick: function(pixel) {
neutronMovement(pixel,zirconoids);
},
};
elements.zirconium_gas = {
density: 3, //Unknown/Unmeasured value
behavior: behaviors.GAS,
onTryMoveInto: function(pixel,otherPixel) {
neutronAbsorbency(pixel,otherPixel);
},
tick: function(pixel) {
neutronMovement(pixel,zirconoids);
},
};
elements.neutron.state = "gas";
elements.neutron.ignoreAir = "true";
neighbors = [[-1,0],[0,-1],[1,0],[0,1]];
function coriumSteamExpHeat(pixel,x,y,radius,fire,smoke,power,damage) {
var distance = pyth(x,y,pixel.x,pixel.y);
var closeness = Math.abs(radius - distance);
var closenessProportion = closeness / radius;
pixel.temp += 25;
if(Math.random() < Math.sqrt(closenessProportion)) {
if(pixel.element.endsWith("water")) {
pixel.temp += 325;
pixelTempCheck(pixel)
}
};
//double velocity
if (!elements[pixel.element].excludeRandom && !elements[pixel.element].excludeVelocity) {
var angle = Math.atan2(pixel.y-y,pixel.x-x);
pixel.vx = Math.round((pixel.vx|0) + Math.cos(angle) * (radius * power/10));
pixel.vy = Math.round((pixel.vy|0) + Math.sin(angle) * (radius * power/10));
}
}
//and the reason I added zirconium in the first place
elements.corium = {
color: ["#F4D851","#A9B335","#E1710F"],
behavior: behaviors.MOLTEN,
tick: function(pixel) {
pixel.radiation ??= 150;
var range = Math.ceil(Math.log(((pixel.radiation ?? 50) ** (0.583)) + 1))
if(isNaN(pixel.radiation)) { pixel.temp += 10; pixel.radiation = 150 };
if(isNaN(pixel.temp)) { pixel.temp = 2400 };
pixel.temp += (pixel.radiation / 75);
if(pixel.radiation > 0) {
for(var dx = -range; dx <= range; dx++) {
for(var dy = -range; dy <= range; dy++) {
if(Math.random() < (pixel.radiation * 0.003)) {
var distance = Math.sqrt((Math.abs(dx)**2) + (Math.abs(dy)**2));
if(distance > range) { continue };
var x = pixel.x + dx;
var y = pixel.y + dy;
if(isEmpty(x,y,false)) {
createPixelReturn("radiation",x,y).temp = pixel.temp;
}
}
}
}
};
pixel.radiation *= 0.99975;
},
reactions: {
"magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"felsic_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"intermediate_felsic_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"intermediate_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"ultramafic_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"crimson_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"blackpinkinitic_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"rainbow_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"nellish_magma": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_slag": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_steel": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_zirconium": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_zirconia": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_carbon": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_dirt": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_tuff": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_glass": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"molten_silica": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"fallout": { func(pixel1,pixel2) {
changePixel(pixel2,"corium",false); pixel2.radiation = pixel1.radiation / 2; pixel1.radiation = pixel1.radiation / 2 }, chance: 0.02
},
"iodine": { elem2: null },
"caesium": { elem2: null },
"barium": { elem2: null },
"ash": { elem2: null },
"liquid_irradium": { elem2: ["liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium",null], temp1: 1.5, propAdds1: { radiation: 10 } },
"pure_water": { elem1: "intermediate_magma", elem2: "pure_water", changeTemp: true },
"chilly_water": { elem1: "intermediate_magma", elem2: "pure_water", temp1: -500, temp2: -100 }
},
hoverStat: function(pixel) { return "rad.lvl. " + (pixel.radiation ?? 150).toLocaleString(undefined,{maximumFractionDigits: 1}) },
temp: 2400,
tempLow: 1400, //made up
stateLow: "solidified_corium",
tempHigh: 4400, //made up
viscosity: 8, //bad guesstrapolation from https://www.kns.org/files/pre_paper/36/16A-362%EA%B9%80%EC%9B%85%EA%B8%B0.pdf
category: "liquids",
state: "liquid",
density: 7058 //assuming a 0.456 U-Zr ratio, and with uranium dioxide's density of 10970 subject to Sandboxels's standard molten density approximation of -10% because no data is available, and 4700 for liquid ZrO2, but this doesn't account for the variety of other s*** that gets in corium
};
/*for(var key in elements.corium.reactions) {
var r = elements.corium.reactions[key]
if(r.elem1 !== "corium") { continue };
elements[key] ??= {};
elements[key].reactions ??= {};
elements[key].reactions.corium ;
}*/
elements.solidified_corium = {
color: ["#5D4D36","#535F30","#414137"],
behavior: behaviors.POWDER,
tick: function(pixel) {
pixel.radiation ??= 10;
var range = Math.ceil(Math.log(((pixel.radiation ?? 10) ** (0.583)) + 1))
pixel.temp += 2;
if(isNaN(pixel.radiation)) { pixel.temp += 3; pixel.radiation = 150 };
for(var dx = -range; dx <= range; dx++) {
for(var dy = -range; dy <= range; dy++) {
if(Math.random() < 0.03 + (pixel.radiation * 0.0025)) {
var distance = Math.sqrt((Math.abs(dx)**2) + (Math.abs(dy)**2));
if(distance > range) { continue };
var x = pixel.x + dx;
var y = pixel.y + dy;
if(isEmpty(x,y,false)) {
createPixelReturn("radiation",x,y).temp = pixel.temp;
}
}
}
};
pixel.radiation *= 0.9998;
},
hoverStat: elements.corium.hoverStat,
reactions: {
"pure_water": { elem1: "andesite", elem2: "pure_water", changeTemp: true },
"chilly_water": { elem1: "solidified_corium", elem2: ["chilly_water","steam"], temp1: -500, temp2: -100 },
"liquid_irradium": { elem2: ["liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium",null], temp1: 1.5, propAdds1: { radiation: 10 } }
},
temp: 50,
tempHigh: 1400, //made up
stateHigh: "corium",
category: "solids",
state: "solid",
density: 11800 //assuming a 0.456 U-Zr ratio, and with uranium dioxide's density of 10970 subject to Sandboxels's standard molten density approximation of -10% because no data is available, and 4700 for liquid ZrO2, but this doesn't account for the variety of other s*** that gets in corium
};
if(eLists.WATER) {
for(var i = 0; i < eLists.WATER.length; i++) {
var water = eLists.WATER[i];
if(water == "chilly_water" || water == "pure_water") { continue };
elements.corium.reactions[water] = { func(pixel1,pixel2) {
explodeAt(pixel1.x,pixel1.y,5,"fire,rad_steam,rad_steam,rad_steam,steam,steam,radiation","steam,radiation",null,coriumSteamExpHeat)
}, temp1: 50, chance: 0.01 }
}
};
elements.corium_gas = {
tick: elements.corium.tick,
hoverStat: elements.corium.hoverStat,
reactions: {
"liquid_irradium": { elem2: ["liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium","liquid_irradium",null], temp1: 1.5, propAdds1: { radiation: 10 } },
"pure_water": { elem1: "intermediate_magma", elem2: "pure_water", changeTemp: true },
"chilly_water": { elem1: "solidified_corium", elem2: "steam", temp1: -500, temp2: -100 }
},
density: 20
};
elements.pure_water.reactions.dirty_water = elements.pure_water.reactions.water
radiationIncreaseOverrides = {
molten_uranium238: 1,
molten_actinium: 5,
molten_protactinium: 3,
molten_americium: 3,
molten_berkelium: 3,
molten_californium: 3,
molten_einsteinium: 5,
molten_fermium: 5,
molten_nihonium: 5,
molten_moscovium: 10,
molten_livermorium: 10,
molten_tennessine: 10,
molten_oganesson: 10,
molten_nihonium_oxide: 10,
molten_flerovium_oxide: 10,
molten_livermorium_oxide: 10,
"molten_p9-leeseocid": 10,
}
var radioactives = eLists.NUCLEARFUEL; radioactives.push("molten_uranium","molten_uranium238","molten_neptunium","molten_uranium238","molten_actinium","molten_protactinium","molten_americium","molten_berkelium","molten_californium","molten_einsteinium","molten_fermium","molten_nihonium","molten_moscovium","molten_livermorium","molten_tennessine","molten_oganesson","molten_nihonium_oxide","molten_flerovium_oxide","molten_livermorium_oxide","molten_p9-leeseocid")
for(var i = 0; i < radioactives.length; i++) {
var radioactive = radioactives[i];
elements.corium.reactions[radioactive] ??= { elem2: null, temp1: 1, chance: 0.1, propAdds1: { radiation: radiationIncreaseOverrides[radioactive] ?? 2 } }
}
//Non-element: Liquid ammonia
elements.liquid_ammonia = {
color: "#bab6a9",
behavior: behaviors.LIQUID,
reactions: {
"methane": { "elem1":null, "elem2":"cyanide", "chance":0.25 },
"plant": { "elem1":"plant", "chance":0.05 },
"wheat_seed": { "elem1":"wheat", "chance":0.05 },
"grass": { "elem1":"grass", "chance":0.05 },
"grass_seed": { "elem1":"grass", "chance":0.05 },
"bamboo_plant": { "elem1":"bamboo", "chance":0.05 },
"flower_seed": { "elem1":"flower_seed", "chance":0.05 },
"petal": { "elem1":"flower_seed", "chance":0.05 },
"vine": { "elem1":"vine", "chance":0.05 },
"sapling": { "elem1":"tree_branch", "chance":0.05 },
"tree_branch": { "elem1":"tree_branch", "chance":0.05 },
"corn_seed": { "elem1":"corn", "chance":0.05 },
"root": { "elem1":"root", "chance":0.05 },
"dirt": { "elem1":"grass", "chance":0.05 },
"mud": { "elem1":"grass", "chance":0.05 },
"potato_seed": { "elem1":"potato", "chance":0.05 },
"yeast": { "elem1":"yeast", "chance":0.05 },
"fish": { "elem2":"meat" },
"frog": { "elem2":"meat" }
},
tempHigh: -78,
stateHigh: "ammonia",
category: "liquids",
state: "liquid",
hidden: true,
density: 681.9,
}
elements.ammonia.tempLow = -78
elements.ammonia.stateLow = "liquid_ammonia"
//Hydrogen
//Hydrogen exists, but its solid form doesn't.
elements.liquid_hydrogen.tempLow = -259.16
elements.liquid_hydrogen.stateLow = "hydrogen_ice"
elements.hydrogen_ice = {
color: "#E6E6FF",
behavior: behaviors.WALL,
density: 76,
category: "solids",
state: "solid",
hidden: true,
tempHigh: -259,
stateHigh: "liquid_hydrogen",
}
//Lithium (incomplete/hiatus)
elements.lithium = {
color: "#b0ab9d",
behavior: behaviors.WALL,
tick: function(pixel) {
tryTarnish(pixel,"lithium_oxide",0.007)
if(pixel.temp >= 179) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
},
reactions: {
"steam": { "elem1": "hydrogen", "elem2": "lithium_hydroxide" },
"water": { "elem1": "hydrogen", "elem2": "lithium_hydroxide" },
"nitrogen": { "elem1": "lithium_nitride", "elem2": "lithium_nitride" },
"liquid_nitrogen": { "elem1": "lithium_nitride", "elem2": "lithium_nitride" },
"liquid_hydrogen": { "elem1": "lithium_hydride", "elem2": "lithium_hydride" },
"ammonia": { "elem1": ["hydrogen",null], "elem2": "lithium_amide" },
"liquid_ammonia": { "elem1": ["hydrogen",null], "elem2": "lithium_amide" },
},
density: 534,
category: "solids",
state: "solid",
conduct: 0.42697,
hardness: 0.019,
tempHigh: 180,
burn: 20,
burnTime: 130,
burnInto: "lithium_oxide",
fireColor: "#fc0a22",
}
elements.molten_lithium = { //too damn reactive
color: "#b0ab9d",
behavior: [
"XX|HT:1%1|XX",
"M2 AND HT:0.1%1|HT:1%1|M2 AND HT:1%1",
"M1|M1 AND HT:1%1|M1"
],
tick: function(pixel) {
tryTarnish(pixel,"lithium_oxide",0.014)
},
reactions: {
"steam": { "elem1": "hydrogen", "elem2": "lithium_hydroxide" },
"water": { "elem1": "hydrogen", "elem2": "lithium_hydroxide" },
"nitrogen": { "elem1": "lithium_nitride", "elem2": "lithium_nitride" },
"liquid_nitrogen": { "elem1": "lithium_nitride", "elem2": "lithium_nitride" },
"hydrogen": { "elem1": "lithium_hydride", "elem2": "lithium_hydride" },
"liquid_hydrogen": { "elem1": "lithium_hydride", "elem2": "lithium_hydride" },
"ammonia": { "elem1": ["hydrogen",null], "elem2": "lithium_amide" },
"liquid_ammonia": { "elem1": ["hydrogen",null], "elem2": "lithium_amide" },
},
burning: true,
burnInto: "lithium_oxide",
fireColor: "#fc0a22",
density: 512,
}
elements.lithium_oxide = {
color: "#eee9ec", //HRT UV-to-visible strategy again
behavior: behaviors.POWDER,
reactions: {
"steam": { "elem1": "lithium_hydroxide", "elem2": "lithium_hydroxide", chance: 0.03 },
"water": { "elem1": "lithium_hydroxide", "elem2": "lithium_hydroxide", chance: 0.03 },
"carbon_dioxide": { "elem1": null, "elem2": "lithium_carbonate" }
},
density: 2013,
category: "powders",
state: "solid",
hidden: true,
tempHigh: 1438,
}
elements.lithium_hydroxide = {
color: "#eeeeee",
behavior: behaviors.POWDER,
reactions: {
"steam": { "elem1": null, "elem2": "lithium_hydroxide_monohydrate" },
"water": { "elem1": null, "elem2": "lithium_hydroxide_monohydrate" },
"carbon_dioxide": { "elem1": "water", "elem2": [null,"lithium_carbonate"], chance: 0.5 },
},
density: 1460,
category: "powders",
state: "solid",
hidden: true,
tempHigh: 462,
}
elements.lithium_hydroxide_monohydrate = {
color: "#e0e4e7",
behavior: behaviors.POWDER,
reactions: {
"carbon_dioxide": { "elem1": "water", "elem2": [null,"lithium_carbonate"], chance: 0.5 },
},
tick: function(pixel) {
emptyNeighborArray = []
for(i=0;i<4;i++) {
if(isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],false)) {
emptyNeighborArray.push(adjacentCoords[i])
}
}
if(pixel.temp >= 100) {
if(emptyNeighborArray.length > 0) {
var placement = randomChoice(emptyNeighborArray)
if(isEmpty(pixel.x+placement[0],pixel.y+placement[1])) {
createPixel("steam",pixel.x+placement[0],pixel.y+placement[1])
changePixel(pixel,"lithium_hydroxide")
}
}
}
},
density: 1510,
category: "powders",
state: "solid",
hidden: true,
}
elements.lithium_carbonate = { //todo
color: "#eeeeee",
behavior: behaviors.POWDER,
density: 2110,
category: "powders",
state: "solid",
hidden: true,
tempHigh: 723,
}
elements.lithium_nitride = {
color: "#eeeeee",
behavior: behaviors.POWDER,
reactions: {
"steam": { "elem1": "lithium_hydroxide", "elem2": "ammonia" },
"water": { "elem1": "lithium_hydroxide", "elem2": "ammonia" },
"hydrogen": { "elem1": "lithium_hydride", "elem2": "lithium_amide" },
"liquid_hydrogen": { "elem1": "lithium_hydride", "elem2": "lithium_amide" },
},
density: 1270,
category: "powders",
state: "solid",
hidden: true,
tempHigh: 813,
}
elements.lithium_hydride = {
color: "#eeeeee",
behavior: behaviors.POWDER,
reactions: { //the acid part of lye
"ammonia": { "elem1": "hydrogen", "elem2": "lithium_amide" },
"liquid_ammonia": { "elem1": "hydrogen", "elem2": "lithium_amide" }
},
density: 780,
category: "powders",
state: "solid",
hidden: true,
tempHigh: 689,
}
elements.lithium_amide = {
color: "#eeeeee",
behavior: behaviors.POWDER,
reactions: {
"steam": { "elem1": "lithium_hydroxide", "elem2": "ammonia" },
"water": { "elem1": "lithium_hydroxide", "elem2": "ammonia" }
},
density: 1178,
category: "powders",
state: "solid",
hidden: true,
tempHigh: 375,
}
//Sodium exists
//...
//at request of Serioustar#1337
elements.niobium = {
color: ["#dedede","#edead8","#e8e9ed"],
behavior: behaviors.WALL,
tempHigh: 2477,
category: "solids",
density: 8570,
conduct: 0.35,
hardness: 0.7, //idk lol
};
//Random bullshit go
elements.kurshunjukium = {
color: ["#435564","#536371"],
behavior: behaviors.WALL,
tempHigh: 308,
category: "solids",
state: "solid",
density: 10304,
conduct: 0.53,
hardness: 0.12,
desc: 'Fictional Kurshunjukium, whose name comes from the Turkish "kurşuncuk", meaning "little lead", is a blue-gray metal that is soft and dense, similarly to its namesake.'
};
elements.molten_kurshunjukium = {
density: 7989,
tempHigh: 1411,
desc: "Fictional"
};
elements.kurshunjukium_gas = {
density: 18
};
elements.kurshuth_alloy = {
color: "#7d806f",
behavior: behaviors.LIQUID,
tempHigh: 863,
stateHigh: "kurshuth_alloy_vapor",
tempLow: 14,
stateLow: "solid_kurshuth_alloy",
category: "liquids",
state: "liquid",
density: 5606,
conduct: 0.13,
hardness: 0.02,
desc: 'Fictional Kurshuth alloy is a highly eutectic alloy composed of bismuth and kurshunjukium. It has an extremely low melting point, and isn\'t very useful.'
};
elements.kurshuth_alloy_vapor = {
density: 23,
behavior: behaviors.GAS,
category: "states",
state: "gas",
tempLow: 863,
stateLow: "kurshuth_alloy",
hidden: true,
color: elements.magma.color.map(x => changeSaturation(changeHue(multiplyColors(x,"#DD4444","json"),10,"add","hsl_json"),0.7,"multiply","hex")), //metals.js already uses code_library
desc: "Fictional"
};
elements.solid_kurshuth_alloy = {
color: "#5d604f",
behavior: behaviors.WALL,
tempHigh: 14,
stateHigh: "kurshuth_alloy",
category: "solids",
state: "solid",
density: 6006,
desc: "Fictional"
};
runAfterAutogen(function() {
var kesddfroged = ["kurshunjukium","molten_kurshunjukium"];
var kesddfroged2 = ["amba_bismuth","amba_molten_bismuth"];
for(var i in kesddfroged) {
for(var j in kesddfroged2) {
elements[kesddfroged[i]].reactions ??= {}; elements[kesddfroged[i]].reactions[kesddfroged2[j]] = {"elem1": "kurshuth_alloy", "elem2": "kurshuth_alloy"}
}
};
for(var i in kesddfroged2) {
for(var j in kesddfroged) {
elements[kesddfroged2[i]].reactions ??= {}; elements[kesddfroged2[i]].reactions[kesddfroged[j]] = {"elem1": "kurshuth_alloy", "elem2": "kurshuth_alloy"}
}
};
});
function newMetal(name,color,meltingPoint,boilingPoint,hardness,density,gasDensity,conduct,categoryOverride = null) {
var temp = {
"name": name,
"color": color,
"meltingPoint": meltingPoint,
"boilingPoint": boilingPoint,
"hardness": hardness,
"density": density,
"gasDensity": gasDensity,
"conduct": conduct
};
var tempNulls = Object.keys(temp).filter(key => (typeof(temp[key]) == undefined || temp[key] == null));
if(tempNulls.length > 0) {
var errorMessage = capitalizeFirstLetter(englishFormatList(tempNulls));
throw new Error(`newMetal: ${errorMessage} {tempNulls.length == 1 ? "is" : "are"} required (generating "${name}")`);
};
var scrapColor = gravelizeToHex(color);
elements[name] = {
"color": (window["gameLoaded"] ?? false) ? (Array.isArray(color) ? color.map(x => convertColorFormats(x,"rgb")) : convertColorFormats(color,"rgb")) : color,
"colorObject": (window["gameLoaded"] ?? false) ? (Array.isArray(color) ? color.map(x => convertColorFormats(x,"json")) : convertColorFormats(color,"json")) : undefined,
"behavior": behaviors.WALL,
"category": "solids",
"state": "solid",
"density": density,
"conduct": conduct,
"tempHigh": meltingPoint,
"breakInto": `${name}_scrap`,
"hardness": hardness
};
if(categoryOverride) { elements[name].category = categoryOverride };
elements[`molten_${name}`] = {
"tempHigh": boilingPoint
};
elements[`${name}_gas`] = {
"density": gasDensity
};
elements[`${name}_scrap`] = {
"color": (window["gameLoaded"] ?? false) ? (Array.isArray(scrapColor) ? scrapColor.map(x => convertColorFormats(x,"rgb")) : convertColorFormats(scrapColor,"rgb")) : scrapColor,
"colorObject": (window["gameLoaded"] ?? false) ? (Array.isArray(scrapColor) ? scrapColor.map(x => convertColorFormats(x,"json")) : convertColorFormats(scrapColor,"json")) : undefined,
"behavior": (window["gameLoaded"] ?? false) ? undefined : behaviors.POWDER,
"tick": (window["gameLoaded"] ?? false) ? behaviors.POWDER : undefined,
"tempHigh": meltingPoint,
"stateHigh": `molten_${name}`,
"category": "powders",
"state": "solid",
"hidden": true,
"density": density * 0.09,
"conduct": conduct * 0.4,
"movable": true,
};
if(window["gameLoaded"] ?? false) {
delete elements[`${name}_scrap`].behavior;
createElementButton(name);
if(settings.unhide == 1) { createElementButton(`${name}_scrap`) }
autoGen(`molten_${name}`,name,"molten");
elements[`molten_${name}`].color = elements[`molten_${name}`].color.map(x => convertColorFormats(x,"rgb"));
elements[`molten_${name}`].colorObject = elements[`molten_${name}`].color.map(x => convertColorFormats(x,"json"));
} else {
delete elements[`${name}_scrap`].tick;
};
return [elements[name],elements[`${name}_scrap`]];
};
//newMetal( "exidmaden", ["#F8EDCF", "#EEAAAE", "#E5678D", "#A6659C", "#6763AD"], 2134, 6769, 0.8, 32333, 49.9, 0.88 );
//newMetal( "jisooium", "#9d0ac2", 8367, 10003, 0.63, 15024, 12.2, 0.9 );
//newMetal( "twicium", ["#F9C596", "#FC5D9D"], 10240, 18018, 0.88, 29029, 24.3, 0.91 );
//ASSORTED LOONA-THEMED MATERIALS ##
haseuliteSpreadWhitelist = ["haseulite","haseulite_powder","molten_haseulite","haseulite_gas"];
jinsouliteSpreadWhitelist = ["jinsoulite","jinsoulite_powder","molten_jinsoulite","jinsoulite_gas"];
function coldExplosionAfterCooling(pixel,x,y,radius,fire,smoke,power,damage) {
pixel.temp -= 2*damage*radius*power;
};
function jinsouliteRxnStealerImmutableEl2DoNotUse(pixel,newPixel,reactionTarget,ignoreSelf=true,_chanceMultMeantForJinsoulites=1) {
if(!elements[reactionTarget]) {
throw new Error(`No such element ${reactionTarget}!`);
};
if(typeof(newPixel) === "undefined") { //timing issue?
return false;
};
var newElement = newPixel.element;
if(ignoreSelf && newElement === pixel.element) {
return false;
};
var newInfo = elements[newElement];
if(typeof(newInfo.reactions) === "undefined") {
return false;
};
if(typeof(newInfo.reactions[reactionTarget]) === "undefined") {
return false;
};
var pixel2 = pixel;
var pixel1 = newPixel;
var r = JSON.parse(JSON.stringify(newInfo.reactions[reactionTarget]));
if (r.setting && settings[r.setting]===0) {
return false;
}
// r has the attribute "y" which is a range between two y values
// r.y example: [10,30]
// return false if y is defined and pixel1's y is not in the range
if (r.tempMin !== undefined && pixel1.temp < r.tempMin) {
return false;
}
if (r.tempMax !== undefined && pixel1.temp > r.tempMax) {
return false;
}
if (r.charged && !pixel.charge) {
return false;
}
if (r.chance !== undefined && Math.random() < (r.chance * _chanceMultMeantForJinsoulites)) {
return false;
}
if (r.y !== undefined && (pixel1.y < r.y[0] || pixel1.y > r.y[1])) {
return false;
}
if(r.elem1 !== undefined && r.elem2 !== undefined) {
if(r.elem1 !== null && r.elem2 !== null) {
r.elem1 = [r.elem1,r.elem2].flat();
};
};
if (r.elem1 !== undefined) {
// if r.elem1 is an array, set elem1 to a random element from the array, otherwise set it to r.elem1
if (Array.isArray(r.elem1)) {
var elem1 = r.elem1[Math.floor(Math.random() * r.elem1.length)];
} else { var elem1 = r.elem1; }
if (elem1 == null) {
deletePixel(pixel1.x,pixel1.y);
}
else {
changePixel(pixel1,elem1);
}
}
if(pixel1) {
if (r.charge1) { pixel1.charge = r.charge1; }
if (r.temp1) { pixel1.temp += r.temp1; pixelTempCheck(pixel1); }
if (r.color1) { // if it's a list, use a random color from the list, else use the color1 attribute
pixel1.color = pixelColorPick(pixel1, Array.isArray(r.color1) ? r.color1[Math.floor(Math.random() * r.color1.length)] : r.color1);
}
if (r.attr1) { // add each attribute to pixel1
for (var key in r.attr1) {
pixel1[key] = r.attr1[key];
}
}
if (r.charge2) { pixel2.charge = r.charge2; }
if (r.temp2) { pixel2.temp += r.temp2; pixelTempCheck(pixel2); }
if (r.color2) { // if it's a list, use a random color from the list, else use the color2 attribute
pixel2.color = pixelColorPick(pixel2, Array.isArray(r.color2) ? r.color2[Math.floor(Math.random() * r.color2.length)] : r.color2);
}
if (r.attr2) { // add each attribute to pixel2
for (var key in r.attr2) {
pixel2[key] = r.attr2[key];
}
}
if (r.func) { r.func(pixel1,pixel2); }
}
return r.elem1!==undefined;
};
elements.loona = {
color: ["#6f7d54","#4f5d34","#7c8a61"],
behavior: behaviors.POWDER,
tempHigh: 1031,
category: "random rocks",
state: "solid",
density: 2466.73,
hardness: 0.56,
breakInto: ["rock","sulfur","loona_gravel","loona_gravel","loona_gravel","haseulite_powder", "rock","sulfur","loona_gravel","loona_gravel","loona_gravel","jinsoulite_powder", "rock","sulfur","loona_gravel","loona_gravel","loona_gravel","heejinite_powder"],
};
var backupCategoryWhitelist = ["land","powders","weapons","food","life","corruption","states","fey","Fantastic Creatures","dyes","energy liquids","random liquids","random gases","random rocks"];
var backupElementWhitelist = ["mercury", "chalcopyrite_ore", "chalcopyrite_dust", "copper_concentrate", "fluxed_copper_concentrate", "unignited_pyrestone", "ignited_pyrestone", "everfire_dust", "extinguished_everfire_dust", "mistake", "polusium_oxide", "vaporized_polusium_oxide", "glowstone_dust", "redstone_dust", "soul_mud", "wet_soul_sand", "nitrogen_snow", "fusion_catalyst", "coal", "coal_coke", "blast_furnace_fuel", "molten_mythril"];
function spoutCriteria(name) {
if(typeof(elements[name]) !== "object") {
throw new Error(`Nonexistent element ${name}`);
};
var info = elements[name];
//console.log(`${name} (${JSON.stringify(elements[name])})`);
if(typeof(info.state) === "undefined") {
var state = null;
} else {
var state = info.state;
};
if(typeof(info.category) === "undefined") {
var category = "other";
} else {
var category = info.category;
};
if(excludedSpoutElements.includes(name)) {
return false
};
var include = false;
if(["liquid","gas"].includes(state)) {
include = true;
};
if(info.movable) {
include = true;
};
if(backupCategoryWhitelist.includes(category)) {
include = true;
};
if(backupElementWhitelist.includes(name)) {
include = true;
};
if(category.includes("mudstone")) {
include = true;
};
//console.log(include);
return include;
};
function heejiniteHeatCriteria(name) {
if(typeof(elements[name]) !== "object") {
throw new Error(`Nonexistent element ${name}`);
};
var info = elements[name];
//console.log(`${name} (${JSON.stringify(elements[name])})`);
if(typeof(info.tempLow) === "undefined") {
return false;
};
if(typeof(info.tempHigh) !== "undefined" && info.tempHigh < elements.heejinite.tempHigh) {
return false;
};
return (info.tempLow < elements.heejinite.tempHigh) || ((typeof(info.state) !== "undefined") && (info.state === "gas"));
};
spoutCriteria = function(name) {
if(typeof(elements[name]) !== "object") {
throw new Error(`Nonexistent element ${name}`);
};
var info = elements[name];
//console.log(`${name} (${JSON.stringify(elements[name])})`);
if(typeof(info.state) === "undefined") {
var state = null;
} else {
var state = info.state;
};
if(typeof(info.category) === "undefined") {
var category = "other";
} else {
var category = info.category;
};
var include = false;
if(["liquid","gas"].includes(state)) {
include = true;
};
if(info.movable) {
include = true;
};
if(backupCategoryWhitelist.includes(category)) {
include = true;
};
if(backupElementWhitelist.includes(name)) {
include = true;
};
if(category.includes("mudstone")) {
include = true;
};
//console.log(include);
return include;
};
//it doesn't want to acknowledge spoutCriteria, so...
runAfterAutogen(function() {
elements.loona.stateHigh = ["molten_loona","rock","rock","rock","sulfur_gas","sulfur_gas","molten_haseulite","molten_loona","rock","rock","rock","sulfur_gas","sulfur_gas","molten_jinsoulite","molten_loona","rock","rock","rock","sulfur_gas","sulfur_gas","molten_heejinite"];
hotHeejiniteElements = Object.keys(elements).filter(function(e) {
return spoutCriteria(e) && heejiniteHeatCriteria(e) && !elements[e].excludeRandom && !e.startsWith("rad");
});
});
elements.loona_gravel = {
color: ["#b3be98","#919a6f","#68744b","#515931"],
behavior: behaviors.POWDER,
tempHigh: 1031,
stateHigh: ["molten_loona","rock","rock","rock","sulfur_gas","sulfur_gas","molten_haseulite","molten_loona","rock","rock","rock","sulfur_gas","sulfur_gas","molten_jinsoulite","molten_loona","rock","rock","rock","sulfur_gas","sulfur_gas","molten_heejinite"],
category: "random rocks",
state: "solid",
density: 1625.14,
hardness: 0.97,
breakInto: ["rock","sulfur","rock","haseulite_powder","rock","sulfur","rock","jinsoulite_powder","rock","sulfur","rock","heejinite_powder"],
};
jinsouliteValueObject = {
cloud: 0.5,
cloud_cloud: {value: 0.5, remainder: "cloud"},
snow_cloud: {value: 0.75},
hail_cloud: {value: 0.75},
steam: 1,
steam_cloud: {value: 0.5, remainder: "steam"},
rain_cloud_cloud: {value: 0.5, remainder: "rain_cloud"},
snow_cloud_cloud: {value: 0.5, remainder: "snow_cloud"},
hail_cloud_cloud: {value: 0.5, remainder: "hail_cloud"},
rain_cloud: {value: 1, remainder: "cloud"},
water_cloud: {value: 1, remainder: "cloud"},
snow: {value: 0.125},
soda: {value: 0.8984375, remainder: "sugar"},
blood: {value: 0.90625, remainder: "dna"},
infection: {value: 0.90625, remainder: "dna"},
packed_snow: {value: 0.90625},
slime: {value: 0.9609375, remainder: "salt"}, //:eggTF:
slush: {value: 0.9609375},
ice: {value: 0.98046875},
salt_water: {value: 1, remainder: "salt"}, //should be 0.965 but simplified here
dirty_water: {value: 1, remainder: ["ash","dust","carbon_dioxide","ash","dust","carbon_dioxide","infection"]},
sugar_water: {value: 1, remainder: "sugar"},
seltzer: {value: 1, remainder: "carbon_dioxide"},
pool_water: {value: 1, remainder: "chlorine"},
water: {value: 1, tempMin: 80},
water_bomb: 59,
water_bomb_2: 164.5,
water_bomb_3: 322.5,
water_bomb_4: 534,
water_bomb_5: 798,
water_bomb_6: 1112.5,
water_bomb_7: 1480,
water_bomb_8: 1901.5,
water_bomb_9: 2373,
water_bomb_10: 2898, //average rates from in-game simulation since I can't come up with an exponential function
water_bomb_bomb: 59*59,
water_bomb_bomb_2: 59*164.5,
water_bomb_bomb_3: 59*322.5,
water_bomb_bomb_4: 59*534,
water_bomb_bomb_5: 59*798,
water_bomb_bomb_6: 59*1112.5,
water_bomb_bomb_7: 59*1480,
water_bomb_bomb_8: 59*1901.5,
water_bomb_bomb_9: 59*2373,
water_bomb_bomb_10: 59*2898, //creates up to around 2,898 water bombs, each of which theoretically create up to around 59 water
water_bomb_bomb: 59*59,
water_bomb_2_bomb: 164.5*59,
water_bomb_3_bomb: 322.5*59,
water_bomb_4_bomb: 534*59,
water_bomb_5_bomb: 798*59,
water_bomb_6_bomb: 1112.5*59,
water_bomb_7_bomb: 1480*59,
water_bomb_8_bomb: 1901.5*59,
water_bomb_9_bomb: 2373*59,
water_bomb_10_bomb: 2898*59, //creates up to around 59 water bombs, each of which theoretically create up to around 2,898 water
water_bomb_10_bomb_10: 2898*2898, //skipping to the funny
water_bomb_cloud: 30,
};
/*function customStaining(pixel,customColorRgb,stainOverride=null) {
if (settings["stainoff"]) { return }
var stain = (stainOverride !== null ? stainOverride : elements[pixel.element].stain);
if (stain > 0) {
var newColor = customColorRgb.match(/\d+/g);
}
else {
var newColor = null;
}
for (var i = 0; i < adjacentCoords.length; i++) {
var x = pixel.x+adjacentCoords[i][0];
var y = pixel.y+adjacentCoords[i][1];
if (!isEmpty(x,y,true)) {
var newPixel = pixelMap[x][y];
if (elements[pixel.element].ignore && elements[pixel.element].ignore.indexOf(newPixel.element) !== -1) {
continue;
}
if ((elements[newPixel.element].id !== elements[pixel.element].id || elements[newPixel.element].stainSelf) && (solidStates[elements[newPixel.element].state] || elements[newPixel.element].id === elements[pixel.element].id)) {
if (Math.random() < Math.abs(stain)) {
if (stain < 0) {
if (newPixel.origColor) {
newColor = newPixel.origColor;
}
else { continue; }
}
else if (!newPixel.origColor) {
newPixel.origColor = newPixel.color.match(/\d+/g);
}
// if newPixel.color doesn't start with rgb, continue
if (!newPixel.color.match(/^rgb/)) { continue; }
// parse rgb color string of newPixel rgb(r,g,b)
var rgb = newPixel.color.match(/\d+/g);
if (elements[pixel.element].stainSelf && elements[newPixel.element].id === elements[pixel.element].id) {
// if rgb and newColor are the same, continue
if (rgb[0] === newColor[0] && rgb[1] === newColor[1] && rgb[2] === newColor[2]) { continue; }
var avg = [];
for (var j = 0; j < rgb.length; j++) {
avg[j] = Math.round((rgb[j]*(1-Math.abs(stain))) + (newColor[j]*Math.abs(stain)));
}
}
else {
// get the average of rgb and newColor, more intense as stain reaches 1
var avg = [];
for (var j = 0; j < rgb.length; j++) {
avg[j] = Math.floor((rgb[j]*(1-Math.abs(stain))) + (newColor[j]*Math.abs(stain)));
}
}
// set newPixel color to avg
newPixel.color = "rgb("+avg.join(",")+")";
}
}
}
}
}*/
function valueSpreading(pixel,whitelist=null) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rX = randomNeighborOffset[0];
var rY = randomNeighborOffset[1];
var rfX = pixel.x+rX;
var rfY = pixel.y+rY;
if(!isEmpty(rfX,rfY,true)) {
var rOtherPixel = pixelMap[rfX][rfY];
var rOtherElement = rOtherPixel.element;
if(whitelist === null || (whitelist !== null && whitelist.includes(rOtherElement))) {
if(typeof(rOtherPixel.value) !== "number") {
rOtherPixel.value = 0;
};
if(typeof(rOtherPixel) === "undefined" || isEmpty(rfX,rfY,true)) {
return false;
};
var averageValue = (pixel.value + rOtherPixel.value) / 2;
pixel.value = averageValue;
rOtherPixel.value = averageValue;
};
};
return true;
};
function valueAbsorbency(pixel,valueObject) {
for(i = 0; i < adjacentCoords.length; i++) {
var oX = adjacentCoords[i][0];
var oY = adjacentCoords[i][1];
var fX = pixel.x+oX;
var fY = pixel.y+oY;
if(!isEmpty(fX,fY,true)) {
var otherPixel = pixelMap[fX][fY];
var otherElement = otherPixel.element;
var otherInfo = elements[otherElement];
if(valueObject[otherElement]) {
//console.log(`${otherElement} in your area`)
if(typeof(otherPixel) === "undefined" || isEmpty(fX,fY,true)) {
console.log(`nope`)
return false;
};
var ValueData = valueObject[otherElement];
//console.log(ValueData.toString())
if(typeof(ValueData) == "object") {
var tempMin = ValueData.tempMin ?? null;
if(pixel.temp < tempMin) {
continue;
};
var finalElement = ValueData.remainder ?? null;
if(finalElement instanceof Array) {
finalElement = finalElement[Math.floor(Math.random() * finalElement.length)];
};
if(finalElement !== 0) {
if(finalElement !== null) {
changePixel(otherPixel,finalElement);
} else {
deletePixel(otherPixel.x,otherPixel.y);
};
};
pixel.value += ValueData.value;
} else if(typeof(ValueData) === "number") {
deletePixel(otherPixel.x,otherPixel.y);
pixel.value += ValueData;
};
};
};
};
return true;
};
function valueFunction(pixel,valueObject,elementWhitelist=null) {
if(typeof(pixel.value) === "undefined") {
pixel.value = 0;
};
var oldValue = pixel.value;
if(!valueAbsorbency(pixel,valueObject) || isNaN(pixel.value)) {
pixel.value = oldValue;
};
var oldValue = pixel.value;
if(!valueSpreading(pixel,elementWhitelist) || isNaN(pixel.value)) {
pixel.value = oldValue;
};
}
//this important thing somehow disappeared
haseuliteValueObject = {
light: 1,
radiation: 4,
fire: {value: 6, remainder: "smoke"},
rad_fire: {value: 10, remainder: "rad_smoke"},
liquid_fire: {value: 12, remainder: ["fire","liquid_smoke","smoke"]},
plasma: {value: 15, remainder: "fire"},
holy_fire: 25,
god_slayer_fire: 40,
liquid_rad_fire: {value: 20, remainder: [null,"rad_fire","rad_fire","rad_smoke","rad_smoke"]},
liquid_plasma: {value: 30, remainder: ["plasma","liquid_fire","fire"]},
liquid_holy_fire: {value: 50, remainder: ["holy_fire","bless","light"]},
liquid_god_slayer_fire: {value: 80, remainder: ["god_slayer_fire",null,null]},
liquid_irradium: {value: 4, remainder: 0}
};
function haseulitoidTick(pixel) {
if(pixel.value == undefined) { pixel.value = 0 };
valueFunction(pixel,haseuliteValueObject,haseuliteSpreadWhitelist);
if(pixel.radioactive && Math.random() < 0.05) { pixel.value += 4 };
if(pixel.oldColor === undefined) { pixel.oldColor = pixelColorPick(pixel) };
if(pixel.oldColor === null) { pixel.oldColor = pixel.color };
if(isNaN(pixel.value)) { pixel.value = 0 };
pixel.color = lightenColor(pixel.oldColor,pixel.value / 3);
var mVal = elements[pixel.element].haseulitoidMaxValue ?? 350;
if(pixel.value >= mVal) {
var coldBoomChance = Math.max(0.008 * ((pixel.value - mVal) / (mVal * 2/7)), 0.001);
if(Math.random() < coldBoomChance) {
var coldBoomRadius = Math.min(40,Math.floor(7 + ((pixel.value - mVal) / (mVal * 2/7))));
explodeAtPlus(pixel.x,pixel.y,coldBoomRadius,"cold_fire","cold_smoke",null,coldExplosionAfterCooling);
};
};
}
elements.haseulite = {
color: ["#3cb00e", "#25d119", "#79f553"],
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
properties: {
oldColor: null
},
behavior: behaviors.WALL,
tick: function(pixel) { haseulitoidTick(pixel) },
excludeVelocity: true, //wall shouldn't move
tempHigh: 1757,
onExplosionBreakOrSurvive: function(pixel,x,y,radius) {
/*power is always radius/10
r 5: value 7
r 10: value 14
r 15: value 28
r 20: value 56
r 25: value 112
r 30: value 224
*/
pixel.value += (2**(((radius) / 5) - 1) * 7);
},
category: "solids",
state: "solid",
density: 7550,
hardness: 0.93,
breakInto: "haseulite_powder",
conduct: 0.84,
};
if(!elements.steel.reactions) {
elements.steel.reactions = {};
};
elements.steel.reactions.haseulite_powder = {
elem1: "haseulite_vent",
elem2: null,
chance: 0.01,
tempMin: 1200,
};
adjacentCoordsInverted = [[0,-1],[0,1],[-1,0],[1,0]];
elements.haseulite_vent = {
color: "#88b058",
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
behavior: behaviors.WALL,
rotatable: true,
desc: "This uses rotation, so just use debug to see the r value. r 0 means it vents haseulite below it upwards, r 1 means it vents haseulite above it downwards, r 2 means it vents left, and r 3 means it vents right.",
tick: function(pixel) {
if(isNaN(pixel.r)) {
pixel.r = 0;
};
pixel.r = pixel.r % 4;
var coord = adjacentCoords[pixel.r];
var invertCoord = adjacentCoordsInverted[pixel.r];
var fX = pixel.x+coord[0];
var fY = pixel.y+coord[1];
if(!isEmpty(fX,fY,true)) {
var otherPixel = pixelMap[fX][fY];
var otherElement = otherPixel.element;
var otherInfo = elements[otherElement];
if(typeof(otherPixel) === "undefined" || isEmpty(fX,fY,true)) {
return false;
};
if(haseuliteSpreadWhitelist.includes(otherElement)) {
var ventLimit = Math.min(10,Math.floor(1 + (Math.sqrt(Math.max(otherPixel.value,1)) / 2)));
for(i = 1; i <= ventLimit; i++) {
if(otherPixel.value >= 3) {
var fIX = pixel.x+(invertCoord[0] * i);
var fIY = pixel.y+(invertCoord[1] * i);
if(isEmpty(fIX,fIY,false)) {
var newCF = createPixelReturn("cold_fire",fIX,fIY);
newCF.temp -= (otherPixel.value / 4);
otherPixel.value -= 3;
} else { //if the pixel to place isn't empty
if(!outOfBounds(fIX,fIY)) { //if it isn't OoB
if(pixelMap[fIX][fIY].element !== "cold_fire") { //if it isn't cold fire
break;
};
} else { //if it is OoB
break;
};
};
} else {
break;
};
};
};
};
return true;
},
excludeVelocity: true, //wall shouldn't move
tempHigh: elements.steel.tempHigh,
stateHigh: ["molten_steel","haseulite_powder"],
breakInto: ["metal_scrap","haseulite_powder"],
category: "machines",
state: "solid",
density: 7550,
hardness: 0.93,
breakInto: "haseulite_powder",
conduct: 0.84,
}
elements.haseulite_powder = {
color: ["#5fb33e", "#32ba29", "#63d141"],
properties: {
oldColor: null
},
category: "powders",
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
tempHigh: 1757,
behavior: behaviors.POWDER,
tick: function(pixel) { haseulitoidTick(pixel) },
onExplosionBreakOrSurvive: function(pixel,x,y,radius) {
/*power is always radius/10
r 5: value 7
r 10: value 14
r 15: value 28
r 20: value 56
r 25: value 112
r 30: value 224
*/
pixel.value += (2**(((radius) / 5) - 1) * 7);
},
stateHigh: "molten_haseulite",
category: "powders",
state: "solid",
hidden: true,
density: 4512,
hardness: 0.7,
conduct: 0.43,
};
elements.molten_haseulite = {
color: ["#cbf569","#f1ffd6","#fdffb5", "#fffa99"],
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
properties: {
oldColor: null
},
behavior: behaviors.LIQUID, //fire creation is problematic due to smoke cooling
tick: function(pixel) { haseulitoidTick(pixel) },
onExplosionBreakOrSurvive: function(pixel,x,y,radius) {
/*power is always radius/10
r 5: value 7
r 10: value 14
r 15: value 28
r 20: value 56
r 25: value 112
r 30: value 224
*/
pixel.value += (2**(((radius) / 5) - 1) * 7);
},
density: 7214,
hardness: 0.52,
breakInto: "haseulite_gas",
temp: 1957,
tempHigh: 3100,
conduct: 0.23,
};
elements.haseulite_gas = {
color: ["#ffff9d", _cc.w.h, "#e9ffe6", "#ffffe5"],
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
properties: {
oldColor: null
},
tick: function(pixel) { haseulitoidTick(pixel) },
onExplosionBreakOrSurvive: function(pixel,x,y,radius) {
/*power is always radius/10
r 5: value 7
r 10: value 14
r 15: value 28
r 20: value 56
r 25: value 112
r 30: value 224
*/
pixel.value += (2**(((radius) / 5) - 1) * 7);
},
density: 0.289,
temp: 3700,
hardness: 1,
conduct: 0.13,
};
elements.hanichrite = { //the names nickel, chrome, and haseulite do not mix
color: ["#dde6bc", "#ebf2ef", "#e8fab1"],
behavior: behaviors.WALL,
tempHigh: 1560,
category: "solids",
density: 8218,
conduct: 0.75,
hardness: 0.78,
state: "solid",
tick: function(pixel) {
if(nichromeDoNeighborCount) {
var neighbors = 0;
for(i = 0; i < adjacentCoords.length; i++) {
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
var newPixel = pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]];
if(elements[newPixel.element].conduct) { neighbors++ };
};
};
};
if(pixel.charge) {
pixel.temp -= ((1.13 + nichromeNeighborLogic(neighbors)) * pixel.charge);
};
},
movable: false
};
elements.molten_hanichrite = {
tick: function(pixel) {
if(nichromeDoNeighborCount) {
var neighbors = 0;
for(i = 0; i < adjacentCoords.length; i++) {
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
var newPixel = pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]];
if(elements[newPixel.element].conduct) { neighbors++ };
};
};
};
if(pixel.charge) {
pixel.temp -= ((1.13 + nichromeNeighborLogic(neighbors)) * pixel.charge) * 1.09;
};
},
};
/*
var shimmeringColor = convertHslObjects(hslColorStringToObject(`hsl(${(pixelTicks / 2) % 360},100%,50%)`,"rgb"));
customStaining(pixel,shimmeringColor,0.2);
*/
function heejinitoidTick(pixel) {
pixel.color ??= pixelColorPick(pixel);
if(pixel.oldColor === null) { pixel.oldColor = pixel.color };
if(pixel.oldColor === undefined) { pixel.oldColor = pixelColorPick(pixel) };
var color = rgbStringToHSL((convertColorFormats(pixel.oldColor,"rgb") ?? pixelColorPick(pixel)),"json");
var heejiniteHueSpread = 30 + (pixel.temp/9.25)
var hueOffset = (Math.sin(pixelTicks / 11) * heejiniteHueSpread) + 15; color.h += hueOffset;
var color = convertHslObjects(color,"rgb");
pixel.color = color;
};
function hotHeejinitoidTick(pixel) {
if(pixel.oldColor === undefined) { pixel.oldColor = pixelColorPick(pixel) };
if(Math.random() < (pixel.temp >= 1500 ? 0.02 : 0.01)) {
if(pixel.temp >= 1387.5) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rX = randomNeighborOffset[0];
var rY = randomNeighborOffset[1];
var rfX = pixel.x+rX;
var rfY = pixel.y+rY;
if(isEmpty(rfX,rfY,false)) {
var randomEligibleHotElement = hotHeejiniteElements[Math.floor(Math.random() * hotHeejiniteElements.length)];
createPixel(randomEligibleHotElement,rfX,rfY);
pixelMap[rfX][rfY].temp = pixel.temp;
};
};
};
}
elements.heejinite = {
color: ["#cf1172", "#fa1977", "#ff619e"],
fireColor: ["#a9085e", "#a32e61", "#fca7c6"],
properties: {
oldColor: null
},
behavior: behaviors.WALL,
tick: function(pixel) { heejinitoidTick(pixel) },
excludeVelocity: true, //wall shouldn't move
tempHigh: 837,
category: "solids",
state: "solid",
density: 3773,
stain: 0.1,
hardness: 0.79,
breakInto: "heejinite_powder",
conduct: 0.86,
};
elements.heejinite_powder = {
color: ["#d64790", "#e63e84", "#f054ac"],
fireColor: ["#a9085e", "#a32e61", "#fca7c6"],
properties: {
oldColor: null
},
behavior: behaviors.POWDER,
tick: function(pixel) { heejinitoidTick(pixel) },
excludeVelocity: true, //wall shouldn't move
tempHigh: 837,
hidden: true,
stateHigh: "molten_heejinite",
category: "powders",
state: "solid",
density: 1412,
stain: 0.1,
hardness: 0.66,
breakInto: "heejinite_powder",
conduct: 0.42,
};
elements.molten_heejinite = {
color: ["#ff0f77","#ff59c2","#ff405c", "#fa5a48"],
fireColor: ["#a9085e", "#a32e61", "#fca7c6"],
properties: {
oldColor: null
},
tick: function(pixel) {
heejinitoidTick(pixel);
hotHeejinitoidTick(pixel);
},
density: 3121,
hardness: 0.5,
breakInto: "heejinite_gas",
temp: 1000,
tempHigh: 1501,
conduct: 0.22,
};
elements.heejinite_gas = {
color: ["#fffab8", "#ffdab3", "#ffd1d1", "#ffc4df", "#ffb0eb"],
fireColor: ["#a9085e", "#a32e61", "#fca7c6"],
properties: {
oldColor: null
},
tick: function(pixel) {
heejinitoidTick(pixel);
hotHeejinitoidTick(pixel);
},
density: 0.117,
temp: 1800,
hardness: 1,
conduct: 0.12,
};
jinsouliteReducedSwapWhitelist = ["slime","glue","soda","milk","chocolate_milk","fruit_milk","ink","blood","vaccine","antibody","infection","sap","ketchup","spirit_tear","enchanted_ketchup","lean","poisoned_ketchup","dirty_ketchup","zombie_blood"];
function jinsouliteDissolution(pixel) {
var did = false;
for(i = 0; i < 2; i++) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rfX = pixel.x+randomNeighborOffset[0];
var rfY = pixel.y+randomNeighborOffset[1];
if(!isEmpty(rfX,rfY,true)) {
var rOtherPixel = pixelMap[rfX][rfY];
if(!rOtherPixel) { return false };
var rOtherElement = rOtherPixel.element;
if(rOtherElement.endsWith("water") || (Math.random() < 0.3 && jinsouliteReducedSwapWhitelist.includes(rOtherElement))) {
swapPixels(pixel,rOtherPixel);
did = true;
};
};
};
return did;
};
function jinsouliteMovement(pixel,move1Spots,move2Spots) {
if(move1Spots.length > 0) {
var randomMove1 = move1Spots[Math.floor(Math.random() * move1Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove1[0], pixel.y+randomMove1[1])) {
//console.log((pixel.x+randomMove1[0]) + " " + (pixel.y+randomMove1[1]))
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1]) || !jinsouliteRxnStealerImmutableEl2DoNotUse(pixel,newPixel,"water",true,2)) {
if(move2Spots.length > 0) {
var randomMove2 = move2Spots[Math.floor(Math.random() * move2Spots.length)];
if(!tryMove(pixel, pixel.x+randomMove2[0], pixel.y+randomMove2[1])) {
var newPixel = null;
if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) {
newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA
};
if(newPixel !== null) { jinsouliteRxnStealerImmutableEl2DoNotUse(pixel,newPixel,"water",true,2) };
};
};
};
};
};
doDefaults(pixel);
};
function jinsouliteSolidNonWaterSideReactions(pixel) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rfX = pixel.x+randomNeighborOffset[0];
var rfY = pixel.y+randomNeighborOffset[1];
if(!isEmpty(rfX,rfY,true)) {
var rOtherPixel = pixelMap[rfX][rfY];
if(typeof(rOtherPixel) === "undefined" || isEmpty(rfX,rfY,true)) {
return false;
};
jinsouliteRxnStealerImmutableEl2DoNotUse(pixel,rOtherPixel,"water",true,2);
};
return true;
};
function jinsouliteSolidWaterSideReactions(pixel) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rfX = pixel.x+randomNeighborOffset[0];
var rfY = pixel.y+randomNeighborOffset[1];
if(!isEmpty(rfX,rfY,true)) {
var pixel2 = pixelMap[rfX][rfY];
var pixel1 = pixel;
if(typeof(pixel2) === "undefined" || isEmpty(rfX,rfY,true)) {
return false;
};
if(typeof(pixel1) === "undefined" || isEmpty(pixel.x,pixel.y,true)) {
return false;
};
var rOtherElement = pixel2.element;
var waterReactions = elements.water.reactions;
if(rOtherElement === pixel.element) {
return false;
};
if(waterReactions[rOtherElement]) {
var r = waterReactions[rOtherElement];
if (r.setting && settings[r.setting]===0) {
return false;
}
// r has the attribute "y" which is a range between two y values
// r.y example: [10,30]
// return false if y is defined and pixel1's y is not in the range
if (r.tempMin !== undefined && pixel1.temp < r.tempMin) {
return false;
}
if (r.tempMax !== undefined && pixel1.temp > r.tempMax) {
return false;
}
if (r.charged && !pixel.charge) {
return false;
}
if (r.chance !== undefined && Math.random() < (r.chance * 2)) {
return false;
}
if (r.y !== undefined && (pixel1.y < r.y[0] || pixel1.y > r.y[1])) {
return false;
}
if (r.charge1) { pixel1.charge = r.charge1; }
if (r.temp1) { pixel1.temp += r.temp1; pixelTempCheck(pixel1); }
if (r.color1) { // if it's a list, use a random color from the list, else use the color1 attribute
pixel1.color = pixelColorPick(pixel1, Array.isArray(r.color1) ? r.color1[Math.floor(Math.random() * r.color1.length)] : r.color1);
}
if (r.attr1) { // add each attribute to pixel1
for (var key in r.attr1) {
pixel1[key] = r.attr1[key];
}
}
var elem1 = r.elem1
if (elem1 !== undefined && elem1 instanceof Array) {
elem1 = elem1[Math.floor(Math.random() * elem1.length)];
};
if (r.elem2 !== undefined) {
// if r.elem2 is an array, set elem2 to a random element from the array, otherwise set it to r.elem2
if (Array.isArray(r.elem2)) {
var elem2 = r.elem2[Math.floor(Math.random() * r.elem2.length)];
} else { var elem2 = r.elem2; }
if (elem2 == null) {
if(elem1 !== undefined) { changePixel(pixel2,elem1) };
}
else {
changePixel(pixel2,elem2);
}
}
if (r.charge2) { pixel2.charge = r.charge2; }
if (r.temp2) { pixel2.temp += r.temp2; pixelTempCheck(pixel2); }
if (r.color2) { // if it's a list, use a random color from the list, else use the color2 attribute
pixel2.color = pixelColorPick(pixel2, Array.isArray(r.color2) ? r.color2[Math.floor(Math.random() * r.color2.length)] : r.color2);
}
if (r.attr2) { // add each attribute to pixel2
for (var key in r.attr2) {
pixel2[key] = r.attr2[key];
}
}
if (r.func) { r.func(pixel1,pixel2); }
return r.elem1!==undefined || r.elem2!==undefined;
};
};
return true;
};
function jinsouliteValue(pixel) {
valueFunction(pixel,jinsouliteValueObject,jinsouliteSpreadWhitelist);
if(pixel.oldColor === null) { pixel.oldColor = pixel.color };
if(isNaN(pixel.value)) { pixel.value = 0 };
pixel.color = changeSaturation(pixel.oldColor,pixel.value / 3,"subtract","rgb")
if(pixel.value > 1) {
if(Math.random() < Math.min((pixel.value / 200),0.5)) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rX = randomNeighborOffset[0];
var rY = randomNeighborOffset[1];
var rfX = pixel.x+rX;
var rfY = pixel.y+rY;
if(isEmpty(rfX,rfY,false)) {
createPixel("water",rfX,rfY);
pixel.value--;
};
};
/*for(g = 0; g < adjacentCoords.length; g++) {
var oX = adjacentCoords[g][0];
var oY = adjacentCoords[g][1];
var fX = pixel.x+oX;
var fY = pixel.y+oY;
if(isEmpty(fX,fY,false)) {
createPixel("water",fX,fY);
pixel.value--;
};
};*/
};
}
function jinsoulitoidTick(pixel,move1Spots=[],move2Spots=[]) {
if(pixel.oldColor === undefined) { pixel.oldColor = pixelColorPick(pixel) };
if(pixel.value == undefined) { pixel.value = 0 };
if(jinsouliteDissolution(pixel)) {
return;
};
jinsouliteValue(pixel);
jinsouliteMovement(pixel,move1Spots,move2Spots);
};
elements.jinsoulite = {
color: ["#0e51b0", "#2129ff", "#3b3dbf"],
fireColor: ["#121978", "#6a9fe6", "#5963d9"],
behavior: [
"XX|CR:water%0.05|XX",
"CR:water%0.05|XX|CR:water%0.05",
"XX|CR:water%0.05|XX"
],
behaviorOn: [
"XX|CR:water%0.15|XX",
"CR:water%0.15|XX|CR:water%0.15",
"XX|CR:water%0.15|XX"
],
properties: {
oldColor: null
},
tick: function(pixel) {
if(pixel.value == undefined) { pixel.value = 0 };
if(pixel.oldColor === undefined) { pixel.oldColor = pixelColorPick(pixel) };
jinsouliteValue(pixel);
jinsouliteSolidNonWaterSideReactions(pixel);
jinsouliteSolidWaterSideReactions(pixel);
},
tempHigh: 2606,
category: "solids",
state: "solid",
density: 8331,
hardness: 0.82,
breakInto: "jinsoulite_powder",
conduct: 0.93,
};
elements.jinsoulite_powder = {
color: ["#4580ba", "#355eb0", "#2d6fc4"],
fireColor: ["#121978", "#6a9fe6", "#5963d9"],
tempHigh: 2606,
behavior: [
"XX|CR:water%0.05|XX",
"CR:water%0.05|XX|CR:water%0.05",
"XX|CR:water%0.05|XX"
],
properties: {
oldColor: null
},
category: "powders",
behaviorOn: [
"XX|CR:water%0.15|XX",
"CR:water%0.15|XX|CR:water%0.15",
"XX|CR:water%0.15|XX"
],
tick: function(pixel) { jinsoulitoidTick(pixel,[[0,1]],[[-1,1],[1,1]]) },
stateHigh: "molten_jinsoulite",
category: "powders",
state: "solid",
hidden: true,
density: 5801,
hardness: 0.7,
conduct: 0.43,
};
elements.molten_jinsoulite = {
behavior: [
"XX|CR:fire,fire,steam%0.5|XX",
"XX|XX|XX",
"XX|XX|XX"
],
behaviorOn: [
"XX|CR:fire,steam,steam%0.7|XX",
"CR:steam%0.1|XX|CR:steam%0.1",
"XX|CR:steam%0.1|XX"
],
properties: {
oldColor: null
},
color: ["#4e35db","#7767eb","#a876f5", "#78acff"],
fireColor: ["#121978", "#6a9fe6", "#5963d9"],
fireElement: ["fire","fire","steam"],
tick: function(pixel) { jinsoulitoidTick(pixel,[[-1,1],[0,1],[1,1]],[[-1,0],[1,0]]); },
density: 6448,
hardness: 0.61,
breakInto: "jinsoulite_gas",
temp: 3000,
tempHigh: 5532.8509,
conduct: 0.34,
};
elements.jinsoulite_gas = {
color: ["#c0f0ef", "#c2c1db", "#c0bff5", "#cdcce6"],
behavior: [
"XX|CR:steam%0.5|XX",
"CR:steam%0.5|XX|CR:steam%0.5",
"XX|CR:steam%0.5|XX",
],
behaviorOn: [
"XX|CR:steam%1|XX",
"CR:steam%1|XX|CR:steam%1",
"XX|CR:steam%1|XX",
],
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
properties: {
oldColor: null
},
tick: function(pixel) { jinsoulitoidTick(pixel,adjacentCoords,[[-1,-1],[1,-1],[1,1],[-1,1]]) },
density: 0.5833,
temp: 6000,
hardness: 1,
conduct: 0.19,
};
//apples (used for yvesite)
appleAttachWhitelist = ["wood","tree_branch"];
elements.apple = {
color: ["#ad2333", "#b51616", "#d6782f", "#e3c634", "#99de31"],
isFood: true,
tick: function(pixel) {
if(pixel.attached) { //only attaches upwards
if(isEmpty(pixel.x,pixel.y-1,true)) {
pixel.attached = false;
};
} else { //Move if not attached
if (!tryMove(pixel, pixel.x, pixel.y+1)) {
if(Math.random() < 0.3) {
if (Math.random() < 0.5) {
if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
tryMove(pixel, pixel.x-1, pixel.y+1);
};
} else {
if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
tryMove(pixel, pixel.x+1, pixel.y+1);
};
};
};
};
};
doDefaults(pixel);
var shouldSpoil = true; //spoil by default
if(pixel.attached) { //if it's attached
if(!isEmpty(pixel.x,pixel.y-1,true)) { //if the attachment coords are a pixel and not OOB
var attachPixel = pixelMap[pixel.x][pixel.y-1];
var attachElement = attachPixel.element;
if(appleAttachWhitelist.includes(attachElement)) {//if the element is a whitelisted "don't spoil" element
shouldSpoil = false; //then don't spoil
};
};
};
if(shouldSpoil) { //spoil if not attached
if(pixel.temp > -18 && pixel.temp <= 4) { //(no spoiling below -18C)
pixel.spoilage += Math.max(Math.min(scale(pixel.temp,-18,4,0,9),9),0)
} else if(pixel.temp > 4) {
pixel.spoilage += Math.max(Math.min(scale(pixel.temp,4,20,9,30),40),0)
};
};
if(pixel.spoilage > 14400) { //3600 = 120 ticks at 20C
if(Math.random() < 0.05) {
changePixel(pixel,"rotten_apple");
};
};
},
properties: {
"spoilage": 0,
"attached": false
},
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
tempHigh: 200,
stateHigh: ["steam", "ash"],
onTryMoveInto: function(pixel,otherPixel) {
var otherInfo = elements[otherPixel.element]
if(typeof(otherInfo.state) === "string" && otherInfo.state !== "gas") {
pixel.attached = false;
};
},
};
elements.rotten_apple = {
hidden: true,
color: ["#802e24", "#9c4227", "#a34b26"],
behavior: [
"XX|CR:stench,fly%0.1|XX",
"M2%0.5|CH:dirty_water,fly,fly%0.007|M2%0.5",
"M2|M1|M2"
],
stain: 0.01,
burn: 5,
burnInto: ["steam", "ash"],
burnTime: 600,
tempHigh: 200,
stateHigh: ["steam", "ash"],
};
//Yvesite
var yvesiteAppleSpots = [[-1, 1], [0, 1], [1, 1]];
var yvesitePowderAppleSpots = [[-1, 0], [0, -1], [1, 0]];
function yvesiteApples(pixel,offsets) {
if(pixel.charge) {
var probAdd = Math.min(0,Math.max(pixel.temp,100)) / 2500;
if(Math.random() < (0.02 + probAdd)) {
var appleOffset = randomChoice(offsets);
if(tryCreatePixel("apple",pixel.x+appleOffset[0],pixel.y+appleOffset[1])) {
var apple = pixelMap[pixel.x+appleOffset[0]][pixel.y+appleOffset[1]];
apple.color = pixelColorPick(apple,"#c40e2c");
apple.spoilage = -Infinity;
return true;
} else {
return null;
};
};
};
return false;
};
elements.yvesite = {
color: ["#850f2c", "#9c0e3d", "#911f3b", "#701625"],
fireColor: ["#b5103f", "#ab3254", "#cc2157", "#ba0936"],
behavior: behaviors.WALL,
tick: function(pixel) {
yvesiteApples(pixel,yvesiteAppleSpots);
},
reactions: {
heejinite: {temp1: 1, temp2: 1},
molten_heejinite: {temp1: 2, temp2: 2},
heejinite_powder: {temp1: 2, temp2: 2},
heejinite_gas: {temp1: 3, temp2: 3}
},
tempHigh: 1545,
category: "solids",
state: "solid",
density: 3601,
hardness: 0.88,
breakInto: "yvesite_powder",
conduct: 0.94,
};
elements.yvesite_powder = {
color: ["#8f1734", "#962638", "#b32749", "#911a3e"],
fireColor: ["#b5103f", "#ab3254", "#cc2157", "#ba0936"],
behavior: behaviors.POWDER,
tick: function(pixel) {
yvesiteApples(pixel,yvesitePowderAppleSpots);
},
reactions: {
heejinite: {temp1: 2, temp2: 2},
molten_heejinite: {temp1: 3, temp2: 3},
heejinite_powder: {temp1: 3, temp2: 3},
heejinite_gas: {temp1: 4, temp2: 4}
},
tempHigh: 1545,
stateHigh: "molten_yvesite",
category: "solids",
state: "solid",
density: 1500,
hardness: 0.43,
breakInto: "yvesite_powder",
conduct: 0.84,
};
elements.molten_yvesite = {
color: ["#e81554", "#c90842", "#db4d70", "#cf2b54"],
fireColor: ["#b5103f", "#ab3254", "#cc2157", "#ba0936"],
behavior: behaviors.MOLTEN,
density: 3608,
state: "liquid",
hardness: 0.57,
breakInto: "yvesite_gas",
temp: 1545,
tempHigh: 3145,
stateHigh: "yvesite_gas",
tempLow: 1545,
stateLow: "yvesite",
conduct: 0.22,
};
elements.yvesite_gas = {
color: ["#e34070", "#d13060", "#c2234a", "#db4866"],
fireColor: ["#b5103f", "#ab3254", "#cc2157", "#ba0936"],
behavior: behaviors.GAS,
state: "gas",
tempLow: 3145,
stateLow: "molten_yvesite",
density: 8.16,
temp: 3300,
hardness: 1,
conduct: 0.11,
};
elements.fly.reactions.rotten_apple = { "elem2":null, chance:0.15, func:behaviors.FEEDPIXEL };
//Vivite
elements.vivite = {
color: ["#ffb5ee", "#fc9fe0", "#fcd9fb"],
colorOn: ["#ff8ca9", "#f76583", "#fcb8d5"],
fireColor: ["#ff66ba", "#ff85ef", "#ff99f7"],
behavior: behaviors.WALL,
onCharge: function(pixel) {
if(isNaN(pixel.charge)) { pixel.charge = 0 };
if(isNaN(pixel.temp)) { pixel.temp = 20 };
if(!pixel) { return false };
doElectricity(pixel);
for(i = 0; i < adjacentCoords.length; i++) {
var newPixel = pixelMap[pixel.x+adjacentCoords[i][0]]?.[pixel.y+adjacentCoords[i][1]];
if(newPixel) {
newPixel.charge ??= 0;
if(isNaN(newPixel.charge)) { newPixel.charge = 0 };
try {
newPixel.charge ??= 0;
if(isNaN(newPixel.charge)) { newPixel.charge = 0 };
doElectricity(newPixel)
if(isNaN(newPixel.charge)) { newPixel.charge = 0 };
} catch (error) {
if(error.toString().includes("Maximum call stack size exceeded")) {
return;
};
throw error;
};
} else {
continue;
};
};
},
tick: function(pixel) {
if(isNaN(pixel.charge)) { pixel.charge = 0 };
if(isNaN(pixel.temp)) { pixel.temp = 20 };
if(Math.random() < 0.013 && exposedToAir(pixel)) {
changePixel(pixel,"vivite_oxide",false);
pixel.temp += 4;
};
},
burnTime: 160,
burnTempChange: 10.65,
burnInto: "vivite_oxide_powder",
noResistance: true,
reactions: {
"ice": { elem1: "vivite_oxide", elem2: null, temp1: 0.2 },
"water": { elem1: "vivite_oxide", elem2: null, temp1: 0.2 },
"steam": { elem1: "vivite_oxide", elem2: null, temp1: 0.2 },
"seltzer": { elem1: "vivite_oxide", elem2: "carbon_dioxide" },
"seltzer_ice": { elem1: "vivite_oxide", elem2: "carbon_dioxide" },
"sugar_water": { elem1: "vivite_oxide", elem2: "sugar" },
"sugar_ice": { elem1: "vivite_oxide", elem2: "sugar" },
"pool_water": { elem1: "vivite_oxide", elem2: "chlorine" },
"pool_ice": { elem1: "vivite_oxide", elem2: "chlorine" },
"salt_water": { elem1: "vivite_oxide", elem2: "salt" },
"salt_ice": { elem1: "vivite_oxide", elem2: "salt" }
},
tempHigh: 938,
category: "solids",
state: "solid",
density: 11013,
hardness: 0.98,
breakInto: "vivite_powder",
conduct: 1,
};
elements.vivite_powder = {
color: ["#f7a6e5", "#fa70d1", "#f0bbf2"],
fireColor: ["#ff66ba", "#ff85ef", "#ff99f7"],
behavior: behaviors.POWDER,
tick: function(pixel) {
if(Math.random() < 0.027 && exposedToAir(pixel)) {
if(getEmptyMooreNeighbors(pixel).length > 4) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
} else {
pixel.temp += 18;
changePixel(pixel,getStateAtTemp("vivite_oxide_powder",pixel.temp),false);
};
if(pixel.burning && ((pixel.temp + (2 * elements[pixel.element].burnTempChange)) > elements[pixel.element].tempHigh)) {
changePixel(pixel,elements[pixel.element].burnInto,false);
pixel.temp += 213;
};
};
},
burnTime: 8,
burnTempChange: 213,
burnInto: "vivite_oxide_powder",
reactions: {
"ice": { elem1: "vivite_oxide_powder", elem2: null, temp1: 0.2 },
"water": { elem1: "vivite_oxide_powder", elem2: null, temp1: 0.2 },
"steam": { elem1: "vivite_oxide_powder", elem2: null, temp1: 0.2 },
"seltzer": { elem1: "vivite_oxide_powder", elem2: "carbon_dioxide" },
"seltzer_ice": { elem1: "vivite_oxide_powder", elem2: "carbon_dioxide" },
"sugar_water": { elem1: "vivite_oxide_powder", elem2: "sugar" },
"sugar_ice": { elem1: "vivite_oxide_powder", elem2: "sugar" },
"pool_water": { elem1: "vivite_oxide_powder", elem2: "chlorine" },
"pool_ice": { elem1: "vivite_oxide_powder", elem2: "chlorine" },
"salt_water": { elem1: "vivite_oxide_powder", elem2: "salt" },
"salt_ice": { elem1: "vivite_oxide_powder", elem2: "salt" }
},
noResistance: true,
tempHigh: 1725,
stateHigh: "molten_vivite",
category: "solids",
state: "solid",
density: 8471,
hardness: 0.99613,
breakInto: "vivite_powder",
conduct: 0.89,
};
elements.smog.stateLow = ["water","dirty_water"];
/*Object.keys(elements).filter(
function(elem) {
return (
!wateroids.includes(elem) && (
wateroids.includes(elements[elem].stateHigh) ||
wateroids.includes(elements[elem].stateLow)
)
)
}
);*/
function doViviteSlag(pixel,target) {
if(!target) { //No pixel
return false;
};
var newElement = target.element;
if(newElement.includes("vivite")) { //Is vivite
return false;
};
if(elements[pixel.element].reactions?.[newElement]) { //Pre-existing reaction
return false;
};
if(elements[newElement].noViviteSlag || elements[pixel.element].ignore?.includes(newPixel.element)) { //Excluded
return false;
};
if(elements[newElement].state == "gas" && !elements[newElement].viviteSlag) {
return false;
};
changePixel(newPixel,"vivite_slag",false);
if(Math.random() < 1/3) { changePixel(pixel,"molten_vivite_slag",false) };
return true;
};
elements.molten_vivite = {
color: ["#f7a6e5", "#fa70d1", "#f0bbf2"],
colorOn: ["#ff63ac", "#ff21bd", "#e81af0"],
fireColor: ["#ff66ba", "#ff85ef", "#ff99f7"],
ignore: ["wall","heejinite","jinsoulite","haseulite","molten_heejinite","molten_jinsoulite","molten_haseulite","yvesite","molten_yvesite"],
tick: function(pixel) {
var info = elements[pixel.element];
if(Math.random() < 0.022 && exposedToAir(pixel)) {
changePixel(pixel,pixel.temp > 7315.27 ? "molten_vivite_oxide" : "vivite_oxide_powder",false)
pixel.temp += 18;
};
if(Math.random() < 0.025) {
var fireColor = info.fireColor;
while(fireColor instanceof Array) { fireColor = fireColor[Math.floor(Math.random() * fireColor.length)] };
var newFire = tryCreatePixelReturn("fire",pixel.x,pixel.y-1);
if(newFire) {
newFire.color = pixelColorPick(newFire,fireColor);
newFire.temp = pixel.temp;
};
};
var viscosityMoveChance = ((Math.random()*100) < 100 / ((info.viscosity ?? 1) ** 0.25)); //returns true if doing m2
var move1Spots = viscosityMoveChance ? [[-1,1],[0,1],[1,1]] : [[0,1]];
var move1Offset = move1Spots[Math.floor(Math.random() * move1Spots.length)];
if(!tryMove(pixel, pixel.x + move1Offset[0], pixel.y + move1Offset[1])) {
var newPixel = pixelMap[pixel.x + move1Offset[0]]?.[pixel.y + move1Offset[1]];
if(newPixel) {
doViviteSlag(pixel,newPixel);
};
var move2Spots = [[-1,0],[1,0]];
var move2Offset = move2Spots[Math.floor(Math.random() * move2Spots.length)];
//console.log(info.viscosity);
var viscosityMoveChance = ((Math.random()*100) < 100 / ((info.viscosity ?? 1) ** 0.25)); //returns true if doing m2
if(viscosityMoveChance) {
if(!tryMove(pixel, pixel.x + move2Offset[0], pixel.y + move2Offset[1])) {
var newPixel = pixelMap[pixel.x + move2Offset[0]]?.[pixel.y + move2Offset[1]];
if(newPixel) {
doViviteSlag(pixel,newPixel);
};
};
};
};
},
density: 8212,
state: "liquid",
burnTime: 160,
burnTempChange: 10.65,
burnInto: "vivite_oxide_powder",
hardness: 0.88,
viscosity: 10000,
breakInto: "vivite_gas",
temp: 2000,
tempHigh: 2256,
stateHigh: "vivite_gas",
tempLow: 938,
stateLow: "vivite",
conduct: 1,
stain: 0.03,
behavior: behaviors.WALL, //placeholder to prevent an auto-behaviors.MOLTEN process
};
elements.vivite_slag = {
color: ["#d962b1", "#bf67b6", "#b57b9e"],
fireColor: ["#fa5584", "#e85a70", "#e05c69", "#ed8672"],
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"M2%25|M1|M2%25"
],
density: 9777,
category: "solids",
state: "solid",
hardness: 0.71,
breakInto: ["vivite_powder","slag"],
tempHigh: 953,
conduct: 0.27,
};
elements.vivite_oxide = {
color: ["#f5b3c5", "#ffb0c6"],
fireColor: ["#ff1f69", "#ff0004", "#ff006a"],
reactions: {
"carbon_monoxide": { elem1: "vivite", elem2: "carbon_dioxide", tempMin: 543, chance: 0.03 }
},
behavior: behaviors.WALL,
reactions: {
"ice": { elem1: "vivite_hydroxide", elem2: null, temp1: 234, tempMax: 733},
"water": { elem1: "vivite_hydroxide", elem2: null, temp1: 234, tempMax: 733},
"steam": { elem1: "vivite_hydroxide", elem2: null, temp1: 234, tempMax: 733},
"seltzer": { elem1: "vivite_hydroxide", elem2: "carbon_dioxide", temp1: 234, tempMax: 733},
"seltzer_ice": { elem1: "vivite_hydroxide", elem2: "carbon_dioxide", temp1: 234, tempMax: 733},
"sugar_water": { elem1: "vivite_hydroxide", elem2: "sugar", temp1: 234, tempMax: 733},
"sugar_ice": { elem1: "vivite_hydroxide", elem2: "sugar", temp1: 234, tempMax: 733},
"pool_water": { elem1: "vivite_hydroxide", elem2: "chlorine", temp1: 234, tempMax: 733},
"pool_ice": { elem1: "vivite_hydroxide", elem2: "chlorine", temp1: 234, tempMax: 733},
"salt_water": { elem1: "vivite_hydroxide", elem2: "salt", temp1: 234, tempMax: 733},
"salt_ice": { elem1: "vivite_hydroxide", elem2: "salt", temp1: 234, tempMax: 733}
},
density: 5135,
category: "solids",
state: "solid",
hardness: 0.9983,
breakInto: "vivite_oxide_powder",
tempHigh: 7315.27,
};
elements.vivite_oxide_powder = {
color: ["#f5b3c5", "#ffb0c6"],
fireColor: ["#ff1f69", "#ff0004", "#ff006a"],
behavior: behaviors.POWDER,
reactions: {
"carbon_monoxide": { elem1: "vivite_powder", elem2: "carbon_dioxide", tempMin: 543, chance: 0.03 }
},
reactions: {
"ice": { elem1: "vivite_hydroxide", elem2: null, temp1: 234, tempMax: 733},
"water": { elem1: "vivite_hydroxide", elem2: null, temp1: 234, tempMax: 733},
"steam": { elem1: "vivite_hydroxide", elem2: null, temp1: 234, tempMax: 733},
"seltzer": { elem1: "vivite_hydroxide", elem2: "carbon_dioxide", temp1: 234, tempMax: 733},
"seltzer_ice": { elem1: "vivite_hydroxide", elem2: "carbon_dioxide", temp1: 234, tempMax: 733},
"sugar_water": { elem1: "vivite_hydroxide", elem2: "sugar", temp1: 234, tempMax: 733},
"sugar_ice": { elem1: "vivite_hydroxide", elem2: "sugar", temp1: 234, tempMax: 733},
"pool_water": { elem1: "vivite_hydroxide", elem2: "chlorine", temp1: 234, tempMax: 733},
"pool_ice": { elem1: "vivite_hydroxide", elem2: "chlorine", temp1: 234, tempMax: 733},
"salt_water": { elem1: "vivite_hydroxide", elem2: "salt", temp1: 234, tempMax: 733},
"salt_ice": { elem1: "vivite_hydroxide", elem2: "salt", temp1: 234, tempMax: 733}
},
density: 4813,
category: "solids",
state: "solid",
hardness: 0.964,
breakInto: "vivite_oxide_powder",
tempHigh: 7315.27,
stateHigh: "molten_vivite_oxide",
};
elements.vivite_hydroxide = {
color: ["#f19cf7", "#d88aff"],
behavior: behaviors.POWDER,
density: 6112,
category: "solids",
state: "solid",
hardness: 0.9983,
breakInto: "vivite_hydroxide",
tempHigh: 733,
stateHigh: ["vivite_oxide_powder","water"],
};
elements.molten_vivite_oxide = {
fireColor: ["#ff1f69", "#ff0004", "#ff006a"],
reactions: {
"carbon_monoxide": { elem1: "vivite_gas", elem2: "carbon_dioxide", tempMin: 543, chance: 0.03 }
},
density: 6113,
hardness: 0.9993,
breakInto: "molten_vivite_oxide",
temp: 8000,
tempHigh: 15500,
};
elements.vivite_oxide_gas = {
reactions: {
"carbon_monoxide": { elem1: "vivite", elem2: "carbon_dioxide", tempMin: 543, chance: 0.03 }
},
};
elements.molten_vivite_slag = {
color: ["#d44e88", "#db7258", "#eda455"],
fireColor: ["#fa5584", "#e85a70", "#e05c69", "#ed8672"],
density: 9213,
hardness: 0.71,
breakInto: ["molten_vivite","slag"],
temp: 1100,
conduct: 0.18,
stain: 0.04
};
elements.vivite_gas = {
color: ["#ffedfe", "#ffe0fd", "#ffd9f9", "#ffd1f0", "#ffccdf"],
colorOn: ["#eec7fc", "#f5b1fc", "#faa2f1", "#fa93c3", "#ff99b1"],
fireColor: ["#ff66ba", "#ff85ef", "#ff99f7"],
tick: function(pixel) {
if(Math.random() < 0.032 && exposedToAir(pixel)) {
if(getEmptyMooreNeighbors(pixel).length > 4) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
} else {
pixel.temp += 18;
changePixel(pixel,pixel.temp > 15500 ? "vivite_oxide_gas" : pixel.temp > 7315.27 ? "molten_vivite_oxide" : "vivite_oxide_powder",false);
};
};
},
behavior: behaviors.GAS,
state: "gas",
tempLow: 2256,
stateLow: "molten_vivite",
burnTime: 8,
burnTempChange: 213,
burnInto: "vivite_oxide_powder",
density: 18.02,
temp: 3300,
hardness: 1,
conduct: 1,
};
runAfterLoad(function() {
if(elements.carbon_monoxide) {
elements.carbon_monoxide.reactions ??= {};
elements.carbon_monoxide.reactions.vivite_oxide = { elem1: "carbon_dioxide", elem2: "vivite", tempMin: 543, chance: 0.03 };
elements.carbon_monoxide.reactions.vivite_oxide_powder = { elem1: "carbon_dioxide", elem2: "vivite_powder", tempMin: 543, chance: 0.03 };
elements.carbon_monoxide.reactions.molten_vivite_oxide = { elem1: "carbon_dioxide", elem2: "vivite_gas", tempMin: 543, chance: 0.03 };
elements.carbon_monoxide.reactions.vivite_oxide_gas = { elem1: "carbon_dioxide", elem2: "vivite_gas", tempMin: 543, chance: 0.03 };
}
});
runAfterLoad(function() {
for(key in elements.water.reactions) {
var value = JSON.parse(JSON.stringify(elements.water.reactions[key]));
if(typeof(value.chance) === "number") {
value.chance = Math.min(1,value.chance * 2);
};
if(value.elem2 === null && value.elem1 !== null) {
value.elem2 = value.elem1;
};
delete value.elem1;
var movableJinsoulitoids = ["jinsoulite_powder","molten_jinsoulite","jinsoulite_gas"];
for(j = 0; j < movableJinsoulitoids.length; j++) {
var jinsoulitoid = movableJinsoulitoids[j];
if(typeof(elements[jinsoulitoid].reactions) === "undefined") {
elements[jinsoulitoid].reactions = {};
};
if(typeof(elements[jinsoulitoid].reactions[key]) === "undefined") {
elements[jinsoulitoid].reactions[key] = value;
};
};
};
});
//REMNANT OF REMOVED FEATURE ##
function highlightButton(element,color,blurRadius="15px",spreadRadius="5px") {
var button = document.getElementById(`elementButton-${element}`);
if(button == null) {
throw new Error(`Nonexistent button for ${element}`)
};
if(typeof(blurRadius) == "number") { blurRadius = blurRadius + "px" };
if(typeof(spreadRadius) == "number") { spreadRadius = spreadRadius + "px" };
document.getElementById(`elementButton-${element}`).style["-webkit-box-shadow"] = `0px 0px ${blurRadius} ${spreadRadius} ${color}`;
document.getElementById(`elementButton-${element}`).style["box-shadow"] = `0px 0px ${blurRadius} ${spreadRadius} ${color}`;
};
//OTHER FICTIONAL MATERIALS ##
function splitRgbColor(color) {
var colorTempArray = color.split(",")
var r = colorTempArray[0].split(",")[0].substring(4)
var g = colorTempArray[1]
var b = colorTempArray[2].slice(0,-1)
return [r,g,b]
}
elements.laetium = {
color: "#f57f87",
tempHigh: 2950,
hardness: 0.87252,
density: 6719,
conduct: 4.7E210,
behavior: behaviors.WALL,
state: "solid",
category: "solids",
reactions: {
sand: {temp1: 5}
}
}
elements.molten_laetium = {
color: ['#ff9f44', '#ff7f44', '#ff5f00'],
behavior: behaviors.MOLTEN,
reactions: {
"ash": { "elem1": null, "elem2": "laetium_slag"},
"dust": { "elem1": null, "elem2": "laetium_slag"},
"magma": { "elem1": null, "elem2": "laetium_slag"},
"sand": { temp1: 5 }
},
density: 6100,
temp: 3000,
tempLow: 2944,
stateLow: "laetium",
tempHigh: 5837,
stateHigh: "vaporized_laetium",
viscosity: 1.517,
hidden: true,
state: "liquid",
category: "molten",
}
elements.vaporized_laetium = {
color: ['#efdf54', '#efbf54', '#efaf10'],
behavior: behaviors.GAS,
reactions: {
"sand": { temp1: 5 }
},
density: 49,
temp: 6000,
tempLow: 5837,
stateLow: "molten_laetium",
viscosity: 0.1,
hidden: true,
state: "gas",
category: "gases",
}
elements.atisanium = {
color: "#8dadb8",
conduct: 0.87,
colorOn: ["#ff00ff", "#e600e6", "#a300cc", "#ce07e8"],
tempLow: -44,
stateLow: "liquid_atisanium",
density: 1.225,
behavior: [
"M1 AND M1|M1 AND M1|M1 AND M1",
"M1 AND M1|XX|M1 AND M1",
"M1 AND M1|M1 AND M1|M1 AND M1"
],
state: "gas",
category: "gases"
}
elements.liquid_atisanium = {
color: "#3f878a",
conduct: 0.96,
colorOn: ["#8307eb", "#8c00ff", "#9617ff", "#a02eff"],
tempHigh: -45,
stateHigh: "atisanium",
tempLow: -214,
stateLow: "alpha_atisanium",
temp: -100,
density: 1594.1,
behavior: behaviors.LIQUID,
state: "liquid",
category: "liquids",
tick: function(pixel) {
var moveSpotsA = [[-1,1],[0,1],[1,1]]
var moveSpotsB = [[-1,0],[1,0]]
var msaChoice = randomChoice(moveSpotsA)
var msbChoice = randomChoice(moveSpotsB)
if(isEmpty(msaChoice[0],pixel.y+msaChoice[1],true)) {
if(!tryMove(pixel,pixel.x+msaChoice[0],pixel.y+msaChoice[1])) {
tryMove(pixel,pixel.x+msbChoice[0],pixel.y+msbChoice[1])
}
}
if(pixel.chargeCD) {
if(pixel.chargeCD > 2) {
pixel.chargeCD = 2
}
}
if(pixel.chargeCD) {
if(pixel.chargeCD > 1) {
if(Math.random() < 0.2) {
pixel.chargeCD = 1
}
}
}
},
}
elements.alpha_atisanium = {
color: "#00382a",
conduct: 0.987,
colorOn: ["#3700ff", "#6820f7", "#4b15bf"],
tempHigh: -213,
stateHigh: "liquid_atisanium",
tempLow: -261,
stateLow: "beta_atisanium",
temp: -240,
density: 5129.5,
behavior: behaviors.WALL,
state: "solid",
category: "solids",
tick: function(pixel) {
if(pixel.chargeCD) {
if(pixel.chargeCD > 2) {
pixel.chargeCD = 2
}
}
if(pixel.chargeCD) {
if(pixel.chargeCD > 1) {
if(Math.random() < 0.4) {
pixel.chargeCD = 1
}
}
}
},
}
elements.beta_atisanium = {
color: "#750e35",
conduct: Infinity, //This is where I would make it a superconductor.
colorOn: ["#0f0021", "#120324", "#4b106e", "#a6058e", "#42043a"], //pretend this is UV becoming more pronounced
tempHigh: -260,
stateHigh: "alpha_atisanium",
temp: -270,
density: 11129.5,
behavior: behaviors.WALL,
state: "solid",
category: "solids",
tick: function(pixel) {
if(pixel.chargeCD) {
if(pixel.chargeCD > 3) {
pixel.chargeCD = 3
}
}
},
}
elements.polusium = {
color: "#dedc9e",
tempHigh: 1213,
hardness: 0.921952,
density: 4113,
conduct: 0.98,
behavior: behaviors.WALL,
state: "solid",
burnInto: "polusium_oxide",
category: "solids",
tick: function(pixel) {
var emptyNeighbors = [];
for(i = 0; i < adjacentCoords.length; i++) {
if(isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
emptyNeighbors.push(adjacentCoords[i]);
};
};
if(Math.random() < 0.002) {
if(emptyNeighbors.length > 0) {
var randomEmptyNeighbor = emptyNeighbors[Math.floor(Math.random() * emptyNeighbors.length)];
changePixel(pixel,"polusium_oxide")
createPixel("nitrogen",pixel.x+randomEmptyNeighbor[0],pixel.y+randomEmptyNeighbor[1])
};
};
},
reactions: {
water: { elem1: "polusium_oxide", elem2: ["water","water","water","water","hydrogen"], chance: 0.006 },
salt_water: { elem1: "polusium_oxide", elem2: ["salt_water","salt_water","salt_water","salt","hydrogen"], chance: 0.012 },
bleach: { elem1: "polusium_oxide", chance: 0.02 }
},
}
elements.molten_polusium = {
tick: function(pixel) {
neighbors = [[-1,0],[0,-1],[1,0],[0,1]]
for(i = 0; i < neighbors.length; i++) {
if(isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],false)) {
if(Math.random() < 0.004) {
changePixel(pixel,"molten_polusium_oxide")
}
}
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
if(pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]].element == "salt_water") {
if(Math.random() < 0.024) {
changePixel(pixel,"molten_polusium_oxide")
}
}
}
}
},
density: 3410,
temp: 1300,
tempLow: 1212,
stateLow: "polusium",
tempHigh: 3110,
stateHigh: "vaporized_polusium",
viscosity: 13,
}
elements.vaporized_polusium = {
color: ["#fdffd1", "#edf2cb", "#fcfac7"],
behavior: behaviors.GAS,
tick: function(pixel) {
neighbors = [[-1,0],[0,-1],[1,0],[0,1]]
for(i = 0; i < neighbors.length; i++) {
if(isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],false)) {
if(Math.random() < 0.015) {
changePixel(pixel,"vaporized_polusium_oxide")
}
}
if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
if(pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]].element == "salt_water") {
if(Math.random() < 0.06) {
changePixel(pixel,"vaporized_polusium_oxide")
}
}
}
}
},
density: 21,
temp: 3200,
tempLow: 3109,
stateLow: "molten_polusium",
viscosity: 0.2,
hidden: true,
state: "gas",
category: "gases",
}
elements.polusium_oxide = {
color: "#a9b594",
tempHigh: 1300,
hardness: 0.511952,
density: 3717,
behavior: behaviors.POWDER,
state: "solid",
category: "solids",
viscosity: 13,
}
elements.molten_polusium_oxide = {
temp: 1350,
tempHigh: 1400,
stateHigh: "vaporized_polusium_oxide",
density: 2917,
}
elements.vaporized_polusium_oxide = {
color: "#faffc7",
temp: 1500,
tempLow: 1399,
stateLow: "molten_polusium_oxide",
density: 10,
behavior: behaviors.GAS,
}
runAfterLoad(function() {
elements.laetium_slag = JSON.parse(JSON.stringify(elements.slag))
elements.laetium_slag.color = ['#a05c5a', '#af6967', '#b06d6d', '#ae6b6c', '#b67a7a']
elements.laetium_slag.tempHigh = 2950
elements.laetium_slag.stateHigh = ["molten_slag","molten_laetium"]
});
//MORE BROKEN FORMS ##
elements.loose_straw = {
color: ["#F9E3A1","#93734E","#C7AA83"],
behavior: behaviors.POWDER,
tempHigh: 380,
stateHigh: "fire",
burn: 80,
burnTime: 30,
burnInto: "ash",
category: "powders",
state: "solid",
density: 47.5,
hidden: true,
},
elements.straw.breakInto = "loose_straw"
elements.plastic_scrap = {
color: "#c3cccc",
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 200,
stateHigh: "molten_plastic",
burn: 15,
burnTime: 350,
burnInto: "dioxin",
state: "solid",
density: 952,
hidden: true,
},
elements.plastic.breakInto = ["plastic_scrap","dioxin"]
elements.insulation.breakInto = ["plastic_scrap","dioxin","glass_shard"]
elements.copper_scrap = {
color: ["#B96242","#CE5332","#D77045","#994222","#AE3312","#B75025","#A95232","#BE4322","#C76035"],
behavior: [
"XX|XX|XX",
"XX|CH:oxidized_copper%0.005|XX",
"M2|M1|M2",
],
reactions: {
"water": { "elem1":"oxidized_copper", chance:0.0035 },
"salt_water": { "elem1":"oxidized_copper", chance:0.006 },
"dirty_water": { "elem1":"oxidized_copper", chance:0.045 },
"sugar_water": { "elem1":"oxidized_copper", chance:0.0045 }
},
category: "powders",
tempHigh: 1085,
stateHigh: "molten_copper",
density: 5960,
conduct: 0.90,
hidden: true,
},
elements.oxidized_copper_scrap = {
color: ["#507565","#52665A","#618374","#305545","#32463A","#416354","#406555","#42564A","#517364"],
behavior: behaviors.POWDER,
category: "powders",
hidden: true,
tempHigh: 1085,
stateHigh: "molten_copper",
density: 5960,
conduct: 0.80,
hidden: true,
}
elements.copper.breakInto = ["copper_scrap","copper_scrap","copper_scrap","copper_scrap","copper_scrap","oxidized_copper_scrap"]
elements.dry_ice.breakInto = "carbon_dioxide"
elements.frozen_ketchup.breakInto = "ketchup_snow"
elements.frozen_poisoned_ketchup.breakInto = "poisoned_ketchup_snow"
regularShinyThingArray = ["iron", "zinc", "tin", "nickel", "silver", "aluminum", "lead", "tungsten", "brass", "bronze", "sterling", "steel", "white_gold", "blue_gold", "rose_gold", "red_gold", "solder", "gold", "pyrite", "mythril", "mithril_mythril_alloy", "titanium", "ilitium", "mithril", "beryllium", "boron", "ruthenium", "rhodium", "palladium", "rhenium", "osmium", "iridium", "platinum", "frozen_mercury", "lithium", "niobium", "ketchup_metal", "ketchup_gold", "tungstensteel", "densinium", "mithril", "signalum", "laetium", "kurshunjukium", "zirconium", "jinsoulite"];
elements.nitrogen_snow = {
color: "#efefef",
behavior: behaviors.POWDER,
category: "solids",
temp: -259.86,
tempHigh: -209.86,
stateHigh: "liquid_nitrogen",
state: "solid",
density: 850,
hidden: true,
}
elements.nitrogen_ice.breakInto = "nitrogen_snow"
runAfterLoad(function() {
for(i = 0; i < regularShinyThingArray.length; i++) {
var thing = regularShinyThingArray[i];
if(typeof(elements[thing]) == "object") {
if(typeof(elements[thing]?.breakInto) == "undefined") {
elements[`${thing}_scrap`] = {
color: gravelizeToHex(elements[thing].color),
behavior: behaviors.POWDER,
tempHigh: elements[thing].tempHigh,
stateHigh: thing,
category: "powders",
hidden: true,
density: elements[thing].density * 0.09,
conduct: elements[thing].conduct * 0.4,
movable: true,
};
if(elements[thing].reactions) {
elements[`${thing}_scrap`].reactions = elements[thing].reactions;
};
elements[thing].breakInto = `${thing}_scrap`;
};
elements[thing].cutInto = elements[thing].breakInto
}
};
elements.acid.ignore.push("densinium_scrap")
elements.lithium_scrap.tick = function(pixel) {
tryTarnish(pixel,"lithium_oxide",0.021)
if(pixel.temp >= 178) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
};
};
elements.laetium_scrap.reactions.sand = { temp1: 7 }
});
//SOIL AND ROCKS, WORLDGEN PRESETS, AND MINERALS (the_ground.js and friends) ##
/*
TODO:
Soils
More sedimentary rocks
Metamorphic rocks
Ersatz pressure
Merge crimson?
Proper classification of limestone within these code comments
*/
//Variables
eLists.WHL = "water,salt_water,sugar_water,dirty_water,swamp_water,heavy_water,radioactive_water,crimwater,pure_water,chilly_water,honey,magma"
var vitreousFelsicName = "obsidian";
var vitreousInterfelsicName = "dacidian";
var vitreousIntermediateName = "diodian";
var vitreousMaficName = "basidian";
var vitreousUltramaficName = "komatidian";
var sandSimplification = ["gravel","granite_gravel","granodiorite_gravel","diorite_gravel","basalt_gravel","peridotite_gravel","rhyolite_gravel","dacite_gravel","andesite_gravel","komatiite_gravel","pumice_gravel","intermediate_pumice_gravel","scoria_gravel","mafic_scoria_gravel","ultramafic_scoria_gravel", "dacidian_shard", "andesidian_shard", "basalidian_shard", "komatidian_shard"];
var rocks = [ "granite", "granodiorite", "diorite", "rock", "peridotite", "rhyolite", "dacite", "andesite", "basalt", "komatiite", "pumice", "intermediate_pumice", "scoria", "mafic_scoria", "ultramafic_scoria", "obsidian", vitreousInterfelsicName, vitreousIntermediateName, vitreousMaficName, vitreousUltramaficName];
var gravels = [ "granite_gravel", "granodiorite_gravel", "diorite_gravel", "gravel", "peridotite_gravel", "rhyolite_gravel", "dacite_gravel", "andesite_gravel", "basalt_gravel", "komatiite_gravel", "pumice_gravel", "intermediate_pumice_gravel", "scoria_gravel", "mafic_scoria_gravel", "ultramafic_scoria_gravel", "obsidian_shard", "dacidian_shard", "andesidian_shard", "basalidian_shard", "komatidian_shard" ];
//Functions
//Stepped rainbow colors (used for rainbow earth)
function makeRegularRainbow(steps,s,l,outputFormat="rgb") {
var hslArray = [];
var divisionSize = 360 / steps;
for(i = 0; i < 360; i += divisionSize) {
hslArray.push({h: i, s: s, l: l});
};
return hslArray.map(x => convertHslObjects(x,outputFormat));
};
crimsonObject = {
grass: "crimson_grass",
ice: "red_ice",
water: "crimwater",
salt_water: "crimwater",
sugar_water: "crimwater",
dirty_water: "crimwater",
pool_water: "pool_water,pool_water,water",
snow: "crimsnow",
packed_snow: "crimsnow",
vine: "crimson_vine",
fish: "vicious_goldfish",
sapling: "shadewood_sapling",
sandy_water: "crimsandy_water",
muddy_water: "crimmuddy_water"
};
crimRate = 0.001
//Crimson spreaders
function grassSpread(pixel,dirt,grass,chance) {
pixel.dirtArray = [] //initialize dirt neighbor list
for (i = -2; i < 3; i++) { //iterate around
for (j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+i,pixel.y+j,true)) { //check for a pixel to see if it's dirt
if(Array.isArray(dirt)) {
if(dirt.includes(pixelMap[pixel.x+i][pixel.y+j].element)) { //see if it's dirt
if(!includesArray(pixel.dirtArray,[i,j])) { //avoid duplicate dirt entry
pixel.dirtArray.push([i,j]) //store dirt
}
}
} else {
if(pixelMap[pixel.x+i][pixel.y+j].element == dirt) { //see if it's dirt
if(!includesArray(pixel.dirtArray,[i,j])) { //avoid duplicate dirt entry
pixel.dirtArray.push([i,j]) //store dirt
}
}
}
}
}
}
for (k = 0; k < pixel.dirtArray.length; k++) { //iterate through dirt list
if(Math.random() < chance) { //random chance
if(isEmpty(pixel.x+pixel.dirtArray[k][0],pixel.y+pixel.dirtArray[k][1]-1)) { //check for empty space to grow grass
createPixel(grass,pixel.x+pixel.dirtArray[k][0],pixel.y+pixel.dirtArray[k][1]-1) //place grass above dirt
}
}
}
}
function crimSpread(pixel) {
for (let i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
if (!isEmpty(pixel.x+j,pixel.y+i,true)) {
var destPixel = pixelMap[pixel.x+j][pixel.y+i];
if(!destPixel) { continue };
var elementToCheck = destPixel.element;
if(Math.random() < crimRate) {
if(crimsonObject[elementToCheck]) {
var result = crimsonObject[elementToCheck];
if((typeof(result) == "string") && result.indexOf(",") !== -1 && !(elementExists(result))) {
result = result.split(",")
};
while(Array.isArray(result)) {
result = randomChoice(result)
};
if(result == "null") { //fsr null gets ignored
deletePixel(destPixel.x,destPixel.y);
} else {
changePixel(destPixel,result);
}
};
grassSpread(pixel,["dirt","crimsoil","rainbow_dirt"],"crimson_grass",0.5);
};
};
};
};
};
//Nellfire code (used for the obvious)
function doNellfire(pixel) {
var info = elements[pixel.element];
if((info.nellfireImmune && info.nellfireImmune !== "torch") && pixel.nellburn) {
delete pixel.nellburn;
delete pixel.nellburnStart;
return;
};
if (pixel.nellburn) { // Burning
if(!settings.burning) { return };
pixel.nellburnStart ??= pixelTicks;
var nellburnTempChange = info.nellburnTempChange ?? 1;
var fire = info.nellFireElement === undefined ? "nellfire" : info.nellFireElement; //allow null but disallow undefined
//console.log(info.nellFireElement,fire);
while(fire instanceof Array) {
fire = fire[Math.floor(Math.random()*fire.length)];
};
var nellFireTemp = info.nellFireSpawnTemp ?? pixel.temp;
var nellFireChance = info.nellFireSpawnChance ?? 20;
pixel.temp += nellburnTempChange ?? 4;
pixelTempCheck(pixel);
for (var i = 0; i < adjacentCoords.length; i++) { // Burn adjacent pixels
var x = pixel.x+adjacentCoords[i][0];
var y = pixel.y+adjacentCoords[i][1];
if (!isEmpty(x,y,true)) {
var newPixel = pixelMap[x][y];
var newInfo = elements[newPixel.element];
var spreadChance = newInfo.nellburn ?? 15
if (spreadChance && !newPixel.nellburn) {
if (Math.floor(Math.random()*100) < spreadChance) {
newPixel.nellburn = true;
newPixel.nellburnStart = pixelTicks;
}
}
}
}
if (info.nellfireImmune !== "torch" && (pixelTicks - pixel.nellburnStart > (info.nellburnTime || 150)) && Math.floor(Math.random()*100)<(info.nellburn || 25)) {
var burnInto = info.nellburnInto;
//console.log(burnInto);
if(burnInto === undefined) { burnInto = nellburnObject[pixel.element] };
//console.log(burnInto);
if(burnInto === undefined) { burnInto = [null,"nell_ash"] };
//console.log(burnInto);
while(burnInto instanceof Array) {
burnInto = burnInto[Math.floor(Math.random()*burnInto.length)];
};
//console.log(burnInto);
if(burnInto == null) { deletePixel(pixel.x,pixel.y); return } else { changePixel(pixel,burnInto,burnInto !== "smoke") };
if(!elements[burnInto].nellBurningWhenConverted) {
delete pixel.nellburn;
delete pixel.nellburnStart;
};
//console.log("ass");
pixel.temp = nellFireTemp;
if (info.nellFireColor != undefined && burnInto == "nellfire") {
pixel.color = pixelColorPick(pixel,info.nellFireColor);
}
else {
pixel.color = pixelColorPick(pixel)
}
}
else if (Math.floor(Math.random()*100) 1000000) {
//console.log('case 1');
coolingFactor = logistic
};
if(pixel.temp <= 1000000 && pixel.temp > 100000) {
//console.log('case 2');
//console.log("l",logistic);
coolingFactor = scale(pixel.temp,1000000,100000,logistic,0.99999);
//if(pixelAge % 10 == 0 || pixel.temp < 100500) { console.log(coolingFactor) };
};
if(pixel.temp < 100000) {
//console.log('case 3');
coolingFactor = 0.99999
};
//console.log(coolingFactor);
pixel.temp = ((pixel.temp - (settings.abszero ?? -273.15)) * coolingFactor) + (settings.abszero ?? -273.15);
for (var i = 0; i < adjacentCoords.length; i++) {
var x = pixel.x+adjacentCoords[i][0];
var y = pixel.y+adjacentCoords[i][1];
if (isEmpty(x,y)) {
if (Math.random() <= c) {
createPixel(Math.random() < 0.995 ? "light" : "neutron", x, y);
pixelMap[x][y].color = pixel.color;
};
} else if (!outOfBounds(x,y)) {
var newPixel = pixelMap[x][y];
//console.log(elements[newPixel.element].conduct);
if(ferromagneticMaterials.includes(newPixel.element) && (Math.random() < 0.1)) { newPixel.charge = 20 }; //no magnetism in sb
//console.log(whitelist,newPixel.element,whitelist.includes(newPixel.element));
if (pixel.temp!==newPixel.temp && whitelist.includes(newPixel.element)) {
var avg = (pixel.temp + newPixel.temp)/2;
pixel.temp = avg;
newPixel.temp = avg;
pixelTempCheck(pixel);
pixelTempCheck(newPixel);
}
}
}
};
function almostSun(pixel,lightScale=1,whitelist=["sun"]) {
starLightAndConduction(pixel,starColor(pixel) * lightScale,whitelist);
};
function nsTick(pixel,lightScale=1,whitelist=["sun"]) {
neutronStarLightAndConduction(pixel,starColor(pixel) * lightScale,whitelist);
};
elements.sun.tick = function(pixel) {
almostSun(pixel);
};
//"Generalized" sedimentation function
function sedimentation(pixel,finalRock,chance=0.0003) {
if(finalRock == undefined) { return false };
if(Math.random() < chance) {
var validNeighborArray = Array.apply(null, Array(adjacentCoords.length)).map(function() {return false});
//sedimentSandstoneTries++;
for(i = 0; i < adjacentCoords.length; i++) {
//sedimentSandstoneTryIterations++;
if(isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],false)) {
validNeighborArray[i] = false;
//sedimentSandstoneNoDetects++;
} else if(!isEmpty(pixel.x+adjacentCoords[i][0],pixel.y+adjacentCoords[i][1],true)) {
/*if(sedimentNeighborTable.includes(pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]].element)) {
validNeighborArray[i] = true;
//sedimentSandstoneDetects++;
} else {
validNeighborArray[i] = false;
//sedimentSandstoneNoDetects++;
};*/
//validNeighborArray[i] = sedimentNeighborTable.includes(pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]].element);
validNeighborArray[i] = (pixelMap[pixel.x+adjacentCoords[i][0]][pixel.y+adjacentCoords[i][1]].state ?? "solid") == "solid";
};
};
if(validNeighborArray.includes(true)) {
//sandstoneFormations++;
//console.log(finalRock);
changePixel(pixel,finalRock);
}/* else {
sandstoneFailures++;
}*/;
};
};
//Function for mass replacement according to an object
function transformAround(pixel,range,substitutionObject,reverse=false) {
var radius1 = (-1 * range);
var radius2 = (range + 1);
for (let i = radius1; i < radius2; i++) {
for (let j = radius1; j < radius2; j++) {
if(reverse) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
var destPixel = pixelMap[pixel.x+j][pixel.y+i];
var elementToCheck = destPixel.element;
if(getKeyByValue(substitutionObject,elementToCheck)) {
changePixel(destPixel,getKeyByValue(substitutionObject,elementToCheck));
};
};
} else {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
var destPixel = pixelMap[pixel.x+j][pixel.y+i];
var elementToCheck = destPixel.element;
if(substitutionObject[elementToCheck]) {
changePixel(destPixel,substitutionObject[elementToCheck]);
};
};
};
};
};
};
//Previous function with adjacentCoords
function transformAdjacent(pixel,substitutionObject,reverse=false) {
for(k = 0; k < adjacentCoords.length; k++) {
var i = adjacentCoords[k][0]
var j = adjacentCoords[k][1]
if(reverse) {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
var destPixel = pixelMap[pixel.x+j][pixel.y+i];
var elementToCheck = destPixel.element;
if(getKeyByValue(substitutionObject,elementToCheck)) {
changePixel(destPixel,getKeyByValue(substitutionObject,elementToCheck));
};
};
} else {
if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i)) {
var destPixel = pixelMap[pixel.x+j][pixel.y+i];
var elementToCheck = destPixel.element;
if(substitutionObject[elementToCheck]) {
changePixel(destPixel,substitutionObject[elementToCheck]);
};
};
};
};
};
//Cooling rate-varied magma solidification
function magmaRateBasedCooling(pixel,freezingPoint,vitriteName,vitriteThreshold,aphaniteName,aphaniteThreshold,phaneriteName) {
pixel.lastTemperatures ??= [];
pixel.lastTemperatures.push(pixel.temp); //due to how it's structured, last temp will always equal pixel.temp;
while(pixel.lastTemperatures.length > 2) {
pixel.lastTemperatures.shift();
};
if(pixel.lastTemperatures.length > 1) {
var overallTemperatureChangeRate = (pixel.temp - pixel.lastTemperatures[0]) / (pixel.lastTemperatures.length - 1);
//console.log(overallTemperatureChangeRate);
if(overallTemperatureChangeRate >= 0) {
return;
};
if(pixel.temp > freezingPoint) {
return;
};
//console.log(pixel.x,pixel.y,overallTemperatureChangeRate)
var stateLow;
if(overallTemperatureChangeRate < vitriteThreshold) { //numbers made up
//console.log("f99fd90");
stateLow = vitriteName;
} else if(overallTemperatureChangeRate < aphaniteThreshold) {
//console.log("aaaaaaaaaa");
stateLow = aphaniteName;
} else {
//console.log("03");
stateLow = phaneriteName;
};
var stateLowInfo = elements[stateLow];
var slHasHotRock = (stateLowInfo.stateLow == "hot_" + stateLow);
var changeToRockIsHot = false;
if(slHasHotRock) {
var hotRockPoint = stateLowInfo.tempHigh;
if(pixel.temp >= hotRockPoint) {
changeToRockIsHot = true;
};
};
changePixel(pixel,changeToRockIsHot ? "hot_" + stateLow : stateLow,false);
};
};
//Gravel finder
function getGravelElementName(rockName) {
if(rockName == "rock") {
return "gravel";
};
var gravelBasedName = rockName + "_gravel";
if(elements[gravelBasedName]) {
return gravelBasedName;
};
var shardBasedName = rockName + "_shard";
if(elements[shardBasedName]) {
return shardBasedName;
};
return false;
};
//Sand finder
function getSandElementName(sandName) {
var theName = sandName;
if(getGravelElementName(theName)) { //will fire if it was a rock with a valid gravel
theName = getGravelElementName(theName)
};
if(["komatiite","peridotite","komatiite_gravel","peridotite_gravel"].includes(theName)) {
return "olivine_sand";
};
if(theName == "gravel" || sandSimplification.includes(theName)) {
return "sand";
};
theName = theName.replace(/(gravel|shard)/,"sand");
if(elements[theName]) {
return theName;
};
return false;
};
/*Metamorphism test
function metamorphosisPressureHandler(rockBeingSquished,rockDoingSquishing) {
pixel.lastPressures ??= [];
while(pixel.lastPressures.length > 2) {
pixel.lastPressures.shift();
};
var squisherInfo = elements[rockDoingSquishing.element];
var squisheeInfo = elements[rockBeingSquished.element];
rockBeingSquished._squishers ??= {};
rockBeingSquished._squishers[pixelTicks] ??= {};
rockBeingSquished._squishers[pixelTicks][`x${rockDoingSquishing.x}y${rockDoingSquishing.y}`] = (squisherInfo.density ?? 2500) + (rockDoingSquishing._receivedPressure ?? 0);
rockBeingSquished._receivedPressure = sumNumericArray(Object.values(rockBeingSquished._squishers[pixelTicks]));
if(squisheeInfo.metamorphismFunction) {
squisheeInfo.metamorphismFunction(rockBeingSquished)
};
};
function removeLastSquishers(pixel) {
if(!pixel._squishers) {
return false;
};
if(pixel._squishers[pixelTicks - 1]) {
delete pixel._squishers[pixelTicks - 1];
};
};
elements.metal_scrap.onTryMoveInto = function(pixel,otherPixel) {
metamorphosisPressureHandler(pixel,otherPixel);
};
elements.metal_scrap.tick = function(pixel) {
removeLastSquishers(pixel);
};
elements.metal_scrap.metamorphismFunction = function(pixel) {
pixel.temp = pixel._receivedPressure;
};
elements.metal_scrap.insulate = true;
delete elements.metal_scrap.tempHigh;
delete elements.metal_scrap.stateHigh;
*/
/*Erosion
function toGravelErodeOtmi(pixel,otherPixel,erosionChanceDivisor=5500) {
var gravelName = getGravelElementName(pixel.element);
//console.log(gravelName);
if(!gravelName) { return false };
var otherState = elements[otherPixel.element].state ?? "solid";
if(otherState == "solid") {
return false;
};
//console.log(otherState);
var otherDensity = elements[otherPixel.element].density ?? otherState == "gas" ? 1.3 : 1000;
var erosionChance = ((otherState == "gas" ? otherDensity * 5 : otherDensity) ** 1/1.7) / erosionChanceDivisor;
if(Math.random() < erosionChance) {
changePixel(pixel,gravelName,false);
//changePixelReturn(pixel,gravelName,false).color = "rgb(255,0,0)";
};
};
function toSandErodeOtmi(pixel,otherPixel,erosionChanceDivisor=5500) {
var sandName = getSandElementName(pixel.element);
//console.log(sandName);
if(!sandName) { return false };
var otherState = elements[otherPixel.element].state ?? "solid";
if(otherState == "solid") {
return false;
};
var otherDensity = elements[otherPixel.element].density ?? otherState == "gas" ? 1.3 : 1000;
var erosionChance = ((otherState == "gas" ? otherDensity * 5 : otherDensity) ** 1/1.7) / erosionChanceDivisor;
if(Math.random() < erosionChance) {
changePixel(pixel,sandName,false);
//changePixelReturn(pixel,sandName,false).color = "rgb(255,255,0)";
};
};*/
//I really hate boilerplate
//Array maker
function twoPartRepeatedArray(value1,amount1,value2,amount2) {
var array1 = Array(amount1).fill(value1);
var array2 = Array(amount2).fill(value2);
return array1.concat(array2)
};
//Powder maker
function newPowder(name,color,density=null,tempHigh=null,stateHigh=null,breakInto=null,hardness=null,itsActuallySolidNotPowderLol=false) { //boilerplate my dick
if(tempHigh == null) {
stateHigh = null;
};
elements[name] = {
behavior: itsActuallySolidNotPowderLol ? behaviors.WALL : behaviors.POWDER,
color: color,
category: itsActuallySolidNotPowderLol ? "solids" : "powders",
state: "solid",
density: density ?? 1000,
};
if(tempHigh !== null) {
elements[name].tempHigh = tempHigh;
};
if(hardness !== null) {
elements[name].hardness = hardness;
};
if(tempHigh !== null && stateHigh !== null) {
elements[name].stateHigh = stateHigh;
};
if(breakInto !== null) {
elements[name].breakInto = breakInto;
};
return elements[name];
};
//Color gen
//Gravels
function gravelizeToHex(colorIn) {
var colorInput = colorIn; //side effects?
//console.log(`gravelizeToHex: ${colorInput}`)
//make sure in is array
if(!(colorInput instanceof Array)) {
colorInput = [colorInput];
};
//console.log(`gravelizeToHex: ${colorInput}`)
//console.log(colorInput);
//prepare final color
var finalColor = [];
//console.log(colorInput);
for(var i = 0; i < colorInput.length; i++) {
finalColor.push(colorInput[i]);
finalColor.push(colorInput[i]);
finalColor.push(colorInput[i]);
};
//vary lightness
for(i = 0; i < finalColor.length; i+=3) {
finalColor[i] = changeLightness(finalColor[i],1.25,"multiply","hsljson");
};
//leave offset-1 colors as-is
for(i = 2; i < finalColor.length; i+=3) {
finalColor[i] = changeLightness(finalColor[i],0.85,"multiply","hsljson");
};
//desaturate
for(i = 0; i < finalColor.length; i++) {
finalColor[i] = changeSaturation(finalColor[i],0.9,"multiply","hex");
};
//finish
//console.log(finalColor);
return finalColor;
};
//Sands
function sandizeToHex(rockColor,type="normal",sBringTo=31,sBringFactor=0.4,lBringTo=70,lBringFactor=0.6) {
if(elements[rockColor]) {
//Assuming an element was given, for compatibility
rockColor = elements[rockColor].color
};
if(!["normal","n","wet","w","packed","p"].includes(type.toLowerCase())) {
throw new Error("Type must be 'normal', 'wet', or 'packed'");
};
var sandColor = [];
//var sandColorObject = [];
if(!(rockColor instanceof Array)) {
rockColor = [rockColor];
};
for(i = 0; i < rockColor.length; i++) {
var colorAsHsl = normalizeColorToHslObject(rockColor[i]);
if(colorAsHsl.s > 0) { colorAsHsl.s = sBringTo + (-sBringFactor * (sBringTo - colorAsHsl.s)) }; //bring towards 31;
colorAsHsl.l = lBringTo + (-lBringFactor * (lBringTo - colorAsHsl.l)); //bring towards 70
switch(type.toLowerCase()) {
case "normal":
case "n":
break;
case "wet":
case "w":
if(colorAsHsl.s > 0) { colorAsHsl.s += 3 };
colorAsHsl.l -= 15;
break;
case "packed":
case "p":
colorAsHsl.s = Math.max(colorAsHsl.s - 11, 0);
colorAsHsl.l += 6;
break;
default:
break;
};
sandColor.push(convertHslObjects(colorAsHsl,"hex"));
//sandColorObject.push(convertHslObjects(colorAsHsl,"rgbjson"));
};
return sandColor;
};
function dustizeToHex(rockColor,sBringTo=25,sBringFactor=0.4,lBringTo=55,lBringFactor=0.6) {
if(elements[rockColor]) {
//Assuming an element was given, for compatibility
rockColor = elements[rockColor].color
};
//console.log(rockName);
var dustColor = [];
//var dustColorObject = [];
if(!(rockColor instanceof Array)) {
rockColor = [rockColor];
};
for(i = 0; i < rockColor.length; i++) {
var colorAsHsl = normalizeColorToHslObject(rockColor[i]);
if(colorAsHsl.s > 0) { colorAsHsl.s = sBringTo + (-sBringFactor * (sBringTo - colorAsHsl.s)) }; //bring towards 31;
colorAsHsl.l = lBringTo + (-lBringFactor * (lBringTo - colorAsHsl.l)); //bring towards 70
dustColor.push(convertHslObjects(colorAsHsl,"hex"));
//dustColorObject.push(convertHslObjects(colorAsHsl,"rgbjson"));
};
return dustColor;
};
//Sandstones
function sandstonizeToHex(sandName,type="normal") {
//console.log(sandName);
var sandInfo = elements[sandName];
if(!sandInfo) { throw new Error("No such element '" + sandName + "'") };
var finalColor = [];
//var sandColorObject = [];
var sandColor = sandInfo.color;
if(!(sandColor instanceof Array)) {
sandColor = [sandColor];
};
//console.log(sandColor);
for(var i = 0; i < sandColor.length; i++) {
//console.log(i,sandColor[i]);
var colorAsHsl = normalizeColorToHslObject(sandColor[i]);
//console.log(colorAsHsl);
if(colorAsHsl.s > 5 && colorAsHsl.h !== 0) { colorAsHsl.h -= 10 };
if(colorAsHsl.s > 5 && colorAsHsl.h !== 0) { colorAsHsl.s = 21 + (-0.8 * (21 - colorAsHsl.s)) }; //bring towards 21;
colorAsHsl.l = 58 + (-0.8 * (58 - colorAsHsl.l)); //bring towards 58
if(colorAsHsl.s > 5 && colorAsHsl.h !== 0) { colorAsHsl.s -= 4 };
colorAsHsl.l += 2;
//console.log(colorAsHsl);
finalColor.push(convertHslObjects(colorAsHsl,"hex"));
//sandColorObject.push(convertHslObjects(colorAsHsl,"rgbjson"));
};
return finalColor;
};
function sedimentHslOffset(hslJsonColor) {
return {h: hslJsonColor.h - 4, s: hslJsonColor.s - 20, l: hslJsonColor.l - 25};
};
//Magmas
function makeMoltenColor(colorIn) { //Edited vanilla code
//console.log(colorIn);
var newcolor = colorIn;
var moltenColorFactors = [ [2,1.25,0.5], [2,1,0.5], [2,0.75,0] ];
var colorList = [];
var colorObjectList = [];
// if newcolor is not an array, put it in an array
if (!(newcolor instanceof Array)) { newcolor = [newcolor]; }
newcolor = newcolor.map(x => convertColorFormats(x,"json"));
// for every color in the newcolor array, add a new color with the same value, but with the r and g values increased
for (var i = 0; i < newcolor.length; i++) {
var c = newcolor[i];
for (var j = 0; j < moltenColorFactors.length; j++) {
var newc = moltenColorFactors[j];
//console.log(c,newc);
r = Math.floor(c.r * newc[0]);
g = Math.floor(c.g * newc[1]);
b = Math.floor(c.b * newc[2]);
if (r > 255) {r = 255}; if (g > 255) {g = 255};
//edit: to hex
var rHex = r.toString(16); if(rHex.length == 1) { rHex = "0" + rHex };
var gHex = g.toString(16); if(gHex.length == 1) { gHex = "0" + gHex };
var bHex = b.toString(16); if(bHex.length == 1) { bHex = "0" + bHex };
colorList.push("#"+rHex+gHex+bHex);
}
}
return colorList;
}
//Magma vapors
function magmavaporizeToHex(colorIn) {
var color = colorIn;
if(!(color instanceof Array)) {
color = [color];
};
color = color.map(x => normalizeColorToHslObject(x));
for(i = 0; i < color.length; i++) {
color[i].h += 5;
color[i].s -= 5;
color[i].l += 20;
};
color = color.map(x => convertHslObjects(x,"hex"));
return color;
};
function magmacloudizeToHex(colorIn) {
var color = colorIn;
if(!(color instanceof Array)) {
color = [color];
};
color = color.map(x => normalizeColorToHslObject(x));
for(i = 0; i < color.length; i++) {
color[i].h += 5;
color[i].s -= 8;
color[i].l += 5;
};
color = color.map(x => convertHslObjects(x,"hex"));
return color;
};
function rockcloudizeToHex(colorIn) {
var color = colorIn;
if(!(color instanceof Array)) {
color = [color];
};
color = color.map(x => normalizeColorToHslObject(x));
for(i = 0; i < color.length; i++) {
color[i].h -= 12;
color[i].s *= 0.12;
color[i].l -= 6;
};
color = color.map(x => convertHslObjects(x,"hex"));
return color;
};
//Generate an entire composition family at once
function redHotColorgen(colorIn,outputFormat="rgb") {
var color = colorIn;
//console.log(color);
if(!Array.isArray(color)) {
color = [color];
};
//console.log(color);
color = color.map(x => convertColorFormats(x,"json"));
//console.log(color);
for(i = 0; i < color.length; i++) {
var subcolor = color[i];
//console.log(i);
subcolor.r += 48;
subcolor.r *= 1.7;
subcolor.g += 24;
subcolor.g *= 1.2;
subcolor.g -= 16;
subcolor.b -= 10;
subcolor.b *= 0.75;
for(colorlet in subcolor) {
subcolor[colorlet] = Math.round(rgbColorBound(subcolor[colorlet]));
};
//console.log(color);
};
//console.log(color);
color = color.map(x => convertColorFormats(x,outputFormat));
if(color.length == 1) { color = color[0] };
return color;
};
var sands = ["sand", "dirt", "crimsoil", "rainbow_dirt"]; //Some sources suggest the existence of topsoil sediment, so for the purposes of sedimentary rock generation, dirt is now a sand /hj
var wetSands = ["wet_sand", "mud"];
var sandSuspensions = [];
var sandSediments = ["radioactive_sand_sediment","clay_sediment"];
var sandstones = ["radioactive_sandstone","shale"];
var vaporizedMagmas = [];
var magmaClouds = [];
var rockClouds = [];
function nicffunc_getReactions(elemName) {
if(!(elements[elemName])) {
return null;
};
if(!(elements[elemName].reactions)) {
return null;
};
var reactions = elements[elemName].reactions;
if(structuredClone) {
return !!reactions ? structuredClone(reactions) : null;
} else {
return !!reactions ? JSON.parse(JSON.stringify(reactions)) : null;
};
};
function simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) {
if(pixel.exposedToAir) { return };
if(pixel.temp > 200 && Math.random () < 0.0001) {
changePixel(pixel,elements[pixel.element].metamorphite)
};
return
};
function newIgneousCompositionFamily(
compositionFamilyName,
magmaViscosity, magmaDensity, vitriteCoolingRateThreshold, aphaniteCoolingRateThreshold, magmaBoilingPoint,
phaneriteName, phaneriteColor, phaneriteMeltingPoint, phaneriteDensity,
metaphaneriteName, metaphaneriteColor, metaphaneriteMeltingPoint, metaphaneriteDensity,
aphaniteName, aphaniteColor, aphaniteMeltingPoint, aphaniteDensity,
metaaphaniteName, metaaphaniteColor, metaaphaniteMeltingPoint, metaaphaniteDensity,
vesiculiteName, vesiculiteColor, vesiculiteMeltingPoint, vesiculiteDensity,
metavesiculiteName, metavesiculiteColor, metavesiculiteMeltingPoint, metavesiculiteDensity,
vitriteName, vitriteColor, vitriteMeltingPoint, vitriteDensity,
metavitriteName, metavitriteColor, metavitriteMeltingPoint, metavitriteDensity,
sandFormationReactionRegularSandCount, sandFormationReactionSpecificSandCount,
) {
//console.log(compositionFamilyName,vesiculiteMeltingPoint,vitriteMeltingPoint);
//Auto names
//Sand
//gabbro_sand instead of rock_sand for rock's unique sand
var phaneriteSandName = compositionFamilyName == "mafic" ? "gabbro_sand" : phaneriteName + "_sand";
var aphaniteSandName = aphaniteName + "_sand";
var vesiculiteSandName = vesiculiteName + "_sand";
var vitriteSandName = vitriteName + "_sand";
var metaphaneriteSandName = metaphaneriteName + "_sand";
var metaaphaniteSandName = metaaphaniteName + "_sand";
var metavesiculiteSandName = metavesiculiteName + "_sand";
var metavitriteSandName = metavitriteName + "_sand";
//Solid rocks (rock walls)
//keep rock_wall to replace vanilla rock wall
var phaneriteWallName = compositionFamilyName == "mafic" ? "rock_wall" : phaneriteName + "_wall";
var aphaniteWallName = aphaniteName + "_wall";
var vesiculiteWallName = vesiculiteName + "_wall";
var vitriteWallName = vitriteName + "_wall";
var metaphaneriteWallName = metaphaneriteName + "_wall";
var metaaphaniteWallName = metaaphaniteName + "_wall";
var metavesiculiteWallName = metavesiculiteName + "_wall";
var metavitriteWallName = metavitriteName + "_wall";
//Gravel
//gravel instead of rock_gravel for normal gravel (as rock's unique gravel)
var phaneriteGravelName = compositionFamilyName == "mafic" ? "gravel" : phaneriteName + "_gravel";
var aphaniteGravelName = aphaniteName + "_gravel";
var vesiculiteGravelName = vesiculiteName + "_gravel";
var vitriteGravelName = vitriteName + "_shard";
var metaphaneriteGravelName = metaphaneriteName + "_gravel";
var metaaphaniteGravelName = metaaphaniteName + "_gravel";
var metavesiculiteGravelName = metavesiculiteName + "_gravel";
var metavitriteGravelName = metavitriteName + "_shard";
//Dust
//gabbro_dust instead of rock_dust for rock's unique dust
var phaneriteDustName = compositionFamilyName == "mafic" ? "gabbro_dust" : phaneriteName + "_dust";
var aphaniteDustName = aphaniteName + "_dust";
var vesiculiteDustName = vesiculiteName + "_dust";
var vitriteDustName = vitriteName + "_dust";
var metaphaneriteDustName = metaphaneriteName + "_dust";
var metaaphaniteDustName = metaaphaniteName + "_dust";
var metavesiculiteDustName = metavesiculiteName + "_dust";
var metavitriteDustName = metavitriteName + "_dust";
//Push future sand names and wet sand names to sand list for sandstone system generation
sands.push(phaneriteSandName);
sands.push(aphaniteSandName);
sands.push(vesiculiteSandName);
sands.push(vitriteSandName);
sands.push(metaphaneriteSandName);
sands.push(metaaphaniteSandName);
sands.push(metavesiculiteSandName);
sands.push(metavitriteSandName);
wetSands.push("wet_" + phaneriteSandName);
wetSands.push("wet_" + aphaniteSandName);
wetSands.push("wet_" + vesiculiteSandName);
wetSands.push("wet_" + vitriteSandName);
wetSands.push("wet_" + metaphaneriteSandName);
wetSands.push("wet_" + metaaphaniteSandName);
wetSands.push("wet_" + metavesiculiteSandName);
wetSands.push("wet_" + metavitriteSandName);
//Magma and magma derivative names
var magmaName = compositionFamilyName == "mafic" ? "magma" : compositionFamilyName + "_magma";
var magmaCloudName = magmaName + "_cloud"
var rockCloudName = compositionFamilyName + "_rock_cloud"
//Create rocks, transplant existing reactions if they exist, add/change erosion reactions to match, and create corresponding physical variants
//Phanerite
var phaneriteOldReactions = nicffunc_getReactions(phaneriteName);
elements[phaneriteName] = {
color: phaneriteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: phaneriteMeltingPoint,
stateHigh: magmaName,
density: phaneriteDensity,
hardness: 0.75,
breakInto: phaneriteGravelName,
_data: [compositionFamilyName,"phanerite","igneous_rock"],
metamorphite: metaphaneriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
if(phaneriteOldReactions) {
elements[phaneriteName].reactions = phaneriteOldReactions;
};
//replace water rock-erosion reaction
elements.water.reactions[phaneriteName] = { "elem2": phaneriteGravelName, "chance": 0.00035 }
//create unique gravel
elements[phaneriteGravelName] = {
color: gravelizeToHex(phaneriteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: phaneriteMeltingPoint,
stateHigh: magmaName,
breakInto: phaneriteDustName,
density: phaneriteDensity * 0.55,
_data: [compositionFamilyName,"phanerite","igneous_gravel"],
metamorphite: metaphaneriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements[phaneriteDustName] = {
color: dustizeToHex(phaneriteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: phaneriteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[phaneriteDustName]: {elem1: phaneriteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (phaneriteDensity / 1000), //unmeasured value
_data: [compositionFamilyName,"phanerite","dust"],
};
//generate water gravel-erosion reaction using rock family's sand ratio
elements.water.reactions[phaneriteGravelName] = { "elem2": twoPartRepeatedArray(phaneriteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
//generate unique solid version
elements[phaneriteWallName] = {
color: phaneriteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: phaneriteMeltingPoint,
stateHigh: magmaName,
density: phaneriteDensity,
hardness: 0.8,
breakInto: phaneriteName,
_data: [compositionFamilyName,"phanerite","solid_igneous_rock"],
metamorphite: metaphaneriteWallName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[phaneriteWallName] = { "elem2": phaneriteName, "chance": 0.00035 }
//Sand and sand variants
elements[phaneriteSandName] = {
color: sandizeToHex(phaneriteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: phaneriteMeltingPoint,
stateHigh: vitriteName,
density: phaneriteDensity * 0.595,
_data: [compositionFamilyName,"phanerite","particulate"],
metamorphite: metaphaneriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
//console.log(phaneriteSandName, elements[phaneriteSandName].color);
elements["wet_" + phaneriteSandName] = {
color: sandizeToHex(phaneriteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + phaneriteSandName,
tempLow: -50,
stateLow:"packed_" + phaneriteSandName,
density: phaneriteDensity * 0.595 + 150,
_data: [compositionFamilyName,"phanerite","wet_particulate"],
metamorphite: metaphaneriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["packed_" + phaneriteSandName] = {
color: sandizeToHex(phaneriteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: phaneriteMeltingPoint,
stateHigh: vitriteName,
density: phaneriteDensity * 0.59,
breakInto: phaneriteSandName,
_data: [compositionFamilyName,"phanerite","packed_particulate"],
metamorphite: metaphaneriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[phaneriteSandName] = {
"elem1": null, "elem2": "wet_" + phaneriteSandName,
};
//Metaphanerite
var metaphaneriteOldReactions = nicffunc_getReactions(phaneriteName);
elements[metaphaneriteName] = {
color: metaphaneriteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: metaphaneriteMeltingPoint,
stateHigh: magmaName,
density: metaphaneriteDensity,
hardness: 0.75,
breakInto: metaphaneriteGravelName,
_data: [compositionFamilyName,"metaphanerite","metamorphic_rock"],
};
if(metaphaneriteOldReactions) {
elements[metaphaneriteName].reactions = metaphaneriteOldReactions;
};
//replace water rock-erosion reaction
elements.water.reactions[metaphaneriteName] = { "elem2": metaphaneriteGravelName, "chance": 0.00035 }
//create unique gravel
elements[metaphaneriteGravelName] = {
color: gravelizeToHex(metaphaneriteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: metaphaneriteMeltingPoint,
stateHigh: magmaName,
breakInto: metaphaneriteDustName,
density: metaphaneriteDensity * 0.55,
_data: [compositionFamilyName,"metaphanerite","metamorphic_gravel"],
};
elements[metaphaneriteDustName] = {
color: dustizeToHex(metaphaneriteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: metaphaneriteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[metaphaneriteDustName]: {elem1: metaphaneriteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (metaphaneriteDensity / 1000), //unmeasured value
_data: [compositionFamilyName,"metaphanerite","dust"],
};
//generate water gravel-erosion reaction using rock family's sand ratio
elements.water.reactions[metaphaneriteGravelName] = { "elem2": twoPartRepeatedArray(metaphaneriteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
//generate unique solid version
elements[metaphaneriteWallName] = {
color: metaphaneriteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: metaphaneriteMeltingPoint,
stateHigh: magmaName,
density: metaphaneriteDensity,
hardness: 0.8,
breakInto: metaphaneriteName,
_data: [compositionFamilyName,"metaphanerite","solid_metamorphic_rock"],
};
elements.water.reactions[metaphaneriteWallName] = { "elem2": metaphaneriteName, "chance": 0.00035 }
//Sand and sand variants
elements[metaphaneriteSandName] = {
color: sandizeToHex(metaphaneriteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: metaphaneriteMeltingPoint,
stateHigh: vitriteName,
density: metaphaneriteDensity * 0.595,
_data: [compositionFamilyName,"metaphanerite","particulate"],
};
//console.log(metaphaneriteSandName, elements[metaphaneriteSandName].color);
elements["wet_" + metaphaneriteSandName] = {
color: sandizeToHex(metaphaneriteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + metaphaneriteSandName,
tempLow: -50,
stateLow:"packed_" + metaphaneriteSandName,
density: metaphaneriteDensity * 0.595 + 150,
_data: [compositionFamilyName,"metaphanerite","wet_particulate"],
};
elements["packed_" + metaphaneriteSandName] = {
color: sandizeToHex(metaphaneriteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: metaphaneriteMeltingPoint,
stateHigh: vitriteName,
density: metaphaneriteDensity * 0.59,
breakInto: metaphaneriteSandName,
_data: [compositionFamilyName,"metaphanerite","packed_particulate"],
};
elements.water.reactions[metaphaneriteSandName] = {
"elem1": null, "elem2": "wet_" + metaphaneriteSandName,
};
//Aphanite
var aphaniteOldReactions = nicffunc_getReactions(aphaniteName);
elements[aphaniteName] = {
color: aphaniteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: aphaniteMeltingPoint,
stateHigh: magmaName,
density: aphaniteDensity,
hardness: 0.75,
breakInto: aphaniteGravelName,
_data: [compositionFamilyName,"aphanite","igneous_rock"],
metamorphite: metaaphaniteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
if(aphaniteOldReactions) {
elements[aphaniteName].reactions = aphaniteOldReactions;
};
elements.water.reactions[aphaniteName] = { "elem2": aphaniteGravelName, "chance": 0.00035 }
elements[aphaniteGravelName] = {
color: gravelizeToHex(aphaniteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: aphaniteMeltingPoint,
stateHigh: magmaName,
breakInto: aphaniteDustName,
density: aphaniteDensity * 0.55,
_data: [compositionFamilyName,"aphanite","igneous_gravel"],
metamorphite: metaaphaniteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements[aphaniteDustName] = {
color: dustizeToHex(aphaniteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: aphaniteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[aphaniteDustName]: {elem1: aphaniteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (aphaniteDensity / 1000), //unmeasured value
_data: [compositionFamilyName,"aphanite","dust"],
};
elements.water.reactions[aphaniteGravelName] = { "elem2": twoPartRepeatedArray(aphaniteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
elements[aphaniteWallName] = {
color: aphaniteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: aphaniteMeltingPoint,
stateHigh: magmaName,
density: aphaniteDensity,
hardness: 0.8,
breakInto: aphaniteName,
_data: [compositionFamilyName,"aphanite","solid_igneous_rock"],
metamorphite: metaaphaniteWallName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[aphaniteWallName] = { "elem2": aphaniteName, "chance": 0.00035 }
//Sand and sand variants
elements[aphaniteSandName] = {
color: sandizeToHex(aphaniteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: aphaniteMeltingPoint,
stateHigh: vitriteName,
density: aphaniteDensity * 0.595,
_data: [compositionFamilyName,"aphanite","particulate"],
metamorphite: metaaphaniteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["wet_" + aphaniteSandName] = {
color: sandizeToHex(aphaniteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + aphaniteSandName,
tempLow: -50,
stateLow:"packed_" + aphaniteSandName,
density: aphaniteDensity * 0.595 + 150,
_data: [compositionFamilyName,"aphanite","wet_particulate"],
metamorphite: metaaphaniteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["packed_" + aphaniteSandName] = {
color: sandizeToHex(aphaniteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: aphaniteMeltingPoint,
stateHigh: vitriteName,
density: aphaniteDensity * 0.59,
breakInto: aphaniteSandName,
_data: [compositionFamilyName,"aphanite","packed_particulate"],
metamorphite: metaaphaniteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[aphaniteSandName] = {
"elem1": null, "elem2": "wet_" + aphaniteSandName,
};
//Metaaphanite
var metaaphaniteOldReactions = nicffunc_getReactions(phaneriteName);
elements[metaaphaniteName] = {
color: metaaphaniteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: metaaphaniteMeltingPoint,
stateHigh: magmaName,
density: metaaphaniteDensity,
hardness: 0.75,
breakInto: metaaphaniteGravelName,
_data: [compositionFamilyName,"metaaphanite","metamorphic_rock"],
};
if(metaaphaniteOldReactions) {
elements[metaaphaniteName].reactions = metaaphaniteOldReactions;
};
//replace water rock-erosion reaction
elements.water.reactions[metaaphaniteName] = { "elem2": metaaphaniteGravelName, "chance": 0.00035 }
//create unique gravel
elements[metaaphaniteGravelName] = {
color: gravelizeToHex(metaaphaniteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: metaaphaniteMeltingPoint,
stateHigh: magmaName,
breakInto: metaaphaniteDustName,
density: metaaphaniteDensity * 0.55,
_data: [compositionFamilyName,"metaaphanite","metamorphic_gravel"],
};
elements[metaaphaniteDustName] = {
color: dustizeToHex(metaaphaniteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: metaaphaniteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[metaaphaniteDustName]: {elem1: metaaphaniteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (metaaphaniteDensity / 1000), //unmeasured value
_data: [compositionFamilyName,"metaaphanite","dust"],
};
//generate water gravel-erosion reaction using rock family's sand ratio
elements.water.reactions[metaaphaniteGravelName] = { "elem2": twoPartRepeatedArray(metaaphaniteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
//generate unique solid version
elements[metaaphaniteWallName] = {
color: metaaphaniteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: metaaphaniteMeltingPoint,
stateHigh: magmaName,
density: metaaphaniteDensity,
hardness: 0.8,
breakInto: metaaphaniteName,
_data: [compositionFamilyName,"metaaphanite","solid_metamorphic_rock"],
};
elements.water.reactions[metaaphaniteWallName] = { "elem2": metaaphaniteName, "chance": 0.00035 }
//Sand and sand variants
elements[metaaphaniteSandName] = {
color: sandizeToHex(metaaphaniteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: metaaphaniteMeltingPoint,
stateHigh: vitriteName,
density: metaaphaniteDensity * 0.595,
_data: [compositionFamilyName,"metaaphanite","particulate"],
};
//console.log(metaaphaniteSandName, elements[metaaphaniteSandName].color);
elements["wet_" + metaaphaniteSandName] = {
color: sandizeToHex(metaaphaniteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + metaaphaniteSandName,
tempLow: -50,
stateLow:"packed_" + metaaphaniteSandName,
density: metaaphaniteDensity * 0.595 + 150,
_data: [compositionFamilyName,"metaaphanite","wet_particulate"],
};
elements["packed_" + metaaphaniteSandName] = {
color: sandizeToHex(metaaphaniteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: metaaphaniteMeltingPoint,
stateHigh: vitriteName,
density: metaaphaniteDensity * 0.59,
breakInto: metaaphaniteSandName,
_data: [compositionFamilyName,"metaaphanite","packed_particulate"],
};
elements.water.reactions[metaaphaniteSandName] = {
"elem1": null, "elem2": "wet_" + metaaphaniteSandName,
};
//Vesiculite
elements[vesiculiteName] = {
color: vesiculiteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: vesiculiteMeltingPoint,
stateHigh: magmaName,
density: vesiculiteDensity,
hardness: 0.75,
breakInto: vesiculiteGravelName,
_data: [compositionFamilyName,"vesiculite","igneous_rock"],
grain: 3,
metamorphite: metavesiculiteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[vesiculiteName] = { "elem2": vesiculiteGravelName, "chance": 0.00035 }
elements[vesiculiteGravelName] = {
color: gravelizeToHex(vesiculiteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: vesiculiteMeltingPoint,
stateHigh: magmaName,
breakInto: vesiculiteDustName,
density: vesiculiteDensity * 3.2,
_data: [compositionFamilyName,"vesiculite","igneous_gravel"],
grain: 3,
metamorphite: metavesiculiteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements[vesiculiteDustName] = {
color: dustizeToHex(vesiculiteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: vesiculiteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[vesiculiteDustName]: {elem1: vesiculiteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (vesiculiteDensity / 800), //unmeasured value
_data: [compositionFamilyName,"vesiculite","dust"],
};
elements.water.reactions[vesiculiteGravelName] = { "elem2": twoPartRepeatedArray(vesiculiteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
elements[vesiculiteWallName] = {
color: vesiculiteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: vesiculiteMeltingPoint,
stateHigh: magmaName,
density: vesiculiteDensity,
hardness: 0.8,
breakInto: vesiculiteName,
_data: [compositionFamilyName,"vesiculite","solid_igneous_rock"],
grain: 3,
metamorphite: metavesiculiteWallName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[vesiculiteWallName] = { "elem2": vesiculiteName, "chance": 0.00035 }
//Sand and sand variants
elements[vesiculiteSandName] = {
color: sandizeToHex(vesiculiteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: vesiculiteMeltingPoint,
stateHigh: vitriteName,
density: vesiculiteDensity * 1.9,
_data: [compositionFamilyName,"vesiculite","particulate"],
metamorphite: metavesiculiteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["wet_" + vesiculiteSandName] = {
color: sandizeToHex(vesiculiteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + vesiculiteSandName,
tempLow: -50,
stateLow:"packed_" + vesiculiteSandName,
density: vesiculiteDensity * 1.9 + 150,
_data: [compositionFamilyName,"vesiculite","wet_particulate"],
metamorphite: metavesiculiteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["packed_" + vesiculiteSandName] = {
color: sandizeToHex(vesiculiteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: vesiculiteMeltingPoint,
stateHigh: vitriteName,
density: vesiculiteDensity * 1.888,
breakInto: vesiculiteSandName,
_data: [compositionFamilyName,"vesiculite","packed_particulate"],
metamorphite: metavesiculiteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[vesiculiteSandName] = {
"elem1": null, "elem2": "wet_" + vesiculiteSandName,
};
//Metavesiculite
elements[metavesiculiteName] = {
color: metavesiculiteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: metavesiculiteMeltingPoint,
stateHigh: magmaName,
density: metavesiculiteDensity,
hardness: 0.75,
breakInto: metavesiculiteGravelName,
_data: [compositionFamilyName,"metavesiculite","igneous_rock"],
grain: 2.5
};
elements.water.reactions[metavesiculiteName] = { "elem2": metavesiculiteGravelName, "chance": 0.00035 }
elements[metavesiculiteGravelName] = {
color: gravelizeToHex(metavesiculiteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: metavesiculiteMeltingPoint,
stateHigh: magmaName,
breakInto: metavesiculiteDustName,
density: metavesiculiteDensity * 3.2,
_data: [compositionFamilyName,"metavesiculite","metamorphic_gravel"],
grain: 2.5
};
elements[metavesiculiteDustName] = {
color: dustizeToHex(metavesiculiteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: metavesiculiteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[metavesiculiteDustName]: {elem1: metavesiculiteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (metavesiculiteDensity / 800), //unmeasured value
_data: [compositionFamilyName,"metavesiculite","dust"],
};
elements.water.reactions[metavesiculiteGravelName] = { "elem2": twoPartRepeatedArray(metavesiculiteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
elements[metavesiculiteWallName] = {
color: metavesiculiteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: metavesiculiteMeltingPoint,
stateHigh: magmaName,
density: metavesiculiteDensity,
hardness: 0.8,
breakInto: metavesiculiteName,
_data: [compositionFamilyName,"metavesiculite","solid_metamorphic_rock"],
grain: 2.5
};
elements.water.reactions[metavesiculiteWallName] = { "elem2": metavesiculiteName, "chance": 0.00035 }
//Sand and sand variants
elements[metavesiculiteSandName] = {
color: sandizeToHex(metavesiculiteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: metavesiculiteMeltingPoint,
stateHigh: vitriteName,
density: metavesiculiteDensity * 1.9,
_data: [compositionFamilyName,"metavesiculite","particulate"],
};
elements["wet_" + metavesiculiteSandName] = {
color: sandizeToHex(metavesiculiteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + metavesiculiteSandName,
tempLow: -50,
stateLow:"packed_" + metavesiculiteSandName,
density: metavesiculiteDensity * 1.9 + 150,
_data: [compositionFamilyName,"metavesiculite","wet_particulate"],
};
elements["packed_" + metavesiculiteSandName] = {
color: sandizeToHex(metavesiculiteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: metavesiculiteMeltingPoint,
stateHigh: vitriteName,
density: metavesiculiteDensity * 1.888,
breakInto: metavesiculiteSandName,
_data: [compositionFamilyName,"metavesiculite","packed_particulate"],
};
elements.water.reactions[metavesiculiteSandName] = {
"elem1": null, "elem2": "wet_" + metavesiculiteSandName,
};
//Vitrite
elements[vitriteName] = {
color: vitriteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: vitriteMeltingPoint,
stateHigh: magmaName,
density: vitriteDensity,
hardness: 0.75,
breakInto: vitriteGravelName,
_data: [compositionFamilyName,"vitrite","igneous_rock"],
metamorphite: metavitriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[vitriteName] = { "elem2": vitriteGravelName, "chance": 0.00035 }
elements[vitriteGravelName] = {
color: gravelizeToHex(vitriteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: vitriteMeltingPoint,
stateHigh: magmaName,
breakInto: vitriteDustName,
density: vitriteDensity * 0.55,
_data: [compositionFamilyName,"vitrite","glass_shard"],
metamorphite: metavitriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements[vitriteDustName] = {
color: dustizeToHex(vitriteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: vitriteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[vitriteDustName]: {elem1: vitriteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (vitriteDensity / 1000), //unmeasured value
_data: [compositionFamilyName,"vitrite","dust"],
};
elements.water.reactions[vitriteGravelName] = { "elem2": twoPartRepeatedArray(vitriteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
elements[vitriteWallName] = {
color: vitriteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: vitriteMeltingPoint,
stateHigh: magmaName,
density: vitriteDensity,
hardness: 0.8,
breakInto: vitriteName,
_data: [compositionFamilyName,"vitrite","solid_igneous_rock"],
metamorphite: metavitriteWallName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[vitriteWallName] = { "elem2": vitriteName, "chance": 0.00035 }
//Sand and sand variants
elements[vitriteSandName] = {
color: sandizeToHex(vitriteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: vitriteMeltingPoint,
stateHigh: vitriteName,
density: vitriteDensity * 0.595,
_data: [compositionFamilyName,"vitrite","particulate"],
metamorphite: metavitriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["wet_" + vitriteSandName] = {
color: sandizeToHex(vitriteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + vitriteSandName,
tempLow: -50,
stateLow:"packed_" + vitriteSandName,
density: vitriteDensity * 0.595 + 150,
_data: [compositionFamilyName,"vitrite","wet_particulate"],
metamorphite: metavitriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements["packed_" + vitriteSandName] = {
color: sandizeToHex(vitriteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: vitriteMeltingPoint,
stateHigh: vitriteName,
density: vitriteDensity * 0.59,
breakInto: vitriteSandName,
_data: [compositionFamilyName,"vitrite","packed_particulate"],
metamorphite: metavitriteName,
onTryMoveInto: function(pixel,otherPixel) { simplifiedSingleMetamorphiteMetamorphismOTMI(pixel,otherPixel) }
};
elements.water.reactions[vitriteSandName] = {
"elem1": null, "elem2": "wet_" + vitriteSandName,
};
//Metavitrite
elements[metavitriteName] = {
color: metavitriteColor,
behavior: behaviors.POWDER,
category: "rock",
state: "solid",
tempHigh: metavitriteMeltingPoint,
stateHigh: magmaName,
density: metavitriteDensity,
hardness: 0.75,
breakInto: metavitriteGravelName,
_data: [compositionFamilyName,"metavitrite","metamorphic_rock"],
};
elements.water.reactions[metavitriteName] = { "elem2": metavitriteGravelName, "chance": 0.00035 }
elements[metavitriteGravelName] = {
color: gravelizeToHex(metavitriteColor),
behavior: behaviors.POWDER,
category: "gravel",
state: "solid",
tempHigh: metavitriteMeltingPoint,
stateHigh: magmaName,
breakInto: metavitriteDustName,
density: metavitriteDensity * 0.55,
_data: [compositionFamilyName,"metavitrite","glass_shard"],
};
elements[metavitriteDustName] = {
color: dustizeToHex(metavitriteName),
behavior: behaviors.GAS,
category: "rock dust",
state: "gas",
tempHigh: metavitriteMeltingPoint,
stateHigh: ["fire",magmaName],
reactions: {
[metavitriteDustName]: {elem1: metavitriteSandName, elem2: null, chance: 0.003},
},
density: airDensity + (metavitriteDensity / 1000), //unmeasured value
_data: [compositionFamilyName,"metavitrite","dust"],
};
elements.water.reactions[metavitriteGravelName] = { "elem2": twoPartRepeatedArray(metavitriteSandName,sandFormationReactionSpecificSandCount,"sand",sandFormationReactionRegularSandCount), "chance": 0.0005 };
elements[metavitriteWallName] = {
color: metavitriteColor,
behavior: behaviors.WALL,
category: "solid rock",
state: "solid",
tempHigh: metavitriteMeltingPoint,
stateHigh: magmaName,
density: metavitriteDensity,
hardness: 0.8,
breakInto: metavitriteName,
_data: [compositionFamilyName,"metavitrite","solid_metamorphic_rock"],
};
elements.water.reactions[metavitriteWallName] = { "elem2": metavitriteName, "chance": 0.00035 }
//Sand and sand variants
elements[metavitriteSandName] = {
color: sandizeToHex(metavitriteName,"normal"),
behavior: behaviors.POWDER,
category: "sand",
state: "solid",
tempHigh: metavitriteMeltingPoint,
stateHigh: metavitriteName,
density: metavitriteDensity * 0.595,
_data: [compositionFamilyName,"metavitrite","particulate"],
};
elements["wet_" + metavitriteSandName] = {
color: sandizeToHex(metavitriteName,"wet"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_" + metavitriteSandName,
tempLow: -50,
stateLow:"packed_" + metavitriteSandName,
density: metavitriteDensity * 0.595 + 150,
_data: [compositionFamilyName,"metavitrite","wet_particulate"],
};
elements["packed_" + metavitriteSandName] = {
color: sandizeToHex(metavitriteName,"packed"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: metavitriteMeltingPoint,
stateHigh: metavitriteName,
density: metavitriteDensity * 0.59,
breakInto: metavitriteSandName,
_data: [compositionFamilyName,"metavitrite","packed_particulate"],
};
elements.water.reactions[metavitriteSandName] = {
"elem1": null, "elem2": "wet_" + metavitriteSandName,
};
//Magma
var magmaOldReactions = nicffunc_getReactions(magmaName);
var magmaOldColor = elements.magma.color;
elements[magmaName] = {
reactions: {
"ash": { "elem1": "molten_slag", "elem2": null },
"dust": { "elem1": "molten_slag", "elem2": null },
},
_magmaCoolingPassToElement: {
vitreous: [vitriteCoolingRateThreshold,vitriteName],
aphanitic: [aphaniteCoolingRateThreshold,aphaniteName],
phaneritic: [Infinity,phaneriteName],
meltingPoints: {
vitreous: vitriteMeltingPoint,
vesicular: vesiculiteMeltingPoint,
aphanitic: aphaniteMeltingPoint,
phaneritic: phaneriteMeltingPoint,
},
},
tick: function(pixel) {
var coolingInfo = elements[pixel.element]._magmaCoolingPassToElement;
magmaRateBasedCooling(
pixel,
Math.min(
coolingInfo.meltingPoints.vitreous,
coolingInfo.meltingPoints.vesicular,
coolingInfo.meltingPoints.aphanitic,
coolingInfo.meltingPoints.phaneritic
) - 20,
coolingInfo.vitreous[1],
coolingInfo.vitreous[0],
coolingInfo.aphanitic[1],
coolingInfo.aphanitic[0],
coolingInfo.phaneritic[1]
);
},
"color": makeMoltenColor(phaneriteColor),
"behavior": behaviors.MOLTEN,
"temp": Math.max(phaneriteMeltingPoint,metaphaneriteMeltingPoint,aphaniteMeltingPoint,metaaphaniteMeltingPoint,vesiculiteMeltingPoint,metavesiculiteMeltingPoint,vitriteMeltingPoint,metavitriteMeltingPoint) + 100,
"tempLow": -Infinity, //cosmetic info
"stateLow": [aphaniteName,phaneriteName,vitriteName],
"tempHigh": magmaBoilingPoint,
"stateHigh": "vaporized_" + magmaName,
"viscosity": magmaViscosity,
"hidden": true,
"state": "liquid",
"category": "magmas",
"density": magmaDensity,
"_data": [compositionFamilyName,"magma","liquid"],
};
if(magmaOldReactions) {
elements[magmaName].reactions = magmaOldReactions;
};
if(magmaName == "magma") {
elements.magma.color = magmaOldColor;
};
elements[magmaName].reactions.foam = { "elem1": vesiculiteName, "elem2": vesiculiteName };
elements["vaporized_" + magmaName] = {
color: magmavaporizeToHex(elements[magmaName].color),
behavior: behaviors.GAS,
reactions: {
["vaporized_" + magmaName]: { elem1: null, elem2: magmaCloudName, chance:0.3, "y":[0,15], "setting":"clouds" }
},
density: magmaDensity * 0.0028,
temp: magmaBoilingPoint + 100,
tempLow: magmaBoilingPoint,
stateLow: magmaName,
category: "magma vapor",
state: "gas",
hidden: true,
_data: [compositionFamilyName,"magma","vaporized"],
};
vaporizedMagmas.push("vaporized_" + magmaName);
elements[magmaCloudName] = {
color: magmacloudizeToHex(elements[magmaName].color),
behavior: [
"XX|XX|XX",
"M1%7|CH:" + magmaName + "%0.05|M1%7",
"XX|XX|XX",
],
density: magmaDensity * 0.0021,
temp: magmaBoilingPoint + 100,
tempLow: Math.min(phaneriteMeltingPoint,metaphaneriteMeltingPoint,aphaniteMeltingPoint,metaaphaniteMeltingPoint,vesiculiteMeltingPoint,metavesiculiteMeltingPoint,vitriteMeltingPoint,metavitriteMeltingPoint) - 50,
stateLow: rockCloudName,
category: "magma cloud",
state: "gas",
_data: [compositionFamilyName,"magma","cloud"],
};
magmaClouds.push(magmaName + "_cloud");
elements[rockCloudName] = {
color: rockcloudizeToHex(elements[magmaName].color),
behavior: [
"XX|XX|XX",
"M1%7|CH:" + [aphaniteName,aphaniteGravelName,aphaniteDustName].join(",") + "%0.05|M1%7",
"XX|XX|XX",
],
density: magmaDensity * 0.0024,
temp: Math.min(phaneriteMeltingPoint,metaphaneriteMeltingPoint,aphaniteMeltingPoint,metaaphaniteMeltingPoint,vesiculiteMeltingPoint,metavesiculiteMeltingPoint,vitriteMeltingPoint,metavitriteMeltingPoint) - 300,
tempHigh: Math.min(phaneriteMeltingPoint,metaphaneriteMeltingPoint,aphaniteMeltingPoint,metaaphaniteMeltingPoint,vesiculiteMeltingPoint,metavesiculiteMeltingPoint,vitriteMeltingPoint,metavitriteMeltingPoint) - 50,
stateHigh: magmaCloudName,
category: "rock cloud",
state: "gas",
_data: [compositionFamilyName,"magma","cloud"],
};
rockClouds.push(rockCloudName);
};
console.log("1/2 loaded") //true halfway point is inside newIgneousCompositionFamily.
function standaloneBrokenFormMaker(elementName,suffixWithoutUnderscore,addBreakIntoToSourceElement=false,category=null,density=null,tempHigh=null,stateHigh=null,breakInto=null) {
var newName = elementName + "_" + suffixWithoutUnderscore;
elements[newName] = {
color: gravelizeToHex(elements[elementName].color),
behavior: behaviors.POWDER,
state: "solid",
};
if(density !== null) {
if(density == "auto") {
elements[newName].density = (elements[elementName].density ?? 2000) * 0.55;
} else {
elements[newName].density = density;
};
};
if(category !== null) {
elements[newName].category = category;
};
if(tempHigh !== null) {
if(tempHigh == "auto") {
elements[newName].tempHigh = elements[elementName].tempHigh;
} else {
elements[newName].tempHigh = tempHigh;
};
};
if(stateHigh !== null) {
if(stateHigh == "auto") {
elements[newName].stateHigh = elements[elementName].stateHigh;
} else {
elements[newName].stateHigh = stateHigh;
};
};
if(breakInto !== null) {
elements[newName].breakInto = breakInto;
};
if(addBreakIntoToSourceElement) {
if(!elements[elementName].breakInto) {
elements[elementName].breakInto = newName;
} else {
if(!(elements[elementName].breakInto instanceof Array)) {
elements[elementName].breakInto = [elements[elementName].breakInto];
};
elements[elementName].breakInto.push(newName);
};
};
return elements[newName];
};
function makeSandstoningElements(sandName) {
var sandInfo = elements[sandName];
if(!sandInfo) {
throw new Error("No such element '" + sandName + "'");
};
var suspensionName, wetSandName, sedimentName, sandstoneName, dustName;
switch(sandName) {
case "dirt":
suspensionName = "muddy_water";
wetSandName = "mud"; //needs special code to not generate a wet dirt and instead use vanilla mud as the wet "sand" here
sedimentName = "soil_sediment";
sandstoneName = "soilstone"; //differentiated from mudstone, which is actually the *packed* dirt (analogously to sand's relationship to packed sand)
dustName = "dirt_dust";
break;
case "rainbow_dirt":
suspensionName = "rainbow_muddy_water";
wetSandName = "rainbow_mud";
sedimentName = "rainbow_soil_sediment";
sandstoneName = "rainbow_soilstone";
dustName = "rainbow_dirt_dust";
break;
case "crimsoil":
suspensionName = "crimmuddy_water";
wetSandName = "crimmud";
sedimentName = "crimsoil_sediment";
sandstoneName = "crimsoilstone";
dustName = "crimsoil_dust";
break;
case 143: //sorry, i had to
default:
suspensionName = sandName + "y_water";
wetSandName = "wet_" + sandName;
sedimentName = sandName + "_sediment";
sandstoneName = sandName + "stone";
dustName = sandName.replace("_sand","_dust");
};
//console.log(sandName,suspensionName);
//Water reaction to pick up the fine material (this is very simplified)
elements.water.reactions[wetSandName] = {
"elem1": suspensionName,
"elem2": [wetSandName,wetSandName,wetSandName,suspensionName],
chance: 0.01
};
//Sediment suspension
//Color generation
var sandColor = sandInfo.color;
if(!(sandColor instanceof Array)) {
sandColor = [sandColor];
};
var waterColor = "#2167ff";
//console.log(sandColor);
suspensionColor = sandColor.map(sandSubcolor => lerpColors(waterColor,sandSubcolor,"hex",weight1=0.5)); //lerp all with half water
var sedimentColor = sandColor.map(sandSubcolor => convertHslObjects(sedimentHslOffset(normalizeColorToHslObject(sandSubcolor)),"hex"));
//console.log(sandInfo);
elements[suspensionName] = {
color: suspensionColor,
behavior: behaviors.LIQUID,
tempHigh: 100,
stateHigh: ["steam","steam",sandName],
//tempLow: 0,
//stateLow: "sandy_ice",
category: "suspensions",
reactions: {
"dirt": { // React with (water reacts with dirt to make mud)
"elem1": [null,null,wetSandName], // First element transforms into; in this case, water deletes itself
"elem2": "mud", // Second element transforms into; in this case, dirt turns to mud
},
"water": { "elem1":"water", "elem2":suspensionName, "chance":0.025 }, //swap reaction
"sand": { "elem1": [null,null,wetSandName], "elem2": wetSandName, },
[suspensionName]: { "elem1":"water", "elem2":sedimentName, "chance": 0.001 },
[wetSandName]: { "elem1": "water", "elem2":sedimentName, "chance": 0.0005 },
//"salt": { "elem1": "salt_water", "elem2": null },
//"sugar": { "elem1": "sugar_water", "elem2": null, },
"dust": { "elem1": "dirty_water", "elem2": null, },
"ash": { "elem1": "dirty_water", "elem2": null, },
"cyanide": { "elem1": "dirty_water", "elem2": null, },
//"carbon_dioxide": { "elem1": "seltzer", "elem2": null, "oneway":true },
"sulfur": { "elem1": "dirty_water", "elem2": null, },
"rat": { "elem1": "dirty_water", chance:0.005 },
"plague": { "elem1": "dirty_water", "elem2": null, },
"rust": { "elem1": "dirty_water", chance:0.005 },
"fallout": { "elem1": "dirty_water", chance:0.25 },
"radiation": { "elem1": "dirty_water", chance:0.25 },
"uranium": { "elem1": "dirty_water", chance:0.25 },
"rotten_meat": { "elem1": "dirty_water", chance:0.25 },
"quicklime": { "elem1": [null,null,wetSandName], "elem2": "slaked_lime", },
"rock": { "elem2": wetSandName, "chance": 0.00035 },
"ruins": { "elem2": "rock", "chance": 0.00035 },
"mudstone": { "elem2": "mud", "chance": 0.00035 },
//"methane": { "elem1":"primordial_soup", "elem2":"primordial_soup", tempMin:60, charged:true },
//"ammonia": { "elem1":"primordial_soup", "elem2":"primordial_soup", tempMin:60, charged:true },
"fly": { "elem2":"dead_bug", "chance":0.1, "oneway":true },
"firefly": { "elem2":"dead_bug", "chance":0.1, "oneway":true },
"bee": { "elem2":"dead_bug", "chance":0.05, "oneway":true },
"stink_bug": { "elem2":"dead_bug", "chance":0.1, "oneway":true },
},
state: "liquid",
density: 1000 + (sandInfo.density * 0.06),
conduct: 0.02,
stain: 0.01,
_data: [sandInfo?._data?.[0] ?? "unknown", sandInfo?._data?.[1] ?? "unknown", "suspension"],
}
if(elements[dustName]) {
elements[dustName].reactions ??= {};
elements[dustName].reactions.water = {
elem1: null, elem2: suspensionName
};
};
//Sediment element where lithification code resides
elements[sedimentName] = {
hidden: true,
color: sedimentColor,
hardness: 0.2,
tick: function(pixel) {
if(!tryMove(pixel,pixel.x,pixel.y+1)) {
var newPixel = pixelMap[pixel.x]?.[pixel.y+1];
if(!newPixel) {
return;
};
var newElement = newPixel.element;
var thisSandName = pixel.element.slice(0,-9); //ABCD_sand_sediment - _sediment
var thisWetSandName = "wet_" + thisSandName;
var thisSuspensionName = pixel.element.slice(0,-9) + "y_water";
var sandstoneName = thisSandName + "stone";
if(Math.random() < 0.005 && ["sediment","wet_particulate"].includes(elements[newElement]._data?.[2])) { //0.5% chance to swap with wet
swapPixels(pixel,newPixel);
return;
};
if(Math.random() < 0.001 && elements[newElement]._data?.[2] == "particulate") { //0.1% chance to give water away
var newWetParticulateName = elements.water.reactions[newElement]?.elem2;
if(!newWetParticulateName) { return };
if(elements[thisWetSandName] && elements[newWetParticulateName]) {
//console.log(thisSandName);
//console.log(newWetSandName);
changePixel(pixel,thisSandName,false);
changePixel(newPixel,newWetParticulateName,false);
};
};
if(Math.random() < 0.001 && newElement == "water") { //0.1% chance to give dissolve in water
if(elements[thisSuspensionName]) {
//console.log(thisSuspensionName);
changePixel(pixel,thisSuspensionName,false);
changePixel(newPixel,thisSuspensionName,false);
};
};
if(Math.random() < 0.001 && elements[newElement]._data?.[2] == "suspension") { //0.1% chance to sediment a suspension
var newSedimentName = elements[newPixel.element].reactions[newPixel.element].elem2;
//console.log(newSedimentName);
if(elements[newSedimentName]) {
changePixel(newPixel,newSedimentName,false);
};
};
};
//console.log(sandstoneName);
sedimentation(pixel,sandstoneName)
},
tempHigh: sandInfo.tempHigh,
stateHigh: sandInfo.stateHigh,
category: "sediment",
state: "solid",
density: elements[wetSandName].density + 150,
breakInto: sandName,
_data: [sandInfo?._data?.[0] ?? "unknown", sandInfo?._data?.[1] ?? "unknown", "sediment"]
};
//Final rock
//console.log(sandName);
elements[sandstoneName] = {
color: sandstonizeToHex(sandName), //["#b27853", "#d1a784", "#d1a784", "#d4996e"]
behavior: behaviors.WALL,
tempHigh: function() {
switch(sandName) {
case "dirt":
return elements.dry_dirt.tempHigh;
case "crimsoil":
return elements.crimsoil.tempHigh;
case "rainbow_dirt":
return elements.rainbow_dirt.tempHigh;
default:
return elements[sandName].tempHigh
}
}(),
stateHigh: function() {
switch(sandName) {
case "sand":
return "glass";
case "gabbro_sand":
return "magma";
case "dirt":
return "hot_soilstone";
case "rainbow_dirt":
return "hot_rainbow_dirt";
case "crimsoil":
return "hot_crimsoilstone";
default:
var elementNameAssumingSandNameIsOfTheFormatFOOBAR_sand = sandName.slice(0,-5);
var correspondingElementObject = elements[elementNameAssumingSandNameIsOfTheFormatFOOBAR_sand];
if(!correspondingElementObject) {
throw new Error(`makeSandstoningElements: Could not generate the sandstone for ${sandName} because this script couldn't find a corresponding parent rock ${elementNameAssumingSandNameIsOfTheFormatFOOBAR_sand}`);
};
return correspondingElementObject.stateHigh
}
}(), //apparently you can do this
category: "solid rock",
state: "solid",
density: sandInfo.density * 1.5, //wide range
hardness: 0.5,
breakInto: sandName,
grain: 2,
_data: [sandInfo?._data?.[0] ?? "unknown", (sandInfo?._data?.[1] ?? "unknown") + "_sandstone", "sedimentary_rock"],
};
};
function makeNonSandSedimentationElements(particulateName,suspensionName,rockName) {
var particulateInfo = elements[particulateName];
if(!particulateInfo) {
throw new Error("No such element '" + particulateName + "'");
};
var sedimentName = particulateName + "_sediment";
//Water reaction to pick up the fine material (this is very simplified)
elements.water.reactions[particulateName] = {
"elem1": suspensionName,
"elem2": [particulateName,particulateName,particulateName,suspensionName],
chance: 0.001
};
//Sediment suspension
//Color generation
var particulateColor = particulateInfo.color;
if(!(particulateColor instanceof Array)) {
particulateColor = [particulateColor];
};
var waterColor = "#2167ff";
//console.log(particulateColor);
suspensionColor = particulateColor.map(sandSubcolor => lerpColors(waterColor,sandSubcolor,"hex",weight1=0.5)); //lerp all with half water
var sedimentColor = particulateColor.map(sandSubcolor => convertHslObjects(sedimentHslOffset(normalizeColorToHslObject(sandSubcolor)),"hex"));
//console.log(particulateInfo);
elements[suspensionName] = {
color: suspensionColor,
behavior: behaviors.LIQUID,
tempHigh: 100,
stateHigh: ["steam","steam",particulateName],
category: "suspensions",
reactions: {
"dirt": { // React with (water reacts with dirt to make mud)
"elem1": [null,null,particulateName], // First element transforms into; in this case, water deletes itself
"elem2": "mud", // Second element transforms into; in this case, dirt turns to mud
},
"water": { "elem1":"water", "elem2":suspensionName, "chance":0.025 }, //swap reaction
"particulateName": { "elem1": [null,null,particulateName], "elem2": particulateName, },
//"salt": { "elem1": "salt_water", "elem2": null },
//"sugar": { "elem1": "sugar_water", "elem2": null, },
"dust": { "elem1": "dirty_water", "elem2": null, },
"ash": { "elem1": "dirty_water", "elem2": null, },
"cyanide": { "elem1": "dirty_water", "elem2": null, },
//"carbon_dioxide": { "elem1": "seltzer", "elem2": null, "oneway":true },
"sulfur": { "elem1": "dirty_water", "elem2": null, },
"rat": { "elem1": "dirty_water", chance:0.005 },
"plague": { "elem1": "dirty_water", "elem2": null, },
"rust": { "elem1": "dirty_water", chance:0.005 },
"fallout": { "elem1": "dirty_water", chance:0.25 },
"radiation": { "elem1": "dirty_water", chance:0.25 },
"uranium": { "elem1": "dirty_water", chance:0.25 },
"rotten_meat": { "elem1": "dirty_water", chance:0.25 },
"quicklime": { "elem1": [null,null,particulateName], "elem2": "slaked_lime", },
"rock": { "elem2": particulateName, "chance": 0.00035 },
"ruins": { "elem2": "rock", "chance": 0.00035 },
"mudstone": { "elem2": "mud", "chance": 0.00035 },
//"methane": { "elem1":"primordial_soup", "elem2":"primordial_soup", tempMin:60, charged:true },
//"ammonia": { "elem1":"primordial_soup", "elem2":"primordial_soup", tempMin:60, charged:true },
"fly": { "elem2":"dead_bug", "chance":0.1, "oneway":true },
"firefly": { "elem2":"dead_bug", "chance":0.1, "oneway":true },
"bee": { "elem2":"dead_bug", "chance":0.05, "oneway":true },
"stink_bug": { "elem2":"dead_bug", "chance":0.1, "oneway":true },
},
state: "liquid",
density: 1000 + (particulateInfo.density * 0.06),
conduct: 0.02,
stain: 0.01,
_data: [particulateInfo._data[0], particulateInfo._data[1], "suspension"],
}
if(eLists.WATER) { eLists.WATER.push(suspensionName) };
elements[suspensionName].reactions[suspensionName] = { "elem1":"water", "elem2":sedimentName, "chance": 0.001 },
elements[suspensionName].reactions[particulateName] = { "elem1": "water", "elem2":sedimentName, "chance": 0.0005 },
//Sediment element where lithification code resides
elements[sedimentName] = {
hidden: true,
color: sedimentColor,
hardness: 0.2,
tick: function(pixel) {
if(!tryMove(pixel,pixel.x,pixel.y+1)) {
var newPixel = pixelMap[pixel.x]?.[pixel.y+1];
if(!newPixel) {
return;
};
var newElement = newPixel.element;
var particulateName = pixel.element.slice(0,-9); //ABCD_sand_sediment - _sediment
var thisSuspensionName = elements[pixel.element]._sedimentationPassToElement.correspondingSuspension
var rockName = elements[pixel.element]._sedimentationPassToElement.finalRock;
if(Math.random() < 0.005 && ["sediment","wet_particulate"].includes(elements[newElement]._data?.[2])) { //0.5% chance to swap with wet
swapPixels(pixel,newPixel);
return;
};
if(Math.random() < 0.001 && elements[newElement]._data?.[2] == "particulate") { //0.1% chance to give water away
var newWetParticulateName = elements.water.reactions[newElement].elem2;
if(elements[particulateName] && elements[newWetParticulateName]) {
changePixel(pixel,particulateName,false);
changePixel(newPixel,newWetParticulateName,false);
};
};
if(Math.random() < 0.001 && newElement == "water") { //0.1% chance to dissolve in water
if(elements[thisSuspensionName]) {
//console.log(thisSuspensionName);
changePixel(pixel,thisSuspensionName,false);
changePixel(newPixel,thisSuspensionName,false);
};
};
if(Math.random() < 0.001 && elements[newElement]._data?.[2] == "suspension") { //0.1% chance to sediment a suspension
//new sediment should be the elem2 of a suspension's reaction with itself
var newSedimentName = elements[newPixel.element].reactions[newPixel.element].elem2;
//console.log(newSedimentName);
if(elements[newSedimentName]) {
changePixel(newPixel,newSedimentName,false);
};
};
};
//console.log(rockName);
sedimentation(pixel,rockName)
},
tempHigh: particulateInfo.tempHigh,
stateHigh: particulateInfo.stateHigh,
_sedimentationPassToElement: {
finalRock: rockName,
correspondingSuspension: suspensionName,
},
category: "sediment",
state: "solid",
density: elements[particulateName].density + 150,
breakInto: particulateName,
_data: [particulateInfo._data[0], particulateInfo._data[1], "sediment"],
};
//Final rock
//console.log(particulateName);
if(rockName !== "limestone") {
elements[rockName] = {
color: sandstonizeToHex(particulateName), //["#b27853", "#d1a784", "#d1a784", "#d4996e"]
behavior: behaviors.WALL,
tempHigh: particulateInfo.tempHigh,
stateHigh: particulateInfo.stateHigh,
category: "solid rock",
state: "solid",
density: particulateInfo.density * 1.5, //wide range
hardness: 0.7,
breakInto: particulateName,
grain: 2,
_data: [particulateInfo._data[0], "rock", "sedimentary_rock"],
};
};
};
if(!eLists.WATER) { console.error(38309309) };
if(eLists.WATER) { eLists.WATER.push("swamp_water","heavy_water","radioactive_water","milk") };
newPowder("calcite","#f5ecd0",2711,825,["carbon_dioxide","quicklime"],"calcium_carbonate_dust");
newPowder("aragonite","#e3c58d",2830,825,["carbon_dioxide","quicklime"],"calcium_carbonate_dust");
newPowder("vaterite","#e8ebd8",2540,825,["carbon_dioxide","quicklime"],"calcium_carbonate_dust");
newPowder("calcium_carbonate_dust","#f7f7f5",2930,825,["carbon_dioxide","quicklime"]);
//i forgot what data[1]s mean and at this point it doesn't really matter
elements.calcite._data = ["calcium","crystalline","mineral"];
elements.aragonite._data = ["calcium","crystalline","mineral"];
elements.vaterite._data = ["calcium","crystalline","mineral"];
elements.calcium_carbonate_dust._data = ["calcium","crystalline","particulate"];
elements.limestone._data = ["calcium", "sedimentary", "sedimentary_rock"];
elements.aragonite.tick = function(pixel) {
if(Math.random() < (0.001 + Math.max(0,(pixel.temp - 300) / 100))) {
changePixel(pixel,"calcite",false);
};
};
elements.vaterite.tick = function(pixel) {
if(Math.random() < (0.01 + Math.max(0,(pixel.temp - 30) / 10))) {
changePixel(pixel,"calcite",false);
};
};
makeNonSandSedimentationElements("calcium_carbonate_dust","calcium_carbonate_solution","limestone")
var calcitoids = ["calcite","aragonite","vaterite"];
for(i = 0; i < calcitoids.length; i++) {
var mineral = calcitoids[i];
elements.water.reactions[mineral] = {
"elem1":"calcium_carbonate_solution",
"elem2":[mineral,mineral,mineral,"calcium_carbonate_solution"],
"chance":0.004
};
elements.seltzer.reactions[mineral] = {
"elem1":"calcium_carbonate_solution",
"elem2":[mineral,mineral,mineral,"calcium_carbonate_solution"],
"chance":0.02
};
};
runAfterLoad(function() {
eLists.MAGMA = Object.keys(elements).filter(x => x.includes("magma") && !(x.includes("vaporized")) && !(x.includes("cloud")))
for(i = 0; i < sands.length; i++) {
switch(sands[i]) {
case "dirt":
sandSuspensions.push("muddy_water");
sandSediments.push("soil_sediment");
sandstones.push("soilstone");
break;
case "crimsoil":
sandSuspensions.push("crimmuddy_water");
sandSediments.push("crimsoil_sediment");
sandstones.push("crimsoilstone");
break;
case "rainbow_dirt":
sandSuspensions.push("rainbow_muddy_water");
sandSediments.push("rainbow_soil_sediment");
sandstones.push("rainbow_soilstone");
break;
default:
sandSuspensions.push(sands[i] + "y_water");
sandSediments.push(sands[i] + "_sediment");
sandstones.push(sands[i] + "stone");
};
makeSandstoningElements(sands[i]);
};
elements.sand.category = "sand";
elements.gravel.category = "gravel";
elements.rock.category = "rock";
elements.wet_sand.category = "wet sand";
elements.packed_sand.category = "packed sand";
elements.clay._data = ["clay","clay","particulate"],
makeNonSandSedimentationElements("clay","clay_water","shale");
elements.shale.color = ["#787b80","#535557","#695e58", "#696969", "#6b5d5b"];
elements.shale.grain = 1;
elements.shale.tempHigh = 200; //shale does get baked (https://pubs.usgs.gov/pp/0108a/report.pdf), but it feels wrong for it to happen so soon
elements.shale.behavior = behaviors.POWDER;
elements.shale.category = "solid rock";
for(fei = 0; fei < sandSuspensions.length; fei++) {
var suspensionToAddReactionTo = sandSuspensions[fei];
//console.log(suspensionToAddReactionTo);
if(!(elements[suspensionToAddReactionTo])) {
console.error(`MI ${suspensionToAddReactionTo}`);
continue
};
elements[suspensionToAddReactionTo].reactions ??= {};
for(sei = 0; sei < sandSuspensions.length; sei++) {
var suspensionToReactWith = sandSuspensions[sei];
var firstSedimentName = suspensionToAddReactionTo.replace("y_water","_sediment");
var secondSedimentName = suspensionToReactWith.replace("y_water","_sediment");
elements[suspensionToAddReactionTo].reactions[suspensionToReactWith] = {
elem1: "water", "elem2": [firstSedimentName,secondSedimentName], "chance": 0.001,
};
};
for(sej = 0; sej < wetSands.length; sej++) {
var wetSandToReactWith = wetSands[sej];
var firstSedimentName = suspensionToAddReactionTo.replace("y_water","_sediment");
var secondSedimentName = wetSandToReactWith.replace("wet_","") + "_sediment";
elements[suspensionToAddReactionTo].reactions[wetSandToReactWith] = {
elem1: "water", "elem2": [firstSedimentName,secondSedimentName], "chance": 0.0005,
};
};
};
//lithificationElements = sandSediments.concat(sandstones);
for(fei = 0; fei < vaporizedMagmas.length; fei++) {
var vaporToAddReactionTo = vaporizedMagmas[fei];
//console.log(vaporToAddReactionTo);
elements[vaporToAddReactionTo].reactions ??= {};
for(sei = 0; sei < vaporizedMagmas.length; sei++) {
var vaporToReactWith = vaporizedMagmas[sei];
var firstCloudName = vaporToAddReactionTo.replace("vaporized_","") + "_cloud";
var secondCloudName = vaporToReactWith.replace("vaporized_","") + "_cloud";
elements[vaporToAddReactionTo].reactions[vaporToReactWith] = {
elem1: null, "elem2": [firstCloudName,secondCloudName], "chance": 0.3, y: [0,15]
};
};
for(sej = 0; sej < magmaClouds.length; sej++) {
var cloudToReactWith = magmaClouds[sej];
var firstCloudName = vaporToAddReactionTo.replace("vaporized_","") + "_cloud";
elements[vaporToAddReactionTo].reactions[cloudToReactWith] = {
elem1: firstCloudName, "chance": 0.4, y: [0,15]
};
};
};
let _s = newPowder("silicon",["#D7DDDF","#999FA1","#7A7E80","#535657"],2330,1414); _s.hardness = 0.7; _s.tick = function(pixel) {
if(pixel.temp >= 700) {
tryTarnish(pixel,"silica",0.02,false);
}
};
elements.molten_silicon = {
tempHigh: 3265,
density: 2520,
viscosity: 1,
behavior: behaviors.MOLTEN,
tick: function(pixel) {
tryTarnish(pixel,"silica",0.02,false);
pixelTempCheck(pixel);
},
reactions: {
oxygen: { elem1: ["molten_silicon","silica"], elem2: null, minTemp: 700 },
liquid_oxygen: { elem1: ["molten_silicon","silica"], elem2: ["liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen",null], minTemp: 700 }, //real ratio is 862:1
oxygen_ice: { elem1: ["molten_silicon","silica"], elem2: ["liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen","liquid_oxygen",null], minTemp: 700 }
}
},
newPowder("silica","#faf9f0",2202,1713).hardness = 0.7;
elements.glass.alpha = 0.6;
elements.fused_silica = {
color: "#F8F5ED",
alpha: 0.5,
renderer: renderPresets.BORDER,
behavior: behaviors.WALL,
reactions: {
"radiation": { elem1:"rad_glass", chance:0.33 },
"rad_steam": { elem1:"rad_glass", elem2:null, chance:0.33 },
"fallout": { elem1:"rad_glass", elem2:"radiation", chance:0.1 }
},
tempHigh: 1713,
stateHigh: "molten_silica",
hardness: 0.72,
category: "solids",
state: "solid",
density: 2202,
breakInto: "silica",
noMix: true,
grain: 0
};
elements.silica.reactions = {
ultramafic_magma: { elem1:[
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica",null //the range of silica content from ultramafic to felsic is about 20%; this regarded as 4 even steps on top of ultramafic magma for simplicity's sake gives 5% or 1/20
], elem2: "magma", "chance":0.1 },
magma: { elem1:[
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica",null
], elem2: "intermediate_magma", "chance":0.09 },
intermediate_magma: { elem1:[
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica",null
], elem2: "intermediate_felsic_magma", "chance":0.08 },
intermediate_felsic_magma: { elem1:[
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica","silica",
"silica","silica","silica","silica",null
], elem2: "felsic_magma", "chance":0.07 },
};
elements.molten_silica = {
tempHigh: 2950,
viscosity: 2000000000, //2e7 centiPoise
stateLow: "fused_silica",
reactions: {
ultramafic_magma: { elem1:[
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica",null //the range of silica content from ultramafic to felsic is about 20%; this regarded as 4 even steps on top of ultramafic magma for simplicity's sake gives 5% or 1/20
], elem2: "magma", "chance":0.1 },
magma: { elem1:[
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica",null
], elem2: "intermediate_magma", "chance":0.09 },
intermediate_magma: { elem1:[
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica",null
], elem2: "intermediate_felsic_magma", "chance":0.08 },
intermediate_felsic_magma: { elem1:[
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica","molten_silica",
"molten_silica","molten_silica","molten_silica","molten_silica",null
], elem2: "felsic_magma", "chance":0.07 }
},
};
elements.felsic_magma.reactions ??= {};
elements.felsic_magma.reactions.intermediate_magma = {
elem1: "intermediate_felsic_magma", elem2: "intermediate_felsic_magma", chance: 0.8,
};
elements.intermediate_felsic_magma.reactions ??= {};
elements.intermediate_felsic_magma.reactions.magma = {
elem1: "intermediate_magma", elem2: "intermediate_magma", chance: 0.7,
};
elements.felsic_magma.reactions ??= {};
elements.felsic_magma.reactions.magma = { //mafic magma
elem1: "intermediate_magma", elem2: "intermediate_magma", chance: 0.7,
};
elements.felsic_magma.reactions ??= {};
elements.felsic_magma.reactions.ultramafic_magma = { //mafic magma
elem1: "intermediate_magma", elem2: "magma", chance: 0.6,
};
elements.intermediate_magma.reactions ??= {};
elements.intermediate_magma.reactions.ultramafic_magma = { //mafic magma
elem1: "magma", elem2: "magma", chance: 0.6,
};
elements.molten_dirt.tempHigh = 3313;
var rockStateHigh = JSON.parse(JSON.stringify(vaporizedMagmas));
//only real magmas in dirt
if(rockStateHigh.includes("vaporized_nellish_magma")) {
rockStateHigh.splice(rockStateHigh.indexOf("vaporized_nellish_magma"));
};
if(rockStateHigh.includes("vaporized_rainbow_magma")) {
rockStateHigh.splice(rockStateHigh.indexOf("vaporized_rainbow_magma"));
};
if(rockStateHigh.includes("vaporized_crimson_magma")) {
rockStateHigh.splice(rockStateHigh.indexOf("vaporized_crimson_magma"));
};
if(rockStateHigh.includes("vaporized_blackpinkinitic_magma")) {
rockStateHigh.splice(rockStateHigh.indexOf("vaporized_blackpinkinitic_magma"));
};
elements.molten_dirt.stateHigh = rockStateHigh; //assuming mixture
for(var sandIndex in sands) {
sandIndex = parseInt(sandIndex);
var sandName = sands[sandIndex];
var usedSandColor = elements[sandName].color;
if(!(usedSandColor instanceof Array)) {
usedSandColor = [usedSandColor];
};
var newSandyClayColor = usedSandColor.map(subcolor => lerpColors(subcolor,elements.clay.color,"hex",weight1=0.5));
var newSandyLoamColor = [];
for(var dirtSubcolorIndex in elements.dirt.color) {
dirtSubcolorIndex = parseInt(dirtSubcolorIndex);
dirtSubcolor = elements.dirt.color[dirtSubcolorIndex];
//for each dirt subcolor, to the final new color concatenate the result of mapping each of the sand color's subcolors to one of dirt's subcolors
newSandyLoamColor = newSandyLoamColor.concat(usedSandColor.map(subcolor => lerpColors(subcolor,dirtSubcolor,"hex",weight1=0.6)));
};
var newLoamySandColor = [];
for(var dirtSubcolorIndex in elements.dirt.color) {
dirtSubcolorIndex = parseInt(dirtSubcolorIndex);
dirtSubcolor = elements.dirt.color[dirtSubcolorIndex];
//for each dirt subcolor, to the final new color concatenate the result of mapping each of the sand color's subcolors to one of dirt's subcolors
newLoamySandColor = newLoamySandColor.concat(usedSandColor.map(subcolor => lerpColors(subcolor,dirtSubcolor,"hex",weight1=0.4)));
};
var newSandyClayLoamColor = newSandyLoamColor.map(subcolor => lerpColors(subcolor,elements.clay.color,"hex",weight1=2/3));
var newSandyLoamColor = elements.dirt.color.map(subcolor => lerpColors(subcolor,elements.clay.color,"hex",weight1=0.5));
}
var newClayLoamColor = elements.dirt.color.map(subcolor => changeHue(lerpColors(subcolor,elements.clay.color,"hex",weight1=0.5),0.9,"multiply","hex"));
var newDryClayLoamColor = newClayLoamColor.map(x => changeSaturation(changeLightness(x,15,"add","hsljson"),0.9,"multiply","hex"));
newPowder("clay_loam",newClayLoamColor,1500,100,"dry_clay_loam",["dirt","clay_soil"]);
elements.clay_loam._data = ["clay_loam","soil","particulate"];
//manual addition due to autogen fuckery and i don't feel like calling in runAfterAutogen
elements.molten_clay_loam = {
"behavior": behaviors.MOLTEN,
"hidden": true,
"state": "liquid",
"category": "states",
"color": [ "rgb(255,217,75)", "rgb(255,174,75)", "rgb(255,130,0)", "rgb(255,205,70)", "rgb(255,164,70)", "rgb(255,123,0)", "rgb(255,202,68)", "rgb(255,162,68)", "rgb(255,121,0)", "rgb(255,210,72)", "rgb(255,168,72)", "rgb(255,126,0)" ].map(x => convertColorFormats(x,"hex")),
"tempLow": 1250,
"stateLow": "dry_clay_loam",
"density": 1350,
"viscosity": 10000
};
newPowder("dry_clay_loam",newDryClayLoamColor,1500,1250,"molten_clay_loam",["dry_dirt","clay_soil"]);
elements.dry_clay_loam.data = ["clay_loam","dry_soil","particulate"];
//newPowder(name,color,density=null,tempHigh=null,stateHigh=null,breakInto=null)
});
//Terrain
//Soils
//Wet
//Wet Clay
//TODO
//Wet Silty clay
//TODO
//Wet Silty Clay Loam
//TODO
//Wet Silty Loam
//TODO
//Wet Silt
//TODO
//Wet Clay Loam
//TODO
//Wet Medium Loam
//Mud exists
//Wet Sandy Clay
//TODO
//Wet Sandy Clay Loam
//TODO
//Wet Sandy Loam
//TODO
//Wet Loamy Sand
//TODO
//Wet Sand
//Wet Sand exists
//Permafrost
//Clay Permafrost
//TODO
//Silty clay Permafrost
//TODO
//Silty Clay Loam Permafrost
//TODO
//Silty Loam Permafrost
//TODO
//Silt Permafrost
//TODO
//Clay Loam Permafrost
//TODO
//Medium Loam Permafrost
//Permafrost exists
//Sandy Clay Permafrost
//TODO
//Sandy Clay Loam Permafrost
//TODO
//Sandy Loam Permafrost
//TODO
//Loamy Sand Permafrost
//TODO
//Sand Permafrost
//TODO
//Radioactive (unmoved/TODO)
//Dry
//Radioactive Clay
//Clay exists
//Radioactive Silty clay
//TODO
//Radioactive Silty Clay Loam
//TODO
//Radioactive Silty Loam
//TODO
//Radioactive Silt
//TODO
//Radioactive Clay Loam
//Clay Soil exists
//Radioactive Medium Loam
//Dirt exists
//Radioactive Sandy Clay
//TODO
//Radioactive Sandy Clay Loam
//TODO
//Radioactive Sandy Loam
//TODO
//Radioactive Loamy Sand
//TODO
//Radioactive Sand
//Sand exists
//Wet
//Radioactive Wet Clay
//TODO
//Radioactive Wet Silty clay
//TODO
//Radioactive Wet Silty Clay Loam
//TODO
//Radioactive Wet Silty Loam
//TODO
//Radioactive Wet Silt
//TODO
//Radioactive Wet Clay Loam
//TODO
//Radioactive Wet Medium Loam
//Mud exists
//Radioactive Wet Sandy Clay
//TODO
//Radioactive Wet Sandy Clay Loam
//TODO
//Radioactive Wet Sandy Loam
//TODO
//Radioactive Wet Loamy Sand
//TODO
//Radioactive Wet Sand
//Wet Sand exists
//Permafrost
//Radioactive Clay Permafrost
//TODO
//Radioactive Silty clay Permafrost
//TODO
//Radioactive Silty Clay Loam Permafrost
//TODO
//Radioactive Silty Loam Permafrost
//TODO
//Radioactive Silt Permafrost
//TODO
//Radioactive Clay Loam Permafrost
//TODO
//Radioactive Medium Loam Permafrost
//Permafrost exists
//Radioactive Sandy Clay Permafrost
//TODO
//Radioactive Sandy Clay Loam Permafrost
//TODO
//Radioactive Sandy Loam Permafrost
//TODO
//Radioactive Loamy Sand Permafrost
//TODO
//Radioactive Sand Permafrost
//TODO
//Rocks
//Igneous
//Felsic
newIgneousCompositionFamily(
"felsic",
1e12, 2200, -85, -20, 2850,
//Not much data on metamorphites besides gneiss
"granite", ["#F3C3AD", "#F0AB75", "#DDA888", "#BD927E", "#998473", "#5C5E53", "#BD8366"], 1215, 2691,
"gneiss", ["#C5C1B4", "#605A5E", "#424449", "#EDECE9", "#73503A", "#92866F"], 1215, 2750,
"rhyolite", ["#A67153","#BF967E","#D9B5A0","#8C533E","#C99F86","#C5997E","#BB8A69"], 800, 1254,
"metarhyolite", ["#C0C7D3","#CAD0D9","#AEB7B7","#728189","#798B96","#B09F98","#515155"], 800, 2584, //https://www.researchgate.net/figure/Physical-properties-of-the-metarhyolites_tbl2_245002845 also there are pictures yay
"pumice", ["#ebe1c3", "#ada386", "#f0bd9e", "#ab846c", "#bfbebd", "#75726f", "#f5e595", "#ab9e60", "#ad683d", "#633d25", "#6e6d6d", "#3b3a39"], 1350, 641,
//it is said to flatten out and have smaller vesicles but the color is pulled out of my ass
"metapumice", ["#a6a295", "#787a6f", "#8f847e", "#917c6e", "#858382", "#696460", "#8a6d5c", "#6e5749", "#5c5b55", "#53594f"], 1350, 2328,
vitreousFelsicName, ["#252422", "#171616", "#161915", "#161018"], 1000, 2488,
//if metamorphism sometimes involves recrystallization and obsidian is the way it is due to being amorphous and lacking a crystal structure then perhaps obsidian might be somewhat like granite with its new crystals
"meta" + vitreousFelsicName, ["#453f3c", "#1f1a18", "#36342b", "#1c1519", "#3d3133", "#1f1b1a", "#453a32"], 1000, 2513,
7,3
);
elements.water.reactions.obsidian_shard.elem2 = ["obsidian_sand","obsidian_sand","obsidian_sand","sand","sand"]
elements.obsidian_sand.color = ["#3b3730", "#211e1e", "#293321", "#31133b"];
elements.obsidian_shard.desc = 'crushed obsidian my beloved';
//Intermediate felsic
newIgneousCompositionFamily(
"intermediate_felsic",
1e10, 2320, -95, -23, 2900,
"granodiorite", ["#B1AB9D", "#262001", "#A6A292", "#D6C5BC", "#F2F2F2", "#DED8C2", "#978871", "#A8AAA7"], 1277, 2644, //Color from image: By Rudolf Pohl - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=7788350; melting point made-up/interpolated from granite and diorite; last 2 digits of density are made up again
"metagranodiorite", ["#F3EDDC","#F0ECD8","#EDECDC","#D0C9A9","#BDB192","#BBA27A","#86744E","#323026","#262417","#202012"], 1277, 2711,
"dacite", ["#D9CCC5", "#F2E9E4", "#877670", "#A69B97"], 1050, 2654, //https://books.google.ca/books?id=ObUPAAAAIAAJ&pg=PA181&lpg=PA181&dq=dacite+specific+gravity&source=bl&ots=qn8B4sirWi&sig=Wp_MHqPuUGPNQobcuNP5c5wqkpU&hl=en&sa=X&ei=cimtUaH8Eab7yAH8joDABQ#v=onepage&q=dacite%20specific%20gravity&f=false
"metadacite", ["#91847d", "#e0c9bc", "#735a56", "#bfa59b", "#696563"], 1050, 2727,
"intermediate_pumice", ["#dbd4bd", "#b5ad94", "#e3ceb6", "#bda891", "#c2c2c2", "#a1a1a1", "#e6c8a1", "#b8a48c"], 1190, 991,
"intermediate_metapumice", ["#777868", "#5a5c51", "#82756f", "#6e6057", "#96918f", "#70665e"], 1190, 2623,
vitreousInterfelsicName, ["#4f4b42", "#474646", "#4a4d49", "#342f36"], 1040, 2640,
"meta" + vitreousInterfelsicName, ["#3d3c39", "#696262", "#313630", "#625966"], 1040, 2772,
6,4
);
//Intermediate
newIgneousCompositionFamily(
"intermediate",
1e8, 2450, -105, -26, 2950,
"diorite", ["#E1E1E1","#B0A696","#707271","#434459","#242424"], 1300, 2822, //Extracted from image and blended; Michael C. Rygel - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=31124755 https://commons.wikimedia.org/w/index.php?curid=7788350; last 2 digits made up again
"metadiorite", ["#D1D2D7","#C3C2AF","#AEACB1","#A1A29D","#C3C4BC","#C3C9CA","#B5AEA4","#B6AC91","#AEA582","#5A6992"], 1300, 2929,
"andesite", ["#6F7575", "#C5C9CB", "#818787", "#797F7F", "#B5B9BA", "#6D7371", "#909696"], 1215, 2474, //https://books.google.ca/books?id=ObUPAAAAIAAJ&pg=PA181&lpg=PA181&dq=dacite+specific+gravity&source=bl&ots=qn8B4sirWi&sig=Wp_MHqPuUGPNQobcuNP5c5wqkpU&hl=en&sa=X&ei=cimtUaH8Eab7yAH8joDABQ#v=onepage&q=dacite%20specific%20gravity&f=false
"metaandesite", ["#5b5c5b", "#a3a6a2", "#6e665e", "#b39b92", "#756763", "#91817d", "#73524d"], 1215, 2553,
"scoria", ["#594545", "#573b31", "#522e28"], 1085, 2550,
"metascoria", ["#403835","#75574c","#4f302b","#8a7c75"], 1085, 2670,
vitreousIntermediateName, ["#636059", "#707070", "#5f615f", "#504b52"], 1085, 2710,
"meta" + vitreousIntermediateName, ["#4a4845", "#75716e", "#43453f", "#5e4b53", "#66554d"], 1085, 2744,
5,5
);
elements.scoria_gravel.density = 2790;
//Mafic
elements.rock.name = "Gabbro";
elements.rock.tempHigh = 1200;
elements.rock.density = 3300;
elements.rock.breakInto = ["gravel"];
elements.gravel.breakInto = ["gabbro_dust"];
elements.gravel.name = "Gabbro Gravel";
delete elements.wet_sand.reactions.gravel;
elements.rock._data = ["mafic","phanerite","igneous_rock"],
elements.magma.name = "mafic magma";
elements.magma.density = 2650;
elements.magma.category = "magmas";
elements.magma._magmaCoolingPassToElement = {
vitreous: [-115,vitreousMaficName],
aphanitic: [-29,"basalt"],
phaneritic: [Infinity,"gabbro"],
meltingPoints: {
vitreous: 1200,
vesicular: 1298,
aphanitic: 1122,
phaneritic: 1200,
},
},
elements.magma.tick = function(pixel) {
magmaRateBasedCooling(pixel,1180,vitreousMaficName,-115,"basalt",-29,"rock");
};
elements.magma.temp = 1400;
elements.magma.tempLow = -Infinity;
elements.magma.stateLow = ["basalt","gabbro",vitreousMaficName]
elements.magma.reactions ??= {};
elements.magma.reactions.foam = { "elem1": "mafic_scoria", "elem2": "mafic_scoria" };
elements.magma._data = ["mafic","magma","liquid"],
elements.basalt.tempHigh = 1122;
elements.basalt.density = 2949;
elements.basalt.breakInto = "basalt_gravel",
elements.rock._data = ["mafic","phanerite","igneous_rock"],
elements.gravel._data = ["mafic","phanerite","igneous_gravel"],
elements.basalt._data = ["mafic","aphanite","igneous_rock"],
elements.sand._data = ["silica","crystalline","particulate"],
elements.wet_sand._data = ["silica","crystalline","wet_particulate"],
elements.packed_sand._data = ["silica","crystalline","packed_particulate"],
newIgneousCompositionFamily(
"mafic",
10000, 2200, -115, -29, 3000,
"rock", ["#808080","#4f4f4f","#949494"], 1474, 3300,
"metagabbro", ["#F6F6F5", "#EEEFEC", "#E7E6DD","#C0BBA3","#A9ABA7", "#8A8C8C", "#727271", "#61635F", "#595A59", "#454641", "#4E514A"], 1474, 3350,
"basalt", ["#2e2e2e","#333333","#3d3d3d"], 1122, 2949,
"metabasalt", ["#292e26","#474d3d","#2e2e29","#4a574f"], 1122, 3070,
"mafic_scoria", ["#756666", "#695751", "#737272"], 1298, 2717,
"mafic_metascoria", ["#856d6d","#4f4139","#8c8373","#494a39"], 1298, 2773,
vitreousMaficName, ["#6e615d", "#706767", "#6a6b63", "#6e5e68"], 1200, 2900,
"meta" + vitreousMaficName, ["#7a685d", "#3c4235", "#7c7869", "#3f3138"], 1200, 2991,
3,7
);
elements.mafic_scoria.tempHigh = 1298;
elements.mafic_scoria.stateHigh = "magma";
elements.mafic_scoria_gravel.density = 2993;
elements.basalt.behavior = behaviors.STURDYPOWDER;
elements.metabasalt.behavior = behaviors.STURDYPOWDER;
//Ultramafic
newIgneousCompositionFamily(
"ultramafic",
800, 2800, -125, -32, 3050,
"peridotite", ["#848a5e","#68785b","#8a9967","#3f403d","#33312e","#4c4f45"], 1400, 3347, //appr from https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/GL003i009p00509#:~:text=Abstract,and%20the%20bulk%20rock%20analyses.
"metaperidotite", ["#7d604f","#959c98","#454443","#363432","#5e4840"], 1400, 3404,
"komatiite", ["#6e7d6e","#858c8a","#768270","#767a77"], 1600, 3100,
"metakomatiite", ["#AEB5AE","#A9B8B5","#7B8881","#858B87","#949F97","#66655d","#5e4d48"], 1600, 3066,
"ultramafic_scoria", ["#636555", "#6a6751", "#828382"], 1400, 2924,
"ultramafic_metascoria", ["#574e47", "#6a7357", "#3b3430", "#4d4939"], 1400, 3003,
vitreousUltramaficName, ["#6e6d5e", "#5f6659", "#54574b", "#665d55"], 1300, 3200,
"meta" + vitreousUltramaficName, ["#4a443d", "#5e5e4a", "#3a4036", "#4d524f"], 1300, 3266,
2,8
);
elements.ultramafic_scoria_gravel.density = 3132;
elements.basalt_gravel._data = ["mafic","aphanite","igneous_gravel"],
elements.limestone_gravel = {
color: ["#c7baa1", "#e8d8b7", "#fcf3d7", "#fffce6"],
behavior: behaviors.POWDER,
tempHigh: 825,
stateHigh: "quicklime",
category: "gravel",
state: "solid",
density: 1380,
hardness: 0.16,
breakInto: ["quicklime","calcium","dust"],
}
elements.limestone.breakInto = "limestone_gravel";
elements.worm.reactions.limestone_gravel = { "elem2":"calcium", "chance":0.1 },
elements.acid.reactions.limestone_gravel = { "elem1":"neutral_acid", "elem2":null },
newPowder("aluminum_oxide","#f2f2f2",3987,2072).hardness = 0.93;
elements.aluminum.burnInto = "aluminum_oxide",
elements.molten_aluminum_oxide = {
tempHigh: 2977,
};
newPowder("sulfur_trioxide","#ededed",1995,16.9).reactions = {
water: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
steam: { elem1: "sulfuric_acid", elem2: "acid" },
ice: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
snow: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
packed_snow: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
slush: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
copper_2_oxide: { elem1: "anhydrous_copper_sulfate", elem2: "anhydrous_copper_sulfate" }
}; elements.sulfur_trioxide.temp = 10;
elements.molten_sulfur_trioxide = {
color: "#c0c0c0",
behavior: behaviors.LIQUID,
density: 1920,
viscosity: 5, //idk idc
tempHigh: 45,
reactions: {
water: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" }, //no H2SO4, hydronium doesn't really seem to be its own substance
steam: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
ice: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
snow: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
packed_snow: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
slush: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
},
};
elements.sulfur_trioxide_gas = {
color: "#c0c0c0",
density: 2.3, //idk idc
reactions: {
water: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" }, //no H2SO4, hydronium doesn't really seem to be its own substance
steam: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
ice: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
snow: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
packed_snow: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
slush: { elem1: "sulfuric_acid", elem2: "sulfuric_acid" },
},
};
var tempaaa = {
sulfur_trioxide: "value doesn't matter",
molten_sulfur_trioxide: "stan loona",
sulfur_trioxide_gas: "aaaaaaa"
};
delete elements.concrete.tempHigh;
delete elements.concrete.stateHigh;
if(elements.hanging_concrete) {
delete elements.hanging_concrete.tempHigh;
delete elements.hanging_concrete.stateHigh;
};
if(elements.crumbling_concrete) {
delete elements.crumbling_concrete.tempHigh;
delete elements.crumbling_concrete.stateHigh;
};
if(elements.attach_concrete) {
delete elements.attach_concrete.tempHigh;
delete elements.attach_concrete.stateHigh;
};
delete elements.quicklime.stateHigh;
elements.quicklime.tempHigh = 2572;
elements.molten_quicklime = {
tempHigh: 2850
};
elements.concrete.properties ??= {};
elements.concrete.properties.composition = "mafic";
newConcreteTick = function(pixel) {
pixel.composition ??= "mafic";
pixel.wet ??= Math.random() < 0.03 ? 1 : 0;
pixel.frozen ??= false;
pixel.didColorChange ??= 0;
pixel.lastTemperatures ??= [];
pixel.lastTemperatures.push(pixel.temp); //due to how it's structured, last temp will always equal pixel.temp;
while(pixel.lastTemperatures.length > 2) {
pixel.lastTemperatures.shift();
};
var overallTemperatureChangeRate = (pixel.temp - pixel.lastTemperatures[0]) / (pixel.lastTemperatures.length - 1);
var magmaName = (pixel.composition == "mafic") ? "magma" : pixel.composition + "_magma";
var magmaTempHigh = Math.max(...Object.values(elements[magmaName]._magmaCoolingPassToElement.meltingPoints));
if(pixel.wet && !pixel.frozen && pixel.temp < 0) {
if(Math.random() < (pixel.wet / 25)) { //if unfrozen, crack apart (freezing damage) with small chance, and then mark survivors as frozen
//console.log("freezing");
explodeAt(pixel.x,pixel.y,2,"ice");
if(!pixel) { //if deleted
return;
};
if(pixel.element !== "ice") { //chance to just change to ice after the fact if survivor
if(Math.random() < (pixel.wet / 8)) {
changePixel(pixel,"ice",false);
};
};
if(pixel.element !== "concrete") { //if changed, stop execution
return;
};
};
//if unchanged and undeleted, mark as frozen
pixel.frozen = true;
};
if(pixel.frozen && pixel.temp > 0) {
pixel.frozen = false;
};
//console.log(pixel.temp,pixel.didColorChange);
if(pixel.temp > 300 && pixel.didColorChange < 1) {
if(Math.random() < 0.02) { breakPixel(pixel) };
var colorWasHSL = pixel.color.startsWith("hsl");
var oldColor = convertHslObjects(normalizeColorToHslObject(pixel.color),"rgbjson");
if(oldColor == null) { oldColor = pixelColorPick(pixel) };
oldColor.r += 81/2;
oldColor.g += 60/2;
oldColor.b += 56/2;
pixel.color = convertHslObjects(normalizeColorToHslObject(oldColor),colorWasHSL ? "hsl" : "rgb");
pixel.didColorChange = 1;
} else if(pixel.temp > 500 && pixel.didColorChange < 2) {
if(Math.random() < 0.04) { breakPixel(pixel) };
var colorWasHSL = pixel.color.startsWith("hsl");
var oldColor = convertHslObjects(normalizeColorToHslObject(pixel.color),"rgbjson");
if(oldColor == null) { oldColor = pixelColorPick(pixel) };
oldColor.r += 81/4;
oldColor.g += 60/4;
oldColor.b += 56/4;
pixel.color = convertHslObjects(normalizeColorToHslObject(oldColor),colorWasHSL ? "hsl" : "rgb");
pixel.didColorChange = 2;
} else if(pixel.temp > 700 && pixel.didColorChange < 3) {
if(Math.random() < 0.06) { breakPixel(pixel) };
var colorWasHSL = pixel.color.startsWith("hsl");
var oldColor = convertHslObjects(normalizeColorToHslObject(pixel.color),"rgbjson");
if(oldColor == null) { oldColor = pixelColorPick(pixel) };
oldColor.r += 81/7;
oldColor.g += 60/7;
oldColor.b += 56/7;
pixel.color = convertHslObjects(normalizeColorToHslObject(oldColor),colorWasHSL ? "hsl" : "rgb");
pixel.didColorChange = 3;
} else if(pixel.temp > 900 && pixel.didColorChange < 4) {
if(Math.random() < 0.08) { breakPixel(pixel) };
var colorWasHSL = pixel.color.startsWith("hsl");
var oldColor = convertHslObjects(normalizeColorToHslObject(pixel.color),"rgbjson");
if(oldColor == null) { oldColor = pixelColorPick(pixel) };
oldColor.r += 81/8;
oldColor.g += 60/8;
oldColor.b += 56/8;
pixel.color = convertHslObjects(normalizeColorToHslObject(oldColor),colorWasHSL ? "hsl" : "rgb");
pixel.didColorChange = 4;
};
pixel.role ??= randomChoice(["aggregate","aggregate","aggregate","aggregate","sand","sand","cement"]);
if(pixel.role == "cement") {
var chooserValue = Math.random();
if(chooserValue < 0.65) {
pixel.role = "lime";
} else if(chooserValue < 0.85) {
pixel.role = "silica";
} else if(chooserValue < 0.91) {
pixel.role = "alumina";
} else if(chooserValue < 0.96) {
pixel.role = "ferricOxide";
} else {
pixel.role = "sulfurTrioxide";
};
};
if(pixel.wet && pixel.temp > 300) {
if(overallTemperatureChangeRate > 25) { //if temp change is fast enough, always spall
if(Math.random() < Math.max(0.1,0.35 - (pixel.wet/20))) { //decreasingly less likely to spall as it gets wetter, for balance
explodeAt(pixel.x,pixel.y,Math.random() < 1/3 ? 2 : 1,"steam,dust")
if(!pixel || pixel.element !== "concrete") { //if destroyed or changed
return;
};
};
pixel.wet--;
} else { //if exposed, continuously try to boil off to random neighbor
if(exposedToAir(pixel)) {
var randomNeighbor = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)]
var rnx = randomNeighbor[0]
var rny = randomNeighbor[1]
if(isEmpty(pixel.x+rnx, pixel.y+rny, false)) {
createPixel("steam", pixel.x+rnx, pixel.y+rny)
pixel.wet--;
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"+",colorWasHSL ? "hsl" : "rgb");
};
} else { //if surrounded, lower chance to spall and higher chance to dissipate
if(Math.random() < 0.03) {
if(Math.random() < 2/5) {
explodeAt(pixel.x,pixel.y,Math.random() < 1/2 ? 2 : 3,"steam,dust")
if(!pixel || pixel.element !== "concrete") { //if destroyed or changed
return;
};
};
pixel.wet--;
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"+",colorWasHSL ? "hsl" : "rgb");
};
};
};
return;
};
if(Math.random() < 1/3) { //tick wetness behavior only 1/3 of the time, for performance
var randomCoords = JSON.parse(JSON.stringify(adjacentCoords)); //so we don't need both an adjacentCoords for *and* a random coord iterator
shuffleArray(randomCoords);
for(i = 0; i < randomCoords.length; i++) {
var coords = [
pixel.x+randomCoords[i][0],
pixel.y+randomCoords[i][1]
];
if(isEmpty(coords[0],coords[1],true)) {
continue;
} else {
var newPixel = pixelMap[coords[0]]?.[coords[1]];
if(newPixel?.element) {
if(newPixel.element === "water" && pixel.wet < 4) {
//console.log("touching water",pixel.wet);
if(pixel.wet < 1) {
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"-",colorWasHSL ? "hsl" : "rgb");
pixel.wet = 1;
if(Math.random() < 0.8) { deletePixel(newPixel.x,newPixel.y) };
break;
};
if(pixel.wet == 1) {
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"-",colorWasHSL ? "hsl" : "rgb");
pixel.wet = 2;
if(Math.random() < 0.6) { deletePixel(newPixel.x,newPixel.y) };
break;
};
if(pixel.wet == 2) {
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"-",colorWasHSL ? "hsl" : "rgb");
pixel.wet = 3;
if(Math.random() < 0.4) { deletePixel(newPixel.x,newPixel.y) };
break;
};
if(pixel.wet == 3) {
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"-",colorWasHSL ? "hsl" : "rgb");
pixel.wet = 4;
if(Math.random() < 0.2) { deletePixel(newPixel.x,newPixel.y) };
break;
};
} else {
//console.log(3);
if(pixel.wet > 1 && !pixel.frozen && newPixel.element.endsWith("concrete") && newPixel.wet != undefined && newPixel.wet < pixel.wet) {
if(pixel.wet <= 1) { break };
pixel.wet--;
var colorWasHSL = pixel.color.startsWith("hsl");
pixel.color = changeLightness(pixel.color,6,"+",colorWasHSL ? "hsl" : "rgb");
newPixel.wet++;
var newColorWasHSL = newPixel.color.startsWith("hsl");
newPixel.color = changeLightness(newPixel.color,6,"-",newColorWasHSL ? "hsl" : "rgb");
};
};
};
};
};
};
if(pixel.role == "sand" && pixel.temp > elements.sand.tempHigh) {
changePixel(pixel,"molten_glass",false);
return;
};
if(pixel.role == "aggregate" && pixel.temp > magmaTempHigh) {
changePixel(pixel,magmaName,false);
return;
};
if(pixel.role == "alumina" && pixel.temp > elements.aluminum_oxide.tempHigh) {
changePixel(pixel,"molten_aluminum_oxide",false);
return;
};
if(pixel.role == "ferricOxide" && pixel.temp > elements.rust.tempHigh) {
changePixel(pixel,"molten_iron",false);
return;
};
if(pixel.role == "sulfurTrioxide" && pixel.temp > magmaTempHigh) { //arbitrary choice: leave when the aggregate leaves
changePixel(pixel,"sulfur_trioxide_gas",false);
return;
};
if(pixel.role == "lime" && pixel.temp > 550) {
changePixel(pixel,"slaked_lime",false);
return;
};
if(pixel.role == "silica") {
pixel.didQuartzThermalExpansion ??= false;
if(pixel.temp > 573 && !pixel.didQuartzThermalExpansion) {
if(Math.random() < 0.13) {
changePixel(pixel,"pop",false);
};
pixel.didQuartzThermalExpansion = true;
};
if(pixel.temp > elements.silica.tempHigh) {
changePixel(pixel,"molten_silica",false);
return;
};
};
};
elements.concrete.tick = newConcreteTick;
//Crimson
//Made-up lore: Crimson naturally drives rocks towards a somewhat mafic comp.
elements.crimglass = {
color: ["#d1808d", "#b8a770", "#a4b386"],
behavior: behaviors.WALL,
tempHigh: 1765,
category: "solids",
state: "solid",
density: 2711,
breakInto: "crimglass_shard",
noMix: true,
tick: function(pixel) { crimSpread(pixel) }
};
elements.crimglass_shard = {
color: gravelizeToHex(["#d1808d", "#b8a770", "#a4b386"]),
behavior: behaviors.POWDER,
tempHigh: 1765,
stateHigh: "molten_crimglass",
category: "powders",
state: "solid",
density: 2711 * 0.5,
tick: function(pixel) { crimSpread(pixel) }
};
elements.molten_crimglass = {
tick: function(pixel) { crimSpread(pixel) }
};
elements.crimson_grass = {
color: ["#e82535","#cc471f","#d6153c","#c20e29","#b81a2c"],
behavior: [
"XX|CR:vicious_mushroom%0.01|XX",
"XX|XX|XX",
"XX|M1|XX",
],
tick: function(pixel) {
crimSpread(pixel)
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn:50,
burnTime:20,
category:"life",
state: "solid",
density: 1400,
}
elements.red_ice = {
color: ["#f0ccc5", "#f7d8d2", "#eba39b"],
behavior: behaviors.WALL,
tick: function(pixel) {
crimSpread(pixel)
},
temp: 0,
tempHigh: 5,
stateHigh: "crimwater",
category: "solids",
state: "solid",
density: 917,
breakInto: "crimsnow",
}
elements.crimwater = { //you shouldn't be able to purify ice by melting it
color: "#e45c7c",
behavior: behaviors.LIQUID,
tick: function(pixel) {
crimSpread(pixel)
},
tempLow: 0,
stateLow: "red_ice",
tempHigh: 100,
stateHigh: "steam",
viscosity: 1,
category: "liquids",
reactions: {
"quicklime": { "elem1": null, "elem2": "slaked_lime", },
"ruins": { "elem2": "rock", "chance": 0.00035 },
},
state: "liquid",
density: 997,
conduct: 0.02,
stain: 0.02,
}
elements.crimsnow = { //BIG break from canon but you shouldn't be able to purify ice by grinding it either
color: "#fce1e4",
behavior: behaviors.POWDER,
tick: function(pixel) {
crimSpread(pixel)
},
temp: 0,
tempHigh: 5,
stateHigh: "crimwater",
category: "land",
state: "solid",
density: 100,
}
elements.vicious_mushroom = {
color: "#e36554",
behavior: behaviors.POWDER,
tick: function(pixel) {
crimSpread(pixel)
},
category: "life",
hidden: true,
tempHigh: 225,
stateHigh: "fire",
burn: 10,
burnTime: 65,
state: "solid",
density: 90.445,
};
elements.crimtane_ore = {
color: ["#d83a3b", "#85242c", "#5d5d5d", "#540c14"],
behavior: behaviors.POWDER,
category: "land",
tempHigh: 1552, //using palladium's melting point as an upper bound
stateHigh: ["molten_slag","molten_slag","molten_crimtane"], //:sunglasses: can't turn things into slag if you're already slag
state: "solid",
density: 5854, //arbitrarily chosen, average of ((average of gold and palladium densities) + (crimstone density) + (crimstone density))
};
elements.crimson = {
color: ["#e82535","#cc471f", "#782b2e", "#8c2e26", "#86241d", "#9d2b20"],
tool: crimSpread,
tick: function(pixel) {
getMooreNeighbors(pixel).forEach(crimSpread)
},
hardness: 0.8,
density: 2500,
state: "solid",
tempHigh: 1200,
stateHigh: "ash",
category: "special",
desc: "Spreads the Crimson",
excludeRandom: true
};
elements.crimtane = {
color: ["#fc141e", "#C62A2F", "#903f3f", "#752E2E", "#5a1c1c", "#5B3C3C", "#5c5c5c"],
behavior: behaviors.SOLID,
category: "solids",
tempHigh: 1200, //i want a behaviors.WALL form of crimtane... and I'm letting the game Autogenerate molten_crimtane because I'm going to use it.
//just pretend it got sintered somehow
state: "solid",
hidden: true,
density: 15661,
}
elements.shadewood_tree_branch = {
color: "#677a8f",
behavior: [
"CR:crimson_leaf,shadewood_tree_branch%2|CR:crimson_leaf,crimson_leaf,crimson_leaf,shadewood_tree_branch%2|CR:crimson_leaf,shadewood_tree_branch%2",
"XX|XX|XX",
"XX|XX|XX",
],
tempHigh: 400,
stateHigh: ["fire","sap"],
tempLow: -30,
stateLow: "wood",
category: "solids",
burn: 40,
burnTime: 50,
burnInto: ["sap","ember","charcoal"],
hidden: true,
state: "solid",
density: 1500,
hardness: 0.15,
breakInto: ["sap","sawdust"],
hidden: true,
}
elements.crimson_vine = {
color: "#de3323",
behavior: [
"XX|SP|XX",
"XX|XX|XX",
"XX|CL%1 AND M1|XX",
],
tick: function(pixel) {
crimSpread(pixel)
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 35,
burnTime: 100,
category: "life",
state: "solid",
density: 1050,
}
elements.shadewood = {
color: "#677a8f",
behavior: behaviors.WALL,
tempHigh: 400,
stateHigh: ["ember","charcoal","fire","fire","fire"],
category: "solids",
burn: 5,
burnTime: 300,
burnInto: ["ember","charcoal","fire"],
state: "solid",
hardness: 0.15,
breakInto: "shadewood_sawdust",
density: 930, //used tigerwood
}
elements.shadewood_sapling = {
color: ["#e64029", "#d43b26"],
behavior: [
"XX|M2%2|XX",
"XX|L2:shadewood,shadewood_tree_branch%80|XX",
"XX|M1|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 65,
burnTime: 15,
category: "life",
state: "solid",
density: 1500,
}
elements.shadewood_sawdust = {
color: ["#95abcf","#8190a3"],
behavior: behaviors.POWDER,
tempHigh: 400,
stateHigh: "fire",
category: "powders",
burn: 25,
burnTime: 150,
burnInto: ["ash","fire","fire","fire"],
state: "solid",
density: 493,
hidden: true,
}
elements.crimson_leaf = {
color: "#de3323",
behavior: behaviors.WALL,
category:"life",
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -1.66,
stateLow: "frozen_plant",
burn:65,
burnTime:60,
burnInto: "dead_plant",
state: "solid",
density: 500,
hidden: true,
}
elements.ichor = {
color: ["#ffec70", "#ffcb52"],
behavior: behaviors.LIQUID,
reactions: {
"head": { "elem2":"meat" }, //sb has no defense to reduce so i just made it deadly (as in greek mythology)
"body": { "elem2":"meat" },
},
category: "liquids",
viscosity: 1,
state: "liquid",
density: 1010,
stain: 0.02,
}
elements.vicious_goldfish = {
color: "#e64230",
behavior: [
"SW:"+eLists.WHL+",blood%2|M2%5 AND SW:"+eLists.WHL+",blood%1|XX", //this is where M3 would have been useful
"SW:"+eLists.WHL+",blood%40|FX%0.01|BO%1", //i have no idea what i'm doing
"SW:"+eLists.WHL+",blood%2 AND M2|M1|XX",
],
reactions: {
"algae": { "elem2":null, chance:0.5 },
"plant": { "elem2":null, chance:0.125 },
"fly": { "elem2":null, chance:0.5 },
"firefly": { "elem2":null, chance:0.5 },
"worm": { "elem2":null, chance:0.25 },
"head": { "elem2":[null,"blood"], chance:0.25 },
"body": { "elem2":[null,"blood"], chance:0.25 },
"oxygen": { "elem2":"carbon_dioxide", chance:0.5 },
},
tick: function(pixel) {
pixel.color = pixelColorPick(pixel)
},
temp: 20,
tempHigh: 42,
stateHigh: "meat",
tempLow: -20,
stateLow: "frozen_meat",
category:"life",
burn:40,
burnTime:100,
state: "solid",
density: 1080,
conduct: 0.2,
}
elements.crimsand = {
color: ["#4c4c44", "#6c645c", "#5c544c", "#847c6c", "#24241c", "#4c4c44", "#6c645c", "#5c544c", "#847c6c", "#24241c", "#3c140c", "#842c24"],
behavior: behaviors.POWDER,
tempHigh: 1765,
stateHigh: "molten_crimson_glass",
category: "sand",
state: "solid",
density: 1602,
_data: ["crimson","crystalline","sand"],
tick: function(pixel) { crimSpread(pixel) }
}
elements.wet_crimsand = {
color: sandizeToHex("crimsand","w"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"crimsand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_crimsand",
tempLow: -50,
stateLow:"packed_crimsand",
density: elements.crimsand.density * 0.595 + 150,
_data: ["crimson","crystalline","wet_particulate"],
nellfireImmune: true,
tick: function(pixel) { crimSpread(pixel) }
};
elements.packed_crimsand = {
color: sandizeToHex("crimsand","p"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: 1911,
stateHigh: "crimglass",
density: elements.crimsand.density * 0.59,
breakInto: "nellsand",
_data: ["nellish","crystalline","packed_particulate"],
nellfireImmune: true,
tick: function(pixel) { crimSpread(pixel) }
};
function newDirtType(names,dirtColor,density,meltingPoint,frostingPoint) {
if(!(dirtColor instanceof Array)) { dirtColor = [dirtColor] };
var mudColor = dirtColor.map(x => colorToHsl(x,"json")); mudColor.forEach(function(x) { x.s *= (41/21); x.l *= (15/26) }); mudColor = mudColor.map(function(x) { return hslToHex(...Object.values(x)) });
if(mudColor.length == 1) { mudColor = mudColor[0] };
var mudstoneColor = dirtColor.map(x => colorToHsl(x,"json")); mudstoneColor.forEach(function(x) { x.h += 6; x.s *= (31/41); if(x.s > 0) { x.s += 5 }; x.l *= (22/15); x.l = bound(x.l + 5,0,60) }); mudstoneColor = mudstoneColor.map(function(x) { return hslToHex(...Object.values(x)) });
if(mudstoneColor.length == 1) { mudstoneColor = mudstoneColor[0] };
var dryDirtColor = dirtColor.map(x => colorToHsl(x,"json")); dryDirtColor.forEach(function(x) { x.h += 4; x.s *= (8/11); x.l *= (34/50); x.l += 5 }); dryDirtColor = dryDirtColor.map(function(x) {
x = convertHslObjects(x,"rgbjson");
x.r += 10;
x.g += 5; //XG??!?!??!?!?!??!?!!??!?!?!?!??!?!?!?!/1/1/1?!/!?!?1?1??!/!1//!
x.b -= 10;
x.g *= 0.94;
x.b *= 0.88;
return convertColorFormats(x,"hex");
});
if(dryDirtColor.length == 1) { dryDirtColor = dryDirtColor[0] };
var permafrostColor = dirtColor.map(x => colorToHsl(x,"json")); permafrostColor.forEach(function(x) { x.h -= 6; x.s *= (3/5); x.l -= 3 }); permafrostColor = permafrostColor.map(function(x) { return hslToHex(...Object.values(x)) });
if(permafrostColor.length == 1) { permafrostColor = permafrostColor[0] };
var dryPermafrostColor = dirtColor.map(x => colorToHsl(x,"json")); dryPermafrostColor.forEach(function(x) { x.h -= 6; x.s *= (3/5); x.s -= 5; x.l += 2 }); dryPermafrostColor = dryPermafrostColor.map(function(x) { return hslToHex(...Object.values(x)) });
if(dryPermafrostColor.length == 1) { dryPermafrostColor = permafrostColor[0] };
//names should b an obj w keys dirt,mud,mudstone,permafrost
elements[names.dirt] = {
color: dirtColor,
behavior: behaviors.POWDER,
tempHigh: 100,
stateHigh: "dry_" + names.dirt,
tempLow: frostingPoint,
forceAutoGen: true,
stateLow: names.permafrost,
category:"land",
state: "solid",
density: density
};
elements["dry_" + names.dirt] = {
color: dryDirtColor,
behavior: behaviors.POWDER,
tempHigh: meltingPoint,
stateHigh: "molten_" + names.dirt,
tempLow: frostingPoint,
stateLow: "dry_" + names.permafrost,
forceAutoGen: true,
stateLow: names.permafrost,
category:"land",
state: "solid",
density: density
};
elements[names.mud] = {
color: mudColor,
behavior: behaviors.STURDYPOWDER,
reactions: {
"dirt": { elem1:names.dirt, elem2:"mud", chance:0.0005, oneway:true },
["dry_" + names.dirt]: { elem1:names.dirt, elem2: ["dry_" + names.dirt], chance:0.0005, oneway:true },
"sand": { elem1:names.mud, elem2:"wet_sand", chance:0.0005, oneway:true },
"sawdust": { elem1:"mulch", "elem2":null },
"evergreen": { elem1:"mulch", "elem2":null },
},
tempHigh: 100,
stateHigh: names.mudstone,
tempLow: frostingPoint,
stateLow: names.permafrost,
category: "land",
state: "solid",
density: density * (17/12),
stain: 0.02
};
elements[names.mudstone] = {
color: mudstoneColor,
behavior: behaviors.SUPPORT,
tempHigh: meltingPoint,
stateHigh: "molten_" + names.dirt,
tempLow: frostingPoint,
stateLow: names.permafrost,
category: "land",
state: "solid",
density: density * 1.2,
breakInto: "dirt"
};
elements[names.permafrost] = {
color: permafrostColor,
behavior: behaviors.SUPPORT,
temp: frostingPoint - 20,
tempHigh: frostingPoint,
stateHigh: names.mud,
category: "land",
state: "solid",
density: density / 1.7
};
elements["dry_" + names.permafrost] = {
color: dryPermafrostColor,
behavior: behaviors.POWDER,
temp: frostingPoint - 20,
tempHigh: 0,
stateHigh: "dry_" + names.dirt,
category: "land",
state: "solid",
density: density
};
elements.water.reactions[names.dirt] = { elem1: null, elem2: names.mud };
elements.water.reactions["dry_" + names.dirt] = { elem1: null, elem2: names.dirt, chance: 0.005 };
elements.mud.reactions["dry_" + names.dirt] = { elem1: "dirt", elem2: names.dirt, chance: 0.005 };
};
newDirtType(
{dirt: "crimsoil", mud: "crimmud", permafrost: "crimson_permafrost", mudstone: "crimmudstone"},
["#782b2e", "#8c2e26", "#86241d", "#9d2b20", "#632f52"],
1260, 903, -70
);
elements.mud._data = ["loam","soil","wet_particulate"];
elements.mudstone._data = ["loam","soil","packed_particulate"];
elements.permafrost._data = ["loam","soil","icy_particulate"];
elements.crimsoil._data = ["crimson","soil","particulate"];
elements.dry_crimsoil._data = ["crimson","soil","particulate"];
elements.crimmud._data = ["crimson","soil","wet_particulate"];
elements.crimmudstone._data = ["crimson","soil","packed_particulate"];
elements.crimson_permafrost._data = ["crimson","soil","icy_particulate"];
elements.dry_crimson_permafrost._data = ["crimson","soil","particulate"];
makeNonSandSedimentationElements("crimsand","crimsandy_water","crimsandstone");
newIgneousCompositionFamily(
"crimson",
13000, 2420, -76, -17, 2877,
"crimstone", ["#cb4444", "#953333", "#611c1c", "#b43434", "#752424"], 1223, 4234,
"metacrimstone", ["#b31010","#8f1111","#80282a","#b31010","#8f1111","#80282a","#bb4e45"], 1223, 4544,
"crimsalt", ["#9e5041", "#a33345"], 1151, 3226,
"metacrimsalt", ["#ab5c4f","#c25c4c","#cf4452"], 1151, 3044,
"crimscoria", ["#914c57", "#ba7b85", "#6b2e38", "#b3626f"], 1032, 2903,
"metacrimscoria", ["#bf2636","#961b12","#b84040"], 1032, 3534,
"crimidian", ["#5a1b1c", "#622b33", "#762733", "#76322c"], 1122, 3050,
"metacrimidian", ["#701b1c","#783628","#802419","#872323"], 1122, 3169,
3,7
);
elements.crimsalt.behavior = behaviors.STURDYPOWDER;
elements.metacrimsalt.behavior = behaviors.STURDYPOWDER;
elements.crimson_magma.temp = elements.crimson_magma.tempHigh * 0.8;
//var elems2 = Object.keys(elements);
//var deltaElems = elems2.filter(function(name) { return !(elems1.includes(name)) });
runAfterLoad(function() { runAfterAutogen(function() { runAfterAutogen(function() { //i need this to happen last
var rockCrimmies = Object.keys(elements).filter(function(name) {return (name.match(/((wet|packed|hot|vaporized)_|meta|)crim/) && !(name.match(/crimtane/)))});
lifeEaterWhitelist = lifeEaterWhitelist.concat(rockCrimmies); //crimson is alive, so LEV should eat it
rockCrimmies.forEach(function(name) {
var data = elements[name];
if(data.tick) {
var oldTick = data.tick;
data.tick = function(pixel) {
oldTick(pixel);
if(pixel && !isEmpty(pixel.x,pixel.y)) {
crimSpread(pixel);
}
}
} else {
data.tick = function(pixel) { crimSpread(pixel) }
};
});
for(var key in elements) {
var data = elements[key];
if(!(elements[key].tick)) { continue };
if(elements[key].tick.toString().includes("crimSpread")) {
data.excludeRandom = true
}
};
})})});
elements.molten_crimsoil = {
tempLow: elements.dry_crimsoil.tempHigh,
stateLow: "dry_crimsoil",
stateHigh: "crimson_magma"
};
crimsonObject.dirt = "crimsoil";
crimsonObject.dry_dirt = "dry_crimsoil";
crimsonObject.mud = "crimmud";
crimsonObject.mudstone = "crimmudstone";
crimsonObject.permafrost = "crimson_permafrost";
crimsonObject.molten_dirt = "molten_crimsoil";
crimsonObject.dry_permafrost = "dry_crimson_permafrost";
runAfterLoad(function() {
elements.molten_crimsoil.tempHigh = elements.crimson_magma.tempHigh;
elements.crimsandy_water.color = ["#985460", "#a8606c", "#a05864", "#b46c74", "#84404c", "#985460", "#a8606c", "#a05864", "#b46c74", "#84404c", "#903844", "#b44450" ] //manual: use crimwater for the lerp in crimsand suspension's color
elements.crimmuddy_water.color = ["#ed4154", "#f25259", "#f2444c", "#f25a62", "#df428d" ]; //same for crimsoil (crimmud) susp.
elements.crimwater.reactions.crimsand = elements.water.reactions.crimsand;
elements.crimwater.reactions.crimmud = elements.water.reactions.crimmud;
for(var k in elements.crimsandy_water.reactions) {
var reactionObject = elements.crimsandy_water.reactions[k];
var e1 = reactionObject.elem1; var e2 = reactionObject.elem2;
if(e1 == "water") { reactionObject.elem1 = "crimwater" };
if(e2 == "water") { reactionObject.elem2 = "crimwater" };
};
for(var k in elements.crimmuddy_water.reactions) {
var reactionObject = elements.crimmuddy_water.reactions[k];
var e1 = reactionObject.elem1; var e2 = reactionObject.elem2;
if(e1 == "water") { reactionObject.elem1 = "crimwater" };
if(e2 == "water") { reactionObject.elem2 = "crimwater" };
};
elements.crimmuddy_water.reactions.crimmuddy_water.elem2 = "crimsoil_sediment";
elements.rainbow_muddy_water.reactions.rainbow_muddy_water.elem2 = "rainbow_soil_sediment"
elements.crimsoilstone.tempHigh = 800;
});
//Blackpinkinitic (why? because FU. that's why. jk lol it's because i want to test metamorphism but there's so little data on the melting of metamorphic rocks--especially clay-based ones--that it's proving to be a real PITA.
newIgneousCompositionFamily(
"blackpinkinitic",
403, 2602, -95, -30, 4007,
"blinkinite", ["#e39dc6", "#e378b7", "#d1589f", "#a1306e", "#6e274e", "#170e13", "#121212"], 1821, 3291,
"lisaslate", ["#f26fbc", "#f26fbc", "#e344a1", "#d42686", "#b52daa", "#8a3683", "#5c324f", "#572c6e", "#421530", "#120c10", "#120c10"], 1821, 3333,
"roselite", ["#eda4c6","#de90ae","#cf9db0","#cf9db0","#d97ca0"], 1715, 2551,
"rosephyllite", ["#e895bb", "#c46286", "#a34b73", "#6e2e4b", "#301921", "#1a1315"], 1715, 3021,
"jisoovesite", ["#bf56af", "#a15495", "#70416f", "#e87de6", "#381a47"], 1977, 719,
"vesimelite", ["#a35097", "#854e72", "#8a5789", "#d47dd2", "#462452"], 1977, 1132,
"jennitrite", ["#8a2966", "#801357", "#75074c", "#4a012f", "#360e27", "#1a0e15"], 2111, 2603,
"harmonitrite", ["#9e3979", "#9e186c", "#a3146e", "#380324", "#2e1028", "#361a2a"], 2111, 2663,
3,7
);
elements.roselite.name = elements.roselite.alias = "rosélite";
elements.rosephyllite.colorPattern = [ // diagonal foliation
"PPppDDddBBbbBBddDDpp",
"ppDDddBBbbBBddDDppPP",
"DDddBBbbBBddDDppPPpp",
"ddBBbbBBddDDppPPppDD",
"BBbbBBddDDppPPppDDdd",
"bbBBddDDppPPppDDddBB",
"BBddDDppPPppDDddBBbb",
"ddDDppPPppDDddBBbbBB",
"DDppPPppDDddBBbbBBdd",
"ppPPppDDddBBbbBBddDD"
];
elements.rosephyllite.colorKey = {
"P": "#e895bb",
"p": "#c46286",
"D": "#a34b73",
"d": "#6e2e4b",
"B": "#301921",
"b": "#1a1315"
};
elements.blinkinite.behavior = behaviors.POWDER;
elements.rosephyllite.name = elements.rosephyllite.alias = "roséphyllite";
elements.jisoovesite.grain = 2;
//Rainbow (actually let's call them Iridian)
//Required manual elements
elements.rainbow_glass = {
color: makeRegularRainbow(12,100,70,"hex"),
behavior: behaviors.WALL,
tempHigh: 1765,
category: "solids",
state: "solid",
density: 2711,
breakInto: "rainbow_glass_shard",
noMix: true,
nellfireImmune: true,
};
elements.rainbow_glass_shard = {
color: makeRegularRainbow(18,70,65,"hex"),
behavior: behaviors.POWDER,
tempHigh: 1784,
stateHigh: "molten_rainbow_glass",
category: "powders",
state: "solid",
density: 2213,
nellfireImmune: true,
};
elements.rainbow_sand = {
color: makeRegularRainbow(7,100,94,"hex").concat("#fbfbfb"),
behavior: behaviors.POWDER,
tempHigh: 1731,
stateHigh: "molten_rainbow_glass",
category: "land",
state: "solid",
density: 1733,
_data: ["iridian","crystalline","particulate"],
nellfireImmune: true,
};
elements.wet_rainbow_sand = {
color: makeRegularRainbow(7,100,84,"hex").concat("#e0e0e0"),
behavior: behaviors.STURDYPOWDER,
category: "land",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_rainbow_sand",
tempLow: -50,
stateLow:"packed_rainbow_sand",
density: 1733 * 0.595 + 150,
_data: ["iridian","crystalline","wet_particulate"],
nellfireImmune: true,
};
elements.packed_rainbow_sand = {
color: makeRegularRainbow(7,70,86,"hex").concat("#dbdbdb"),
behavior: behaviors.SUPPORT,
category: "land",
state: "solid",
tempHigh: 1731,
stateHigh: "rainbow_glass",
density: 1733 * 0.59,
breakInto: "rainbow_sand",
_data: ["iridian","crystalline","packed_particulate"],
nellfireImmune: true,
};
newDirtType(
{dirt: "rainbow_dirt", mud: "rainbow_mud", permafrost: "rainbow_permafrost", mudstone: "rainbow_mudstone"},
"#b09eac #b0bfa1 #d9c0b6 #b09eac #b0bfa1 #d9c0b6 #ed7777 #a7d975 #7bd4d4 #ab77e0 #e0cf77".split(" "),
1533, 942, -110
);
elements.rainbow_dirt._data = ["iridian","soil","particulate"];
elements.dry_rainbow_dirt._data = ["iridian","soil","particulate"];
elements.rainbow_mud._data = ["iridian","soil","wet_particulate"];
elements.rainbow_mudstone._data = ["iridian","soil","packed_particulate"];
elements.rainbow_permafrost._data = ["iridian","soil","icy_particulate"];
elements.dry_rainbow_permafrost._data = ["iridian","soil","particulate"];
elements.molten_rainbow_dirt = {
tempLow: elements.dry_rainbow_dirt.tempHigh,
stateLow: "dry_rainbow_dirt",
stateHigh: "rainbow_magma"
};
runAfterLoad(function() {
elements.rainbow_soilstone.tempHigh = 800;
elements.molten_rainbow_dirt.tempHigh = elements.rainbow_magma.tempHigh;
});
//Vanilla changes
elements.water.reactions.rainbow_sand = { elem1: null, elem2: "wet_rainbow_sand" };
elements.water.reactions.wet_rainbow_sand = { "elem1": "rainbow_sand_water", "elem2": [ "rainbow_sand", "rainbow_sand", "rainbow_sand", "rainbow_sand_water" ], "chance": 0.01 };
//Actual rock generation
//Sedimentary
makeNonSandSedimentationElements("rainbow_sand","rainbow_sand_water","rainbow_sandstone");
elements.rainbow_sandstone.color = makeRegularRainbow(14,90,71,"hex").concat("#b5b5b5");
//Igneous
newIgneousCompositionFamily(
"rainbow",
133487, 5512, -71, -17, 4555,
"phirite", makeRegularRainbow(6,70,45,"hex"), 1671, 4004,
"metaphirite", makeRegularRainbow(7,60,35,"hex"), 1671, 4244,
"aphirite", makeRegularRainbow(24,63,75,"hex").concat("#bfbfbf"), 1685, 3951,
"metaaphirite", makeRegularRainbow(23,83,65,"hex").concat("#afafaf"), 1685, 4191,
"vesirite", makeRegularRainbow(7,55,30,"hex").concat(makeRegularRainbow(7,75,70,"hex")), 1712, 2918,
"metavesirite", makeRegularRainbow(5,66,80,"hex").concat(makeRegularRainbow(5,56,60,"hex")), 1712, 3118,
"vitirite", makeRegularRainbow(30,70,35,"hex").concat("#595959"), 2054, 3741,
"metavitirite", makeRegularRainbow(15,60,45,"hex").concat("#494949").concat(makeRegularRainbow(15,60,55,"hex")).concat("#797979"), 2054, 3941,
3,7
);
//Nellfire immunization
var immunes = ["rainbow_sand_water", "rainbow_sand_sediment", "rainbow_sandstone", "phirite", "phirite_wall", "phirite_gravel", "aphirite", "aphirite_wall", "phirite_sand", "wet_phirite_sand", "packed_phirite_sand", "aphirite_gravel", "aphirite_sand", "wet_aphirite_sand", "packed_aphirite_sand", "vesirite", "vesirite_wall", "vesirite_gravel", "vesirite_sand", "wet_vesirite_sand", "packed_vesirite_sand", "vitirite", "vitirite_wall", "vitirite_shard", "vitirite_sand", "wet_vitirite_sand", "packed_vitirite_sand", "rainbow_magma", "vaporized_rainbow_magma", "rainbow_magma_cloud", "phirite_sandy_water", "phirite_sand_sediment", "phirite_sandstone", "aphirite_sandy_water", "aphirite_sand_sediment", "aphirite_sandstone", "vesirite_sandy_water", "vesirite_sand_sediment", "vesirite_sandstone", "vitirite_sandy_water", "vitirite_sand_sediment", "vitirite_sandstone", "phirite_dust", "aphirite_dust", "vesirite_dust", "vitirite_dust" ];
runAfterLoad(function() {
for(i = 0; i < immunes.length; i++) {
if(!elements[immunes[i]]) {
console.error(immunes[i]);
continue;
}
elements[immunes[i]].nellfireImmune = true;
};
});
//Nellish
//Manuals
elements.nellglass = {
color: ["#a161b0", "#b06177", "#b59159"],
behavior: behaviors.WALL,
tempHigh: 1765,
category: "solids",
state: "solid",
density: 5012,
breakInto: "nellglass_shard",
noMix: true,
nellfireImmune: true,
};
elements.nellglass_shard = {
color: ["#7d5f8c","#875966","#9e7b47"],
behavior: behaviors.POWDER,
tempHigh: 1765,
stateHigh: "molten_nellglass",
category: "powders",
state: "solid",
density: 4212,
nellfireImmune: true,
};
elements.nellsand = {
color: ["#906fa8", "#80747a", "#b08464"],
behavior: behaviors.POWDER,
tempHigh: 1911,
stateHigh: "molten_nellglass",
category: "sand",
state: "solid",
density: 3742,
_data: ["nellish","crystalline","particulate"],
nellfireImmune: true,
};
elements.water.reactions.nellsand = { elem1: null, elem2: "wet_nellsand" };
elements.water.reactions.wet_nellsand = { "elem1": "nellsand_water", "elem2": [ "nellsand", "nellsand", "nellsand", "nellsand_water" ], "chance": 0.01 };
elements.wet_nellsand = {
color: sandizeToHex("nellsand","w"),
behavior: behaviors.STURDYPOWDER,
category: "wet sand",
reactions: {
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
state: "solid",
tempHigh: 100,
stateHigh: "packed_nellsand",
tempLow: -50,
stateLow:"packed_nellsand",
density: 3742 * 0.595 + 150,
_data: ["nellish","crystalline","wet_particulate"],
nellfireImmune: true,
};
elements.packed_nellsand = {
color: sandizeToHex("nellsand","p"),
behavior: behaviors.SUPPORT,
category: "packed sand",
state: "solid",
tempHigh: 1911,
stateHigh: "nellglass",
density: 3742 * 0.59,
breakInto: "nellsand",
_data: ["nellish","crystalline","packed_particulate"],
nellfireImmune: true,
};
nellburnObject = {
"dirt": "nellsand",
"dry_dirt": "nellsand",
"mud": "wet_nellsand",
"mudstone": "packed_nellsand",
"brass": ["nell_ash","zinc"],
"thermite": ["nell_ash","zinc"],
"rose_gold": ["nell_ash","gold"],
"electrum": ["nell_ash","gold"],
"molten_brass": ["nell_ash","molten_zinc"],
"molten_thermite": ["nell_ash","molten_zinc"],
"molten_rose_gold": ["nell_ash","molten_gold"],
"molten_electrum": ["nell_ash","molten_gold"],
"sun": "nellsun",
};
var otherImmunes = ["fire","smoke","plasma","cold_fire","radiation","light","proton","neutron","electron","positron","antimatter","cold_smoke","rad_fire","rad_smoke","laser","liquid_fire","liquid_smoke","liquid_plasma","liquid_cold_fire","liquid_cold_smoke","liquid_rad_fire","liquid_rad_fire","liquid_rad_smoke","le_liquid_light","liquid_laser","pure_ice","pure_water","pure_steam","magic","gold","zinc","molten_gold","molten_zinc","pyreite","infernium","molten_pyreite","molten_infernium","infernyrite","molten_infernyrite","infernyreitheum","molten_infernyreitheum","pyrinfernyreitheum","molten_pyrinfernyreitheum","stellar_plasma","liquid_stellar_plasma","hydrogen","liquid_hydrogen","hydrogen_ice","neutronium","molten_neutronium","liquid_neutronium","neutronium_gas","liquid_degenerate_neutronium","gaseous_degenerate_neutronium"].concat(["water","ice","slush","snow","packed_snow","steam", "heavy_steam","heavy_water","heavy_ice","heavy_snow", "hydrogen_ice","liquid_hydrogen","hydrogen","ionized_hydrogen", "liquid_helium","helium","ionized_helium", "tralphium","liquid_tralphium","ionized_tralphium", "carbon","charcoal","diamond","molten_carbon", "carbon_monoxide","liquid_carbon_monoxide","carbon_monoxide_ice", "carbon_dioxide","dry_ice","seltzer","seltzer_ice","foam","cloud","rain_cloud","snow","snow_cloud","snow_cloud_floater","ice","thunder_cloud","hail_cloud"]);
for(let i = 0; i < otherImmunes.length; i++) {
var element = otherImmunes[i];
if(elements[element]) { elements[element].nellfireImmune = true };
};
elements.nell_ash = {
color: ["#ab9393","#947873"],
behavior: behaviors.POWDER,
/*reactions: {
"steam": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"rain_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"snow_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"hail_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"acid_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,12], "setting":"clouds" },
"pyrocumulus": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,12], "setting":"clouds" },
"stench": { "elem2":null, "chance":0.1 }
},*/
category:"powders",
state: "solid",
nellfireImmune: true,
tick: function(pixel) {
if(Math.random() < 0.01 && pixel.temp < 25) {
pixel.temp++;
};
},
density: 810,
//tempHigh: 2000,
//forceAutoGen: true,
//stateHigh: ["molten_ash","smoke","smoke","smoke"]
};
elements.wall.nellfireImmune = true;
//Massive block of code that programatically assigns nellburn results to rocks based on their properties
runAfterLoad(function() {
var rockdataElements = Object.keys(elements).filter(function(name) {
return (
elements[name]._data &&
!["blackened_carbonate","nellish","nellsand_material"].includes(elements[name]._data[0])
)
});
for(i = 0; i < rockdataElements.length; i++) {
var name = rockdataElements[i];
var info = elements[name];
switch(info._data[1]) {
case "phanerite":
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "gehennite"
break;
case "solid_igneous_rock":
nellburnObject[name] = "gehennite_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "gehennite_gravel"
break;
case "particulate":
nellburnObject[name] = "gehennite_sand"
break;
case "dust":
nellburnObject[name] = "gehennite_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_gehennite_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_gehennite_sand"
break;
case "sediment":
nellburnObject[name] = "gehennite_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "gehennite_sandy_water"
break;
};
break;
case "aphanite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "nellrock"
break;
case "solid_igneous_rock":
nellburnObject[name] = "nellrock_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "nellrock_gravel"
break;
case "particulate":
nellburnObject[name] = "nellrock_sand"
break;
case "dust":
nellburnObject[name] = "nellrock_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_nellrock_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_nellrock_sand"
break;
case "sediment":
nellburnObject[name] = "nellrock_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "nellrock_sandy_water"
break;
};
break;
case "vesiculite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "hadean_sponge"
break;
case "solid_igneous_rock":
nellburnObject[name] = "hadean_sponge_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "hadean_sponge_gravel"
break;
case "particulate":
nellburnObject[name] = "hadean_sponge_sand"
break;
case "dust":
nellburnObject[name] = "hadean_sponge_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_hadean_sponge_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_hadean_sponge_sand"
break;
case "sediment":
nellburnObject[name] = "hadean_sponge_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "hadean_sponge_sandy_water"
break;
};
break;
case "vitrite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "gehidian"
break;
case "solid_igneous_rock":
nellburnObject[name] = "gehidian_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "gehidian_gravel"
break;
case "particulate":
nellburnObject[name] = "gehidian_sand"
break;
case "dust":
nellburnObject[name] = "gehidian_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_gehidian_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_gehidian_sand"
break;
case "sediment":
nellburnObject[name] = "gehidian_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "gehidian_sandy_water"
break;
};
break;
case "metaphanerite":
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "sheolite"
break;
case "solid_igneous_rock":
nellburnObject[name] = "sheolite_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "sheolite_gravel"
break;
case "particulate":
nellburnObject[name] = "sheolite_sand"
break;
case "dust":
nellburnObject[name] = "sheolite_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_sheolite_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_sheolite_sand"
break;
case "sediment":
nellburnObject[name] = "sheolite_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "sheolite_sandy_water"
break;
};
break;
case "metaaphanite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "nellbolite"
break;
case "solid_igneous_rock":
nellburnObject[name] = "nellbolite_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "nellbolite_gravel"
break;
case "particulate":
nellburnObject[name] = "nellbolite_sand"
break;
case "dust":
nellburnObject[name] = "nellbolite_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_nellbolite_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_nellbolite_sand"
break;
case "sediment":
nellburnObject[name] = "nellbolite_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "nellbolite_sandy_water"
break;
};
break;
case "metavesiculite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "metahadiculite"
break;
case "solid_igneous_rock":
nellburnObject[name] = "metahadiculite_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "metahadiculite_gravel"
break;
case "particulate":
nellburnObject[name] = "metahadiculite_sand"
break;
case "dust":
nellburnObject[name] = "metahadiculite_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_metahadiculite_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_metahadiculite_sand"
break;
case "sediment":
nellburnObject[name] = "metahadiculite_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "metahadiculite_sandy_water"
break;
};
break;
case "metavitrite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
nellburnObject[name] = "metagehitrite"
break;
case "solid_igneous_rock":
nellburnObject[name] = "metagehitrite_wall"
break;
case "igneous_gravel":
nellburnObject[name] = "metagehitrite_gravel"
break;
case "particulate":
nellburnObject[name] = "metagehitrite_sand"
break;
case "dust":
nellburnObject[name] = "metagehitrite_dust"
break;
case "wet_particulate":
nellburnObject[name] = "wet_metagehitrite_sand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_metagehitrite_sand"
break;
case "sediment":
nellburnObject[name] = "metagehitrite_sand_sediment"
break;
case "suspension":
nellburnObject[name] = "metagehitrite_sandy_water"
break;
};
break;
case "phanerite_sandstone":
nellburnObject[name] = "gehennite_sandstone"
break;
case "aphanite_sandstone":
nellburnObject[name] = "nellrock_sandstone"
break;
case "vesiculite_sandstone":
nellburnObject[name] = "hadean_sponge_sandstone"
break;
case "vitrite_sandstone":
nellburnObject[name] = "gehidian_sandstone"
break;
case "metaphanerite_sandstone":
nellburnObject[name] = "sheolite_sandstone"
break;
case "metaaphanite_sandstone":
nellburnObject[name] = "nellbolite_sandstone"
break;
case "metavesiculite_sandstone":
nellburnObject[name] = "metahadiculite_sandstone"
break;
case "metavitrite_sandstone":
nellburnObject[name] = "metagehitrite_sandstone"
break;
case "silica_sandstone":
nellburnObject[name] = "nellsandstone"
break;
case "magma":
switch(info._data[2]) {
case "liquid":
nellburnObject[name] = "nellish_magma"
break;
case "vaporized":
nellburnObject[name] = "vaporized_nellish_magma"
break;
case "cloud":
nellburnObject[name] = "nellish_magma_cloud"
break;
};
break;
case "rock":
switch(name) {
case "shale":
nellburnObject[name] = "nellsandstone"
break;
case "limestone":
nellburnObject[name] = "black_limestone"
break;
};
break;
case "calcium":
switch(info._data[2]) {
case "particulate":
case "mineral":
nellburnObject[name] = bccd
break;
case "sediment":
nellburnObject[name] = "blackened_calcium_carbonate_dust_sediment"
break;
case "suspension":
nellburnObject[name] = bccs
break;
};
break;
case "silica":
case "crystalline":
switch(info._data[2]) {
case "particulate":
nellburnObject[name] = "nellsand"
break;
case "wet_particulate":
nellburnObject[name] = "wet_nellsand"
break;
case "packed_particulate":
nellburnObject[name] = "packed_nellsand"
break;
case "suspension":
nellburnObject[name] = "nellsand_water"
break;
case "sediment":
nellburnObject[name] = "nellsand_sediment"
break;
};
break;
case "soil":
case "dry_soil":
case "clay":
switch(info._data[2]) {
case "particulate":
nellburnObject[name] = "nellsand"
break;
case "suspension":
nellburnObject[name] = "nellsand_water"
break;
case "sediment":
nellburnObject[name] = "nellsand_sediment"
break;
};
break;
case "crystalline_sandstone":
case "soil_sandstone":
nellburnObject[name] = "nell_ash"
break;
case "sedimentary":
if(info._data[0] == "calcium") {
nellburnObject[name] = "black_limestone";
break
};
default:
console.log("Nellburn assignment: Unknown _data[1] value for element",name,info._data);
};
};
nellfireSpawnBlacklist = ["nellfire"];
});
//Glad that's over
//Rocks
makeNonSandSedimentationElements("nellsand","nellsand_water","nellsandstone");
newIgneousCompositionFamily(
"nellish",
10, 3012, -96, -12, 3812,
"gehennite", ["#857c71", "#b5a98d", "#91847c", "#948b68", "#8a834a", "#adad34"], 2011, 3432,
"sheolite", ["#785848","#8c7e5b","#9c745c","#80463b"], 2011, 3852,
"nellrock", ["#a15a42","#997849","#946043","#8c533e","#a66658"], 2036, 3371,
"nellbolite", ["#7a3017","#693d21","#8a673a"], 2036, 3671,
"hadean_sponge", ["#e66785", "#b54761", "#cc8156", "#dbc760", "#ab9a44"], 2213, 1012,
"metahadiculite", ["#a0a35d","#665d37", "#7b804d", "#869151", "#6e443f"], 2213, 1412,
"gehidian", ["#754c2f", "#855d3a", "#702a1c", "#691a41"], 2054, 3112,
"metagehitrite", ["#5e4f2a","#53544e", "#68787a", "#454f46", "#5e584b"], 2054, 3312,
1,9
);
//More sedimentaries because nellfire also transforms limestone, and the associated baggage
var bccd = "blackened_calcium_carbonate_dust";
var bccs = "blackened_calcium_carbonate_solution";
elements.calcium_carbonate_dust.reactions ??= {};
elements.calcium_carbonate_dust.reactions.charcoal = {
elem1: bccd, elem2: [bccd, "charcoal", "charcoal"]
};
newPowder(bccd,"#948e87",2771,804,["carbon_dioxide","quicklime","charcoal","ash"]);
elements[bccd]._data = ["blackened_carbonate","blackened_carbonate","particulate"];
elements[bccd].nellfireImmune = true;
makeNonSandSedimentationElements(bccd,bccs,"black_limestone");
elements.blackened_calcium_carbonate_dust_sediment.color = "#756e64";
elements.blackened_calcium_carbonate_dust_sediment.nellfireImmune = true;
elements.black_limestone.color = "#575148";
elements.black_limestone.stateHigh = ["fire","smoke","charcoal","carbon_dioxide","quicklime","quicklime","quicklime","quicklime","quicklime","quicklime","quicklime","quicklime"];
elements[bccs].nellfireImmune = true;
elements.water.reactions[bccd] = {
"elem1":"calcium_carbonate_solution",
"elem2":[bccd,bccd,bccd,bccs],
"chance":0.004
};
elements.seltzer.reactions[bccd] = {
"elem1":bccs,
"elem2":[bccd,bccd,bccd,bccs],
"chance":0.02
};
var resultingAutoElems = [ "gehennite", "gehennite_wall", "gehennite_gravel", "nellrock", "nellrock_wall", "gehennite_sand", "gehennite_dust", "wet_gehennite_sand", "packed_gehennite_sand", "nellrock_gravel", "nellrock_sand", "nellrock_dust", "wet_nellrock_sand", "packed_nellrock_sand", "hadean_sponge", "hadean_sponge_wall", "hadean_sponge_gravel", "hadean_sponge_sand", "hadean_sponge_dust", "wet_hadean_sponge_sand", "packed_hadean_sponge_sand", "gehidian", "gehidian_wall", "gehidian_shard", "gehidian_sand", "gehidian_dust", "wet_gehidian_sand", "packed_gehidian_sand", "nellish_magma", "vaporized_nellish_magma", "nellish_magma_cloud", "gehennite_sandy_water", "gehennite_sand_sediment", "gehennite_sandstone", "nellrock_sandy_water", "nellrock_sand_sediment", "nellrock_sandstone", "hadean_sponge_sandy_water", "hadean_sponge_sand_sediment", "hadean_sponge_sandstone", "gehidian_sandy_water", "gehidian_sand_sediment", "gehidian_sandstone", bccd, bccs, "black_limestone" ] //hard-coded
runAfterLoad(function() {
for(i = 0; i < resultingAutoElems.length; i++) {
if(!elements[resultingAutoElems[i]]) {
console.error(resultingAutoElems[i]);
continue;
}
elements[resultingAutoElems[i]].nellfireImmune = true;
};
});
//Crimson transformation assigner
runAfterAutogen(function() {
crimsonAssignmentUnknownData1Errors = {};
var rockdataElements = Object.keys(elements).filter(function(name) {
return (
elements[name]._data &&
!["crimson"].includes(elements[name]._data[0])
)
});
for(i = 0; i < rockdataElements.length; i++) {
var name = rockdataElements[i];
var info = elements[name];
switch(info._data[1]) {
case "phanerite":
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "crimstone"
break;
case "solid_igneous_rock":
crimsonObject[name] = "crimstone_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "crimstone_gravel"
break;
case "particulate":
crimsonObject[name] = "crimstone_sand"
break;
case "dust":
crimsonObject[name] = "crimstone_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_crimstone_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_crimstone_sand"
break;
case "sediment":
crimsonObject[name] = "crimstone_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "crimstone_sandy_water"
break;
};
break;
case "aphanite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "crimsalt"
break;
case "solid_igneous_rock":
crimsonObject[name] = "crimsalt_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "crimsalt_gravel"
break;
case "particulate":
crimsonObject[name] = "crimsalt_sand"
break;
case "dust":
crimsonObject[name] = "crimsalt_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_crimsalt_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_crimsalt_sand"
break;
case "sediment":
crimsonObject[name] = "crimsalt_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "crimsalt_sandy_water"
break;
};
break;
case "vesiculite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "crimscoria"
break;
case "solid_igneous_rock":
crimsonObject[name] = "crimscoria_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "crimscoria_gravel"
break;
case "particulate":
crimsonObject[name] = "crimscoria_sand"
break;
case "dust":
crimsonObject[name] = "crimscoria_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_crimscoria_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_crimscoria_sand"
break;
case "sediment":
crimsonObject[name] = "crimscoria_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "crimscoria_sandy_water"
break;
};
break;
case "vitrite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "crimidian"
break;
case "solid_igneous_rock":
crimsonObject[name] = "crimidian_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "crimidian_gravel"
break;
case "particulate":
crimsonObject[name] = "crimidian_sand"
break;
case "dust":
crimsonObject[name] = "crimidian_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_crimidian_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_crimidian_sand"
break;
case "sediment":
crimsonObject[name] = "crimidian_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "crimidian_sandy_water"
break;
};
break;
case "metaphanerite":
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "metacrimstone"
break;
case "solid_igneous_rock":
crimsonObject[name] = "metacrimstone_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "metacrimstone_gravel"
break;
case "particulate":
crimsonObject[name] = "metacrimstone_sand"
break;
case "dust":
crimsonObject[name] = "metacrimstone_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_metacrimstone_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_metacrimstone_sand"
break;
case "sediment":
crimsonObject[name] = "metacrimstone_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "metacrimstone_sandy_water"
break;
};
break;
case "metaaphanite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "metacrimsalt"
break;
case "solid_igneous_rock":
crimsonObject[name] = "metacrimsalt_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "metacrimsalt_gravel"
break;
case "particulate":
crimsonObject[name] = "metacrimsalt_sand"
break;
case "dust":
crimsonObject[name] = "metacrimsalt_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_metacrimsalt_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_metacrimsalt_sand"
break;
case "sediment":
crimsonObject[name] = "metacrimsalt_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "metacrimsalt_sandy_water"
break;
};
break;
case "metavesiculite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "metacrimscoria"
break;
case "solid_igneous_rock":
crimsonObject[name] = "metacrimscoria_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "metacrimscoria_gravel"
break;
case "particulate":
crimsonObject[name] = "metacrimscoria_sand"
break;
case "dust":
crimsonObject[name] = "metacrimscoria_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_metacrimscoria_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_metacrimscoria_sand"
break;
case "sediment":
crimsonObject[name] = "metacrimscoria_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "metacrimscoria_sandy_water"
break;
};
break;
case "metavitrite":
//console.log(info._data[2]);
switch(info._data[2]) {
case "igneous_rock":
crimsonObject[name] = "metacrimidian"
break;
case "solid_igneous_rock":
crimsonObject[name] = "metacrimidian_wall"
break;
case "igneous_gravel":
crimsonObject[name] = "metacrimidian_gravel"
break;
case "particulate":
crimsonObject[name] = "metacrimidian_sand"
break;
case "dust":
crimsonObject[name] = "metacrimidian_dust"
break;
case "wet_particulate":
crimsonObject[name] = "wet_metacrimidian_sand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_metacrimidian_sand"
break;
case "sediment":
crimsonObject[name] = "metacrimidian_sand_sediment"
break;
case "suspension":
crimsonObject[name] = "metacrimidian_sandy_water"
break;
};
break;
case "phanerite_sandstone":
crimsonObject[name] = "crimstone_sandstone"
break;
case "aphanite_sandstone":
crimsonObject[name] = "crimsalt_sandstone"
break;
case "vesiculite_sandstone":
crimsonObject[name] = "crimscoria_sandstone"
break;
case "vitrite_sandstone":
crimsonObject[name] = "crimidian_sandstone"
break;
case "phanerite_sandstone":
crimsonObject[name] = "metacrimstone_sandstone"
break;
case "aphanite_sandstone":
crimsonObject[name] = "metacrimsalt_sandstone"
break;
case "vesiculite_sandstone":
crimsonObject[name] = "metacrimscoria_sandstone"
break;
case "vitrite_sandstone":
crimsonObject[name] = "metacrimidian_sandstone"
break;
case "crystalline_sandstone":
case "silica_sandstone":
case "sedimentary":
case "rock":
case "sandstone":
case "silica":
crimsonObject[name] = "crimsandstone"
break;
case "soil_sandstone":
crimsonObject[name] = "crimsoilstone"
break;
case "rainbow_soil_sandstone":
crimsonObject[name] = "crimsoilstone"
break;
case "magma":
switch(info._data[2]) {
case "liquid":
crimsonObject[name] = "crimson_magma"
break;
case "vaporized":
crimsonObject[name] = "vaporized_crimson_magma"
break;
case "cloud":
crimsonObject[name] = "crimson_magma_cloud"
break;
};
break;
case "crystalline":
switch(info._data[2]) {
case "particulate":
crimsonObject[name] = "crimsand"
break;
case "wet_particulate":
crimsonObject[name] = "wet_crimsand"
break;
case "packed_particulate":
crimsonObject[name] = "packed_crimsand"
break;
case "suspension":
crimsonObject[name] = "crimsand_water"
break;
case "sediment":
crimsonObject[name] = "crimsand_sediment"
break;
};
break;
case "soil":
case "dry_soil":
case "clay":
switch(info._data[2]) {
case "particulate":
crimsonObject[name] = "crimsand"
break;
case "suspension":
crimsonObject[name] = "crimsand_water"
break;
case "sediment":
crimsonObject[name] = "crimsand_sediment"
break;
};
break;
default:
crimsonAssignmentUnknownData1Errors[name] = info._data;
};
};
//Manual overrides because JavaScript sees the cases and pretends it doesn't know what they mean
crimsonObject.soilstone = "crimsoilstone";
crimsonObject.sandstone = "crimsandstone";
crimsonObject.rosephyllite = "metacrimsalt";
});
//Assigner end
/* //Rocks
//Igneous
//Phaneritic
//Ultramafic: peridotite
var molten_olivine = ["molten_fayalite","molten_forsterite","molten_forsterite"];
//apparently olivine sand exists
elements.olivine_sand = {
color: ['#b5a773', '#b5af78', '#b2b471', '#bab07b', '#b4ae74', '#b4b471', '#b5a970', '#b4b476'],
behavior: behaviors.POWDER,
tempHigh: 1750, //https://www.indiamart.com/olivineindia/olivine-sand.html
stateHigh: molten_olivine,
category: "land",
state: "solid",
density: 1720,
};
elements.wet_olivine_sand = {
color: ["#a08d4b","#918949","999c49","#aa9b50","#8f8743","#adad53","#9d8f48","#838f43"],
behavior: behaviors.STURDYPOWDER,
reactions: {
"sand": { "elem1":"sand", "elem2":"wet_olivine_sand", "chance":0.0005, "oneway":true },
"olivine_sand": { "elem1":"olivine_sand", "elem2":"wet_olivine_sand", "chance":0.0005, "oneway":true },
"dirt": { "elem1":"olivine_sand", "elem2":"mud", "chance":0.0005, "oneway":true },
},
tempHigh: 100,
stateHigh: "packed_olivine_sand",
tempLow: -50,
stateLow: "packed_olivine_sand",
category: "land",
state: "solid",
density: 2002,
};
elements.packed_olivine_sand = {
color: ["#968f64","#969669","#8d9362","#9d996c","#959465","#8f9362","#949061","#909366"],
behavior: behaviors.SUPPORT,
tempHigh: 1700,
stateHigh: molten_olivine,
category: "land",
state: "solid",
density: 1811,
breakInto: "olivine_sand",
};
elements.water.reactions.olivine_sand = { "elem1": null, "elem2": "wet_olivine_sand" };
newPowder("fayalite",["#bf7432","#ad8e3e"],4390,1200,null,null);
newPowder("forsterite","#cccccc",3270,1890,null,null);
elements.molten_forsterite = {
reactions: {
"molten_fayalite": { elem1: "olivine", elem2: ["molten_fayalite","olivine"], tempMax: 1890 },
},
};
elements.olivine = {
color: ["#7fa14f","#7dba52"],
behavior: behaviors.POWDER,
tempHigh: 1890,
stateHigh: molten_olivine,
category: "solids",
state: "solid",
density: 2700,
breakInto: "olivine_shard",
},
newPowder("olivine_shard",["#97ba65","#7a994e","#99d96c","#7cb553"],2811,1890,molten_olivine,null);
*/
//Gems
//There is a mineral classification scheme, but it will take a while to implement if I ever get around to it.
//We're assuming that the crystal structures reform properly because I don't want to have to research and implement refrozen amorphous forms.
//Emerald
elements.emerald = {
color: ["#31e31e", "#88fa5a", "#28d419", "#54e823", "#64f235"],
tempHigh: 1287,
//1: I can't be arsed to find out what happens to emerald in extreme heat. Apparently, neither can anyone else, and Google is useless for this.
//2: So I'm just assuming that the chromium impurities are polite and remain in suspension with the molten beryl.
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2710, //within natural variation
hardness: 0.8, //Mohs scaled to diamond
};
//Amethyst
elements.amethyst = {
color: ["#c569e0", "#bd43e0", "#e37aeb", "#ab2fe0", "#b05bd4", "#9b2cdb"],
tempHigh: 1650,
//1: Gee, another quartz-like...
//2: Like with emerald, I'm trusting the impurities to stay dissolved because I don't exactly have any amethyst laying around to melt.
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2650,
hardness: 0.7,
};
standaloneBrokenFormMaker("iron","scrap",true,"powders","auto","auto","molten_iron",null).hidden = true;
standaloneBrokenFormMaker("chromium","scrap",true,"powders","auto","auto","molten_chromium",null).hidden = true;
standaloneBrokenFormMaker("amethyst","shard",true,"powders","auto","auto","molten_amethyst",["silica","silica","silica","silica","silica","silica","silica","silica","silica","iron_scrap"]).hidden = true;
//Corundum
elements.corundum = {
color: ["#e3e3e3", "#d9d9d9", "#cccccc", "#dbdbdb", "#f2f2f2"],
tempHigh: 2072,
stateHigh: "molten_alumina",
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 4020,
hardness: 0.9,
breakInto: "alumina",
};
elements.molten_titanium ??= {}; elements.molten_titanium.tempHigh = 3287;
elements.molten_iron ??= {}; elements.molten_iron.tempHigh = 2861;
elements.molten_chromium ??= {}; elements.molten_chromium.tempHigh = 2671;
elements.molten_copper ??= {}; elements.molten_copper.tempHigh = 4700;
elements.molten_alumina ??= {};
elements.molten_alumina.tempHigh = 5400;
elements.molten_alumina.state = "liquid";
elements.molten_alumina.autoType = "gas";
elements.molten_alumina.reactions ??= {};
elements.molten_alumina.reactions.iron_scrap = {elem1: "molten_sapphire", elem2: ["molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron",null] };
elements.molten_alumina.reactions.molten_iron = {elem1: "molten_sapphire", elem2: ["molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron",null] };
elements.molten_alumina.reactions.titanium_scrap = {elem1: "molten_sapphire", elem2: ["molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium",null] };
elements.molten_alumina.reactions.molten_titanium = {elem1: "molten_sapphire", elem2: ["molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium","molten_titanium",null] };
elements.molten_alumina.reactions.chromium_scrap = {elem1: "molten_ruby", elem2: ["molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium",null] };
elements.molten_alumina.reactions.molten_chromium = {elem1: "molten_ruby", elem2: ["molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium","molten_chromium",null] };
elements.molten_alumina.stateLow = "corundum";
//Sapphire
elements.sapphire = {
color: ["#2d43e3", "#4d5fe3", "#1f30cc", "#375fdb", "#2d39e3"],
tempHigh: 2040,
//1: You can actually grow corundum-based gems through the Verneuil process
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 3980,
hardness: 0.9,
};
elements.molten_sapphire ??= {}; elements.molten_sapphire.tick = function(pixel) {
if(pixel.temp >= 5040) {
if(Math.random() < 0.005) { //the real proportion of 0.01% is so low that you'd just melt sapphire and get back corundum
changePixel(pixel,Math.random() < 0.5 ? "titanium_gas" : "iron_gas",false)
} else {
changePixel(pixel,"alumina_gas",false)
}
};
};
standaloneBrokenFormMaker("sapphire","shard",true,"powders","auto","auto","molten_sapphire",["corundum","corundum","corundum","corundum","corundum","corundum","corundum","corundum","corundum","iron_scrap","titanium_scrap"]).hidden = true;
//Ruby
elements.ruby = {
//Corundum with different impurities, so I can copy/paste everything but the color
color: ["#ff1222", "#ff4545", "#e30b13", "#fa253b", "#f2120f"],
tempHigh: 2040,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 4010,
hardness: 0.9,
};
elements.molten_ruby ??= {}; elements.molten_ruby.tick = function(pixel) {
if(pixel.temp >= 5040) {
if(Math.random() < 0.02) { //1% also too low
changePixel(pixel,"chromium_gas",false)
} else {
changePixel(pixel,"alumina_gas",false)
}
};
};
standaloneBrokenFormMaker("ruby","shard",true,"powders","auto","auto","molten_sapphire",["corundum","corundum","corundum","corundum","corundum","corundum","corundum","corundum","corundum","chromium_scrap"]).hidden = true;
//Garnet
var garnetDecomposition = ["iron_scrap","spinel"]
elements.garnet = { //Almandine
color: ["#660c20","#a52942","#8d0404","#c3040d"],
tempHigh: 1250,
tick: function(pixel) {
if(pixel.temp >= 950) {
//and fayalite, cristobalite, and cordierite. i was expecting to add 1 mineral, not 3.
var boost = Math.max((pixel.temp - 950),0) / 40000 //rate pulled out of my ass
if(Math.random() < (0.005 + boost)) {
changePixel(pixel,randomChoice(garnetDecomposition),false)
}
}
},
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 4318,
hardness: 0.8,
};
elements.molten_garnet ??= {}; elements.molten_garnet.tick = function(pixel) {
var boost = Math.max((pixel.temp - 1250),0) / 40000
if(Math.random() < 0.0125 + boost) {
changePixel(pixel,randomChoice(garnetDecomposition),false);
pixelTempCheck(pixel)
}
}
standaloneBrokenFormMaker("garnet","shard",true,"powders","auto","auto","molten_garnet",null).hidden = true;
elements.garnet_shard.tick = elements.garnet.tick
//Spinel (kek)
elements.spinel = {
color: ["#ff1261", "#db2776", "#f20732", "#f71670", "#f7167f"],
tempHigh: 2130,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 3600,
hardness: 0.85,
}
elements.molten_spinel = {
tempHigh: 2977, //The real boiling point is not known, so using corundum
}
//Topaz
elements.topaz = {
color: ["#f7f431", "#ffff5c", "#f7e048", "#fae43e", "#fff86e", "#ede321"],
tempHigh: 1340,
stateHigh: "mullite", //thermal decomposition
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 3500,
hardness: 0.8,
};
//Mullite
elements.mullite = {
color: ["#f2d7bf", "#f5cbdc", "#f2dfd3"], //hardly a gemstone, but i will color it like the others regardless
tempHigh: 1840,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 3110,
hardness: 0.7,
};
//Onyx
elements.onyx = {
color: ["#1a1919", "#070605", "#111313"],
tempHigh: 1650, //another silicate mineral
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2650,
hardness: 0.7,
};
//Zircon
blueZirconColors = ["#017cbc","#146ea0","#17b6c9","#3bbfd3"];
goldenZirconColors = ["#e99209","#fcb111","#d88208","#b97605"];
//heatTreated 0 = untreated, 1 = inertly (blue), 2 = with oxygen (golden)
elements.zircon = {
color: ["#37130b","#a9301a","#3c1810"],
properties: {
heatTreated: 0
},
tick: function(pixel) {
pixel.heatTreated ??= 0;
if(pixel.temp > 900) {
if(pixel.heatTreated == 0) {
if(exposedToAir(pixel)) {
pixel.color = pixelColorPick(pixel,goldenZirconColors)
pixel.heatTreated = 2;
} else {
pixel.color = pixelColorPick(pixel,blueZirconColors)
pixel.heatTreated = 1;
}
} else if((pixel.heatTreated == 1) && (exposedToAir(pixel))) {
pixel.color = pixelColorPick(pixel,goldenZirconColors)
pixel.heatTreated = 2;
}
}
},
onUnpaint: function(pixel) {
if(pixel.heatTreated == 1) {
pixel.color = pixelColorPick(pixel,blueZirconColors)
} else if(pixel.heatTreated = 2) {
pixel.color = pixelColorPick(pixel,goldenZirconColors)
};
},
tempHigh: 2100,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 4010,
hardness: 0.9,
};
//Opal
elements.opal = {
color: ["#ffcfcf", "#fff0d9", "#fcf7c5", "#e4ffd4", "#d1fff5", "#dcecfa", "#dfdbff", "#f5e0ff", "#f7d0f1"],
tempHigh: 100,
stateHigh: ["broken_opal", "broken_opal", "broken_opal", "broken_opal", "broken_opal", "broken_opal", "broken_opal", "broken_opal", "broken_opal", "steam"],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2090,
hardness: 0.6,
breakInto: ["quartz", "quartz", "quartz", "quartz", "quartz", "quartz", "quartz", "quartz", "quartz", "water"],
};
elements.broken_opal = {
color: ["#f5e6e6", "#ebe2d5", "#f7f6ed", "#e4eddf", "#d8ebe7", "#d8e0e8", "#e4e3e8", "#f4edf7", "#ebebeb"],
tempHigh: 1650,
stateHigh: "molten_quartz",
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2322,
hardness: 0.55, //it cracks
};
//Quartz
elements.quartz = { //silicates, silicates, and more silicates
color: ["#f0f0f0", "#e3e3e3", "#f7f7f7"],
tempHigh: 1650,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2650,
hardness: 0.7,
};
//Re-add molten quartz because it stopped auto-generating
elements.molten_quartz = {"behavior":behaviors.MOLTEN,"hidden":true,"state":"liquid","category":"states","color":['#ffff78', '#fff078', '#ffb400', '#ffff71', '#ffe371', '#ffaa00', '#ffff7b', '#fff77b', '#ffb900'],"temp":1650,"tempLow":1550,"stateLow":"quartz","density":2385,"viscosity":10000,"reactions":{"ash":{"elem1":null,"elem2":"molten_slag"},"dust":{"elem1":null,"elem2":"molten_slag"},"magma":{"elem1":null,"elem2":"molten_slag"}},"movable":true}
//Use in glass
elements.molten_quartz.reactions = {
quicklime: { elem1: "molten_glass", elem2: ["quicklime", "quicklime", "quicklime", "quicklime", "quicklime", "quicklime", "quicklime", "quicklime", "quicklime", null]} //lack of vanilla washing soda, lack of tripartite reactions
};
/*
elements.elem1.reactions = {
elem2: { elem1: "elem1_becomes", elem2: "elem2_becomes"}
};
*/
//Pearl (not a mineral)
elements.pearl = {
color: ["#e3e3e3", "#e3e0d1", "#eddbce", "#eef2c9", "#d5f5dc", "#d8f2ec", "#fadcf9", "#e3d1c1", "#f2edc9", "#e0f5d7", "#e2beeb", "#e3e3e3", "#e3e0d1", "#eddbce", "#eef2c9", "#d5f5dc", "#d8f2ec", "#fadcf9", "#e3d1c1", "#f2edc9", "#e0f5d7", "#e2beeb", "#38332e"],
tempHigh: 1340, //yay, more thermal decomposition elements
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 772, //It is partly made of proteins and is said to burn, but I can't find an ignition point, so here it melts.
hardness: 0.45,
};
//Jade
elements.jadeite = {
color: ["#3D7D31", "#2D6D1F", "#538A2F", "#6A9A37"],
tempHigh: 1000,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 3400,
hardness: 0.65,
};
//Missing gases
elements.molten_plastic.tempHigh = 360;
elements.molten_plastic.stateHigh = ["steam","carbon_dioxide","smoke","acid_gas","benzene_gas","dioxin","stench"];
elements.copper_sulfate.tempHigh = 110;
elements.molten_copper_sulfate.burn = 0.1;
elements.molten_copper_sulfate.behavior = behaviors.LIQUID;
elements.molten_copper_sulfate.tempHigh = 150;
elements.molten_copper_sulfate.stateHigh = "molten_anhydrous_copper_sulfate";
var acs = newPowder("anhydrous_copper_sulfate","#8a9c7f",3603,340);
elements.molten_anhydrous_copper_sulfate = {
tempHigh: 630,
stateHigh: ["copper_2_oxide","sulfur_trioxide_gas"]
};
acs.reactions = {
water: {elem1: "copper_sulfate", elem2: null, tempMax: 63},
salt_water: {elem1: "copper_sulfate", elem2: "salt", tempMax: 63},
sugar_water: {elem1: "copper_sulfate", elem2: "sugar", tempMax: 63},
dirty_water: {elem1: "copper_sulfate", elem2: ["dust","ash","poison"], tempMax: 63},
radioactive_water: {elem1: "copper_sulfate", elem2: "fallout", tempMax: 63},
heavy_water: {elem1: "copper_sulfate", elem2: null, tempMax: 63},
radioactive_water: {elem1: "copper_sulfate", elem2: "radiation", tempMax: 63}
};
acs.tick = function(pixel) {
if(exposedToAir(pixel) && Math.random() < 0.02 && pixel.temp < 200) {
if(pixel.temp > 63 && pixel.water >= 4) { return };
pixel.water ??= 0;
pixel.water++;
if(!pixel.color.startsWith("hsl")) {
var _oldColor = convertColorFormats(pixel.color,"json");
_oldColor.r -= 15; _oldColor.g += 2; _oldColor.b -= 6;
pixel.color = convertColorFormats(_oldColor,"rgb");
_oldColor = null
};
if(pixel.water >= 5) {
changePixel(pixel,"copper_sulfate",false)
}
}
};
newPowder("copper_2_oxide","#171516",6310,1326);
elements.molten_copper_2_oxide = { tempHigh: 2000 };
runAfterLoad(function() {
simpleMissingGases = {
//For substances that don't decompose before they boil
molten_silver: 2162,
molten_nickel: 2913,
molten_tin: 2602,
molten_lead: 1749,
molten_aluminum: 2470,
molten_zinc: 907,
molten_uranium: 4131,
molten_polonium: 962
}
for(elemName in simpleMissingGases) {
var tH = simpleMissingGases[elemName];
if(tH) {
elements[elemName] ??= {};
elements[elemName].tempHigh = tH;
//console.log(elemName,elements[elemName])
}
};
liquidsMissingGases = {
molten_solder: null,
molten_tuff: null,
molten_thermite: null,
molten_slag: null,
molten_iron_dichloride: null,
molten_rutile: null,
molten_magnesium_oxide: null,
molten_magnesium_chloride: null,
molten_francium: null,
molten_stable_polonium: null,
molten_polonium_dioxide: null,
molten_magnesium_polonide: null,
molten_stable_francium: null,
molten_potassium_salt: null,
molten_cryolite_solution: null,
molten_fluorite: null,
molten_chalk: null,
molten_potassium_carbonate: null,
molten_potassium_fluoride: null,
molten_potassium_bromide: null,
molten_sodium_bromide: null,
molten_silver_bromide: null,
molten_potassium_sulfate: null,
molten_sodium_aluminate: null,
molten_sodium_carbonate: null,
molten_cryolite: null,
molten_sodium_fluoride: null,
molten_magnesium_fluoride: null,
molten_sodium_sulfate: null,
molten_boric_acid: null,
molten_borax: null,
molten_boron_trioxide: null,
molten_sodium_methoxide: null,
molten_decaborane: null,
molten_sodium_dodecaborate: null,
molten_depleted_uranium: null,
molten_enriched_uranium: null,
molten_uranium_dioxide: null,
molten_enriched_uranium_dioxide: null,
molten_uranium_tetrafluoride: null,
molten_enriched_uranium_tetrafluoride: null,
molten_radium: null,
molten_actinium: null,
molten_thorium: null,
molten_protactinium: null,
molten_neptunium: null,
molten_plutonium: null,
molten_enriched_plutonium: null,
molten_depleted_plutonium: null,
molten_plutonium_dioxide: null,
molten_enriched_plutonium_dioxide: null,
molten_depleted_plutonium_dioxide: null,
molten_plutonium_tetrafluoride: null,
molten_enriched_plutonium_tetrafluoride: null,
molten_depleted_plutonium_tetrafluoride: null,
molten_americium: null,
molten_curium: null,
molten_berkelium: null,
molten_californium: null,
molten_einsteinium: null,
molten_fermium: null,
molten_stable_thorium: null,
molten_radium_chloride: null,
molten_stable_radium: null,
molten_stable_actinium: null,
molten_stable_protactinium: null,
molten_stable_neptunium: null,
molten_nihonium: null,
molten_nihonium_nitrate: null,
molten_nihonium_sulfate: null,
molten_flerovium_oxide: null,
molten_moscovium: null,
molten_moscovium_hydroxide: null,
molten_livermorium: null,
molten_livermorium_oxide: null,
molten_tennessine: null,
molten_ununennium_fluoride: null,
molten_unbinilium: null,
molten_stable_unbinilium: null,
molten_unbinilium_difluoride: null,
molten_francium_hydroxide_powder: null,
molten_ununennium_hydroxide_powder: null,
molten_caustic_soda: null,
molten_caustic_potash: null,
molten_sodium_acetate: null,
molten_endstone: null,
molten_netherrack: null,
molten_dripstone: null,
molten_obsidian: null,
molten_mythril: null,
molten_mithril_mythril_alloy: null,
molten_hematite: null,
molten_carbon: null,
molten_quartz: null,
molten_ketchup_metal: null,
molten_caesium_137: null,
molten_barium: null,
molten_technetium: null,
molten_bismuth: null,
molten_gallium_nitride: null,
molten_gallium_phosphide: null,
molten_densinium: null,
molten_polystyrene: null,
molten_sterling: null,
molten_signalum: null,
molten_pyreite: null,
molten_infernium: null,
molten_infernyrite: null,
molten_infernyreitheum: null,
molten_pyrinfernyreitheum: null,
molten_nichrome: null,
molten_lithium: null,
molten_hanichrite: null,
molten_vivite_slag: null,
molten_crimglass: null,
molten_sapphire: null,
molten_ruby: null,
molten_dantite: null,
molten_gypsum: null,
molten_tungstensteel: null,
molten_clay_loam: null,
molten_brick: null,
molten_galvanized_steel: null,
molten_brass: null,
molten_bronze: null,
molten_rose_gold: null,
molten_purple_gold: null,
molten_blue_gold: null,
molten_electrum: null,
molten_pyrite: null,
molten_amalgam: null,
molten_alga: null,
molten_metal_scrap: null,
molten_epsom_salt: null,
molten_polytetrafluoroethylene: null,
molten_polyethylene: null,
molten_bauxite: null,
molten_cryolite_mixture: null,
molten_boron: null,
molten_uraninite: null,
molten_yellowcake: null,
molten_stable_uranium: null,
molten_depleted_uranium_dioxide: null,
molten_stable_uranium_dioxide: null,
molten_depleted_uranium_tetrafluoride: null,
molten_stable_uranium_tetrafluoride: null,
molten_stable_plutonium: null,
molten_stable_plutonium_dioxide: null,
molten_stable_plutonium_tetrafluoride: null,
molten_stable_americium: null,
molten_stable_curium: null,
molten_stable_berkelium: null,
molten_stable_californium: null,
molten_stable_einsteinium: null,
molten_stable_fermium: null,
molten_thorium_dioxide: null,
molten_stable_thorium_dioxide: null,
molten_thorium_tetrafluoride: null,
molten_stable_thorium_tetrafluoride: null,
molten_radium_oxide: null,
molten_actinium_oxide: null,
molten_protactinium_v_oxide: null,
molten_protactinium_pentafluoride: null,
molten_neptunium_dioxide: null,
molten_neptunium_tetrafluoride: null,
molten_stable_nihonium: null,
molten_nihonium_oxide: null,
molten_francium_nihonide: null,
molten_flerovium_sulfide: null,
molten_stable_moscovium: null,
molten_moscovium_fluoride: null,
molten_stable_livermorium: null,
molten_stable_tennessine: null,
molten_oganesson_difluoride: null,
molten_oganesson_tetrafluoride: null,
molten_ununennium_trifluoride: null,
molten_unbinilium_oxide: null,
molten_unbinilium_tetrafluoride: null,
molten_bleakstone: null,
molten_mithril: null,
molten_corrupt_land: null,
molten_corrupt_rock: null,
molten_ketchup_gold: null,
molten_monosodium_glutamate: null,
molten_agar: null,
molten_stainless_steel: null,
molten_brimstone_slag: null,
molten_loona: null,
molten_white_gold: null,
molten_red_gold: null,
molten_amba_bismuth: null,
molten_zirconium: null,
molten_lithium_oxide: null,
molten_lithium_hydroxide: null,
molten_lithium_carbonate: null,
molten_lithium_nitride: null,
molten_lithium_hydride: null,
molten_lithium_amide: null,
molten_niobium: null,
molten_crimtane: null,
molten_dry_crimsoil: null,
molten_rainbow_glass: null,
molten_dry_rainbow_dirt: null,
molten_nellglass: null,
molten_emerald: null,
molten_amethyst: null,
molten_spinel: null,
molten_mullite: null,
molten_onyx: null,
molten_pearl: null,
molten_jadeite: null,
molten_hydroxyapatite: null,
molten_calcium_sulfate: null
}
})
//Soil
//Dry dirt
elements.dirt.forceAutoGen = true;
elements.dry_dirt = {
color: ["#a88e5e","#8f7950","#8a7045","#9e804c"],
behavior: [
"XX|SW:dirt%3 AND SW:mud%6|XX",
"XX|XX|XX",
"M2|M1|M2",
],
tempHigh: 1200,
stateHigh: "molten_dirt",
tempLow: -50,
stateLow: "dry_permafrost",
category:"land",
state: "solid",
density: 1100,
_data: ["loam","dry_soil","particulate"]
},
elements.water.reactions.dry_dirt = {
elem1: null, elem2: "dirt", chance: 0.005
};
elements.mud.reactions.dry_dirt = {
elem1: "dirt", elem2: "dirt", chance: 0.005
};
elements.dirt._data = ["loam","soil","particulate"];
elements.molten_dirt = { //added manually because the change to dirt will prevent molten_dirt from being auto-generated
"behavior": behaviors.MOLTEN,
"name": "molten_loam",
"hidden": true,
"state": "liquid",
"category": "states",
"color": ["#EC6A15", "#EC5515", "#EC3F00", "#B85210", "#B84210", "#B83100", "#AE4B0D", "#AE3C0D", "#AE2D00", "#D65A0F", "#D6480F", "#D63600"],
"temp": 1200,
"tempLow": 1100,
"stateLow": "dry_dirt",
"density": 1098,
"viscosity": 10000
}
elements.molten_dirt.tempHigh = 3000;
elements.molten_dirt.stateHigh = "vaporized_rock";
elements.dry_permafrost = {
color: ["#5B7870","#535D51","#52746A","#5A7A6F"],
behavior: behaviors.POWDER, //not enough water for cementing
temp: -50,
tempHigh: 10,
stateHigh: "dry_dirt",
category: "land",
state: "solid",
state: "solid",
density: 1200,
_data: ["loam","soil","particulate"]
}
elements.dirt.tempHigh = 110;
elements.dirt.stateHigh = "dry_dirt";
//Land Element Cults
/*
"Cult" is used similarly to its EoD sense; here, it signifies a set of elements that systematically replicates another set of elements except for a given modification.
In this case, they replicate some land elements; a "yellow" cult, for example, would have yellow_dirt, yellow_mud, yellow_mudstone, yellow_permafrost, yellow_sand...
*/
//Radiation
//System with new special_property_library.js to replace the old mass manual recreation
radioactiveTransforms = {
steam: "rad_steam",
glass: "rad_glass",
molten_glass: "molten_rad_glass",
vaporized_glass: "vaporized_rad_glass",
fire: {element: "rad_fire", chance: 0.005},
torch: "rad_torch"
};
specialProperties.radioactive = {
/*specialColorFunction: function(pixel,oldColor) {
var colorJSON = convertColorFormats(oldColor,"json");
colorJSON.r *= 0.85;
colorJSON.r += 8;
colorJSON.g *= 1.4;
colorJSON.g += 16;
colorJSON.b *= 0.4;
colorJSON.b -= 0.4;
return convertColorFormats(colorJSON,"rgb");
},*/
specialFunction: function(pixel) {
if(radioactiveTransforms[pixel.element]) {
var result = radioactiveTransforms[pixel.element];
var changeTemp = false;
var chance = 1;
if(typeof(result) === "object" && result.element !== undefined) {
result = result.element;
chance = result.chance ?? 1;
changeTemp = result.changeTemp ?? false;
}
while(result instanceof Array) {
result = result[Math.floor(Math.random() * result.length)]
};
if(result === null) {
deletePixel(pixel)
} else {
changePixel(pixel,result,changeTemp)
};
return
};
for(var i in adjacentCoords) {
if(Math.random() < 0.005) {
pixel.temp++;
var newCoords = [
pixel.x+adjacentCoords[i][0],
pixel.y+adjacentCoords[i][1]
];
if(isEmpty(newCoords[0],newCoords[1],false)) {
createPixel("radiation",newCoords[0],newCoords[1])
}
};
};
if(Math.random() < 0.05) {
pixel.temp+=0.5;
if(Math.random() < 0.005) {
delete pixel.radioactive
}
}
}
}
console.log("Radioactive property defined");
//Main elements
elements.liquid_irradium = {
color: "#5499FF",
behavior: behaviors.LIQUID,
tick: function(pixel) {
for(var i = 0; i < adjacentCoords.length; i++) {
//transformAdjacent(pixel,radioactiveTransforms)
var newCoords = [
pixel.x+adjacentCoords[i][0],
pixel.y+adjacentCoords[i][1]
];
var newPixel = pixelMap[newCoords[0]]?.[newCoords[1]];
if(newPixel && newPixel.element !== pixel.element) {
newPixel.radioactive = true
}
}
},
//Becomes rainbow sand by water or poison, as well as by protocite, or bio-ooze
//Becomes sulfuric acid on contact with it
//Becomes corrupt slime by elder fluid
//Converts black tar and organic soup into itself
//Turns either grav liquid into aether dust, as well as liquid crystal
//Turns blood into bloodstone
//Turns blue slime into black slime
//Made by {mercury or bio-ooze} and protocite
category:"liquids",
state: "liquid",
density: 18180, //Cherry-picked from a Tumblr headcanon
//https://omniblog-of-starbound.tumblr.com/post/188424072728/starbound-element-headcannon-modded-metals
viscosity: 80.1, //probably misinterpreting tickDelta, and w/o the game assets, I can't compare against water, so this is in relation to H2SO4 scaled to its density in cP and under the assumption that water visc = 1
}
/*
//Metamorphism will be driven using solely temperature.
//Pressure simulation, due to how the game is coded, will be limited to requiring the rock to be surrounded.
elements.slate = {
color: ["#787B80", "#535557", "#695E58", "#696969", "#6B5D5B"],
tempHigh: 200,
stateHigh: "felsic_magma",
category: "solid rock",
state: "solid",
density: 2640,
hardness: 0.7,
maxColorOffset: 15,
hardness: 0.3,
_data: ["clay", "rock", "sedimentary_rock"]
};
elements.shale.onTryMoveInto = function(pixel,otherPixel) {
var otherData = elements[otherPixel.element];
if(otherData.category == "magmas" && Math.random() < 0.005 && pixel.temp > 650) {
var around = getCirclePixels(pixel.x,pixel.y,2);
around.forEach(pixel => changePixel(pixel,"hornfels"));
return
};
if(pixel.exposedToAir) { return };
if(pixel.temp > 800 && Math.random () < 0.0007) {
changePixel(pixel,"migmatite")
} else if(pixel.temp > 600 && Math.random () < 0.001) {
changePixel(pixel,"gneiss")
} else if(pixel.temp > 400 && Math.random () < 0.001) {
changePixel(pixel,"schist")
} else if(pixel.temp > 200 && Math.random () < 0.001) {
changePixel(pixel,"slate")
};
return
};*/
runAfterLoad(function() {
rocksSandsAndSoilsToGiveHotForms = Object.keys(elements).filter(
function(elemName) {
//console.log(elemName,elements[elemName]._data?.[2]);
return (!(["clay","limestone","black_limestone"].includes(elemName)) && !(elemName.endsWith("permafrost")) && ["igneous_rock","solid_igneous_rock","igneous_gravel","sedimentary_rock","particulate","packed_particulate","metamorphic_rock","solid_metamorphic_rock","metamorphic_gravel"].includes(elements[elemName]._data?.[2]))
}
);
if(rocksSandsAndSoilsToGiveHotForms.includes("clay")) { rocksSandsAndSoilsToGiveHotForms.splice(rocksSandsAndSoilsToGiveHotForms.indexOf("clay"),1) };
hotRockFunction(); //needs to happen after dry dirt is defined
elements.hot_crimsoilstone.stateHigh = "molten_crimsoil";
elements.crimsoil.tempHigh = 100;
elements.crimsoil.stateHigh = "dry_crimsoil";
elements.hot_rainbow_soilstone.stateHigh = "molten_rainbow_dirt";
elements.rainbow_dirt.tempHigh = 100;
elements.rainbow_dirt.stateHigh = "dry_rainbow_dirt";
});
//Generation
//TNT world
//Supplementary elements
elements.oil_cloud = {
color: "#8c4331",
behavior: [
"XX|XX|XX",
"XX|CH:oil%0.05|M1%2.5 AND BO",
"XX|XX|XX",
],
category:"gases",
temp: 30,
state: "gas",
density: 0.5,
burn: 60,
burnTime: 15,
burnInto: "explosion", //atomization moment
ignoreAir: true,
stain: 0.02,
};
elements.oil_cloud_floater = {
color: "#8c4331",
behavior: [
"M2|M1|M2",
"M1%80|CH:oil_cloud%0.2|M1%80",
"M%60|XX|M2%60",
],
reactions: {
"oil_cloud_floater": { elem1: "oil_cloud", elem2: "oil_cloud", chance: 0.003 },
"oil_cloud": { elem1: "oil_cloud", elem2: "oil_cloud", chance: 0.01 }
},
category:"gases",
temp: 30, //otherwise identical
state: "gas",
density: 0.5,
burn: 60,
burnTime: 15,
burnInto: "explosion", //atomization moment
stain: 0.02,
};
//Main preset
worldgentypes.tnt_world = {
name: "TNT World", //unimplemented
layers: [
[0.9, "red_gas", 0.50],
[0.9, "oil_cloud_floater"],
[0.65, "coal", 0.1],
[0.65, "nitro"],
[0.55, "nitro", 0.5],
[0.2, "coal", 0.2],
[0.2, "tnt"],
[0.05, "coal", 0.3],
[0.05, "c4"],
[0.0, "coal", 0.4],
[0.0, "lamp_oil"]
]
};
//Ice world
//Supplementary elements
elements.snow_cloud_floater = {
color: "#7e8691",
behavior: [
"M2|M1|M2",
"M1%80|CH:snow_cloud%0.2|M1%80",
"M%60|XX|M2%60",
],
reactions: {
"snow_cloud_floater": { elem1: "snow_cloud", elem2: "snow_cloud", chance: 0.003 },
"snow_cloud": { elem1: "snow_cloud", elem2: "snow_cloud", chance: 0.01 }
},
category:"gases",
temp:-10,
tempHigh:30,
stateHigh:"rain_cloud",
tempLow:-200,
stateLow:"hail_cloud",
state:"gas",
density:0.55,
conduct:0.01,
movable:true,
isGas:true
};
//Main preset
worldgentypes.ice = {
layers: [
//[0.95, "snow_cloud_floater"], //le cutting room floor has arrived
[0.9, "snow"],
[0.65, "ice"],
[0.6, "gravel"],
[0.35, "permafrost"],
[0, "rock"]
],
temperature: -20
};
/*worldgentypes.nuclear_wasteland = {
layers: [
[0.9, "smoke", 0.5],
[0.9, "rad_snow_cloud_floater", 0.75],
[0.82, "fallout", 0.4],
[0.7, "liquid_irradium", 0.05],
[0.7, "dead_plant", 0.12],
[0.55, "radioactive_dirt"],
[0.45, "radioactive_rock"],
[0.25, "uranium", 0.4],
[0.35, "radioactive_rock", 0.5],
[0.3, "radioactive_gravel", 0.5],
[0.2, "uranium", 0.2],
[0.05, "rock"],
[0, "basalt"],
],
temperature: -5 //nuclear winter
};*/
//Dark world
worldgentypes.dark = {
layers: [
[0.8, "carbon_dioxide"],
[0.65, "ink"],
[0.5, "charcoal"],
[0, "basalt"]
]
};
//Money world
worldgentypes.money = {
layers: [
[0.9, "jadeite",1/2],
[0.9, "emerald"],
[0.6, "diamond"],
[0.3, "osmium_scrap",1/5],
[0.3, "rhenium_scrap",1/5],
[0.3, "rhodium_scrap",1/5],
[0.3, "iridium_scrap",1/5],
[0.3, "gold_coin"],
[0.1, "garnet", 1/5],
[0.1, "spinel", 1/5],
[0.1, "ruby", 1/5],
[0.1, "amethyst", 1/5],
[0.1, "sapphire"],
[-0.1, "pearl", 0.4],
[-0.1, "onyx"]
],
};
//Concrete
worldgentypes.concrete = {
layers: [
[0.13, "concrete"],
[0.1, "concrete", 0.5],
[-0.1, "dirt"]
],
heightVariance: 0.00000000000000000000000000000001, //R74n didn't use the nullish ??, so 0 is disallowed.
};
//Star world
//If GWSN can have a decidedly Earth-y name and a space concept, then I should be able to do the same
//Supplementary elements
elements.liquid_stellar_plasma = {
color: "#ffffbd",
colorOn: "#ffffbd",
behavior: [
"XX|M2%5 AND CR:plasma%1|XX",
"M2|XX|M2",
"M1|M1|M1",
],
behaviorOn: [
"XX|M2%10 AND M1%0.5 AND CR:plasma%2.3|XX",
"M2|XX|M2",
"M1|M1|M1",
],
tick: function(pixel) {
almostSun(pixel,0.6,stellarPlasmaSpreadWhitelist);
},
temp:5500,
isGas: true,
tempLow:2300,
stateLow: "plasma",
category: "liquids",
state: "liquid",
density: 1000, //density actually depends on depth in the star: https://astronomy.stackexchange.com/a/32734
conduct: 0.5,
};
elements.stellar_plasma = {
color: "#ffffbd",
colorOn: "#ffffbd",
behavior: [
"M2|M1 AND CR:plasma%0.6|M2",
"M1 AND CR:plasma%0.6|XX|M1 AND CR:plasma%0.6",
"M2|M1 AND CR:plasma%0.6|M2",
],
behaviorOn: [
"M2|M1 AND CR:plasma%1|M2",
"M1 AND CR:plasma%1|XX|M1 AND CR:plasma%1",
"M2|M1 AND CR:plasma%1|M2",
],
tick: function(pixel) {
almostSun(pixel,0.5,stellarPlasmaSpreadWhitelist);
},
temp:5500,
tempLow:2300,
stateLow: "plasma",
category: "gases",
state: "gas",
density: 10,
conduct: 0.5,
};
elements.neutron_star = {
color: "#e9eaf7",
colorOn: "#ffffbd",
behavior: [
"XX|CR:neutron%0.1|XX", //no neutrinos though
"CR:neutron%0.1|XX|CR:neutron%0.1",
"XX|CR:neutron%0.1|XX"
],
tick: function(pixel) {
nsTick(pixel,0.7,stellarPlasmaSpreadWhitelist);
},
temp: 1e8,
category: "special",
state: "gas",
density: 1e17,
insulate: true,
conduct: 1,
};
elements.liquid_degenerate_neutronium = {
color: "#e9eaf7",
behavior: [
"XX|M2%5 AND CR:neutron%0.6|XX",
"M2|XX|M2",
"M1|M1|M1",
],
behaviorOn: [
"XX|M2%10 AND M1%0.5 AND CR:neutron%1.2|XX",
"M2|XX|M2",
"M1|M1|M1",
],
tick: function(pixel) {
nsTick(pixel,0.7,stellarPlasmaSpreadWhitelist);
},
temp:1e6,
isGas: true,
tempLow:2300,
stateLow: elements.liquid_neutronium ? "liquid_neutronium" : "neutron",
category: "liquids",
state: "liquid",
density: 100000, //i'm not doing any more research on these neutron stars because google is useless
conduct: 1,
};
elements.gaseous_degenerate_neutronium = {
color: "#e9eaf7",
behavior: [
"M2|M1 AND CR:neutron%0.6|M2",
"M1 AND CR:neutron%0.6|XX|M1 AND CR:neutron%0.6",
"M2|M1 AND CR:neutron%0.6|M2",
],
behaviorOn: [
"M2|M1 AND CR:neutron%1|M2",
"M1 AND CR:neutron%1|XX|M1 AND CR:neutron%1",
"M2|M1 AND CR:neutron%1|M2",
],
tick: function(pixel) {
nsTick(pixel,0.6,stellarPlasmaSpreadWhitelist);
},
temp:1e6,
isGas: true,
tempLow:2300,
stateLow: "neutron",
category: "gases",
state: "gas",
density: 10000, //i'm not doing any more research on these neutron stars because google is useless
conduct: 1,
};
elements.supernova.behavior[1] = elements.supernova.behavior[1].split("|");
elements.supernova.behavior[1][1] = elements.supernova.behavior[1][1].replace("void","amba_black_hole") + ",neutron_star,neutron_star,amba_black_hole,amba_black_hole,amba_black_hole"
elements.supernova.behavior[1] = elements.supernova.behavior[1].join("|");
elements.plasma.noConduct = ["plasma_torch","stellar_plasma","liquid_stellar_plasma","liquid_degenerate_neutronium","gaseous_degenerate_neutronium","neutron_star"]; //I can't suppress the charge overlay and keep the tick color, only effective with noConduct.js but not strictly required
//Tangentially linked
elements.rainbow_sun = {
color: ["#ffbdbd", "#f2ffbd", "#bdffd7", "#bdd7ff", "#f2bdff"],
tick: function(pixel) {
starLightAndConduction(pixel,rainbowSunColor(pixel),["sun","nellsun","rainbow_sun"])
},
reactions: {
"hydrogen": { "elem2":"helium", "temp1":5 },
"helium": { "elem2":"carbon_dioxide", "temp1":5, "tempMax":3600 },
"carbon_dioxide": { "elem2":"neon", "temp1":5, "tempMax":1800 },
},
temp: 5700,
tempLow: -100,
stateLow: "supernova",
category: "special",
state: "gas",
//density: 1408,
insulate: true,
nellfireImmune: true,
};
//Tangentially linked
elements.rainbow_fire = {
color: [
{h: 330, s: 100, l: 56},
{h: 0, s: 100, l: 59},
{h: 22, s: 100, l: 58},
{h: 42, s: 100, l: 57},
{h: 60, s: 100, l: 55},
{h: 73, s: 100, l: 49},
{h: 120, s: 100, l: 49.5},
{h: 159, s: 100, l: 52},
{h: 159, s: 100, l: 52},
{h: 180, s: 100, l: 49.5},
{h: 197, s: 100, l: 59},
{h: 240, s: 100, l: 58.5},
{h: 280, s: 94, l: 53},
{h: 307, s: 100, l: 55}
].map(x => convertHslObjects(x,"hex")),
behavior: behaviors.UL_UR,
reactions: {
"fire": { "elem1": "rainbow_fire" },
"water": { "elem1": "color_smoke" },
"steam": { "elem1": "color_smoke" },
"carbon_dioxide": { "elem1": "color_smoke" },
"dirty_water": { "elem1": "color_smoke" },
"salt_water": { "elem1": "color_smoke" },
"sugar_water": { "elem1": "color_smoke" },
},
nellfireImmune: true,
fireSpawnChance: 0,
temp:610,
tempLow:102,
stateLow: "color_smoke",
tempHigh: 7000,
stateHigh: "plasma",
category: "energy",
burning: true,
burnTime: 44,
burnInto: "color_smoke",
state: "gas",
density: 0.21,
ignoreAir: true,
noMix: true,
};
elements.color_smoke.tempHigh = 610;
elements.color_smoke.stateHigh = "rainbow_fire";
//I guess other worlds do still fall under the purview of TGJS (future alice: i forgot what tgjs stands for)
function nellsunColor(pixel) {
if (pixel.temp < 0) { pixel.color = pixelColorPick(pixel,"#615e5e"); var c=0 }
else if (pixel.temp < 300) { pixel.color = pixelColorPick(pixel,"#664962"); var c=0 }
else if (pixel.temp < 500) { pixel.color = pixelColorPick(pixel,"#714487"); var c=0.00004 }
else if (pixel.temp < 850) { pixel.color = pixelColorPick(pixel,"#6a43bf"); var c=0.00015 }
else if (pixel.temp < 1300) { pixel.color = pixelColorPick(pixel,"#c356db"); var c=0.0005 }
else if (pixel.temp < 1800) { pixel.color = pixelColorPick(pixel,"#f04ac4"); var c=0.0015 }
else if (pixel.temp < 2100) { pixel.color = pixelColorPick(pixel,"#f788c5"); var c=0.004 }
else if (pixel.temp < 2400) { pixel.color = pixelColorPick(pixel,"#f7a3b8"); var c=0.007 }
else if (pixel.temp < 3200) { pixel.color = pixelColorPick(pixel,"#ffd1d9"); var c=0.01 }
else if (pixel.temp < 3900) { pixel.color = pixelColorPick(pixel,"#fce1e1"); var c=0.02 }
else if (pixel.temp < 4600) { pixel.color = pixelColorPick(pixel,"#fff5f5"); var c=0.035 }
else if (pixel.temp < 6100) { pixel.color = pixelColorPick(pixel,_cc.w.h); var c=0.05 }
else if (pixel.temp < 7200) { pixel.color = pixelColorPick(pixel,"#f4fad9"); var c=0.075 }
else if (pixel.temp < 8300) { pixel.color = pixelColorPick(pixel,"#e4f2c2"); var c=0.1 }
else if (pixel.temp < 10400) { pixel.color = pixelColorPick(pixel,"#c6f2a2"); var c=0.125 }
else if (pixel.temp < 12500) { pixel.color = pixelColorPick(pixel,"#90f277"); var c=0.15 }
else if (pixel.temp < 15600) { pixel.color = pixelColorPick(pixel,"#75f754"); var c=0.175 }
else if (pixel.temp < 18700) { pixel.color = pixelColorPick(pixel,"#5aff30"); var c=0.2 }
else if (pixel.temp < 21800) { pixel.color = pixelColorPick(pixel,"#1df54f"); var c=0.25 }
else if (pixel.temp < 28900) { pixel.color = pixelColorPick(pixel,"#3ce873"); var c=0.3 }
else if (pixel.temp < 36000) { pixel.color = pixelColorPick(pixel,"#4fdb90"); var c=0.35 }
else if (pixel.temp < 45600) { pixel.color = pixelColorPick(pixel,"#5dcfa7"); var c=0.4 }
else if (pixel.temp < 52200) { pixel.color = pixelColorPick(pixel,"#4fe3af"); var c=0.45 }
else if (pixel.temp < 58300) { pixel.color = pixelColorPick(pixel,"#3cfad4"); var c=0.5 }
else if (pixel.temp < 63400) { pixel.color = pixelColorPick(pixel,"#26f8ff"); var c=0.6 }
else if (pixel.temp < 68500) { pixel.color = pixelColorPick(pixel,"#19d9ff"); var c=0.7 }
else if (pixel.temp < 73600) { pixel.color = pixelColorPick(pixel,"#08b1ff"); var c=0.8 }
else { pixel.color = pixelColorPick(pixel,"#0099ff"); var c=0.9 }
return c;
};
function nellSLAC(pixel,c,whitelist=["sun","nellsun"]) {
for (var i = 0; i < adjacentCoords.length; i++) {
var x = pixel.x+adjacentCoords[i][0];
var y = pixel.y+adjacentCoords[i][1];
if (isEmpty(x,y)) {
if (Math.random() <= c) {
createPixel("light", x, y);
pixelMap[x][y].color = pixel.color;
};
} else if (!outOfBounds(x,y)) {
var newPixel = pixelMap[x][y];
//console.log(whitelist,newPixel.element,whitelist.includes(newPixel.element));
if (pixel.temp!==newPixel.temp && whitelist.includes(newPixel.element)) {
var avg = (pixel.temp + newPixel.temp)/2;
pixel.temp = avg;
newPixel.temp = avg;
pixelTempCheck(pixel);
pixelTempCheck(newPixel);
}
}
}
};
elements.nellsun = {
color: ["#ff26ac", "#ffb8e4", _cc.w.h, "#b7ffa8", "#2df7b4"],
tick: function(pixel) {
nellSLAC(pixel,nellsunColor(pixel));
},
reactions: {
"hydrogen": { "elem2":"helium", "temp1":5 },
"helium": { "elem2":"carbon_dioxide", "temp1":5, "tempMax":3600 },
"carbon_dioxide": { "elem2":"neon", "temp1":5, "tempMax":1800 },
},
temp: 5504,
tempLow: -100,
stateLow: "supernova",
category: "special",
state: "gas",
//density: 1408,
insulate: true,
nellfireImmune: true,
};
elements.nellfire = {
excludeRandom: true,
color: ["#ff8929","#ffb429","#ffde0a"],
behavior: [
"M1|M1|M1",
"M1%10 AND M2|HT%2|M1%10 AND M2",
"XX|M2|XX"
],
reactions: {
"fire": { "elem2": "nellfire" },
/*"water": { "elem1": "smoke" },
"steam": { "elem1": "smoke" },
"carbon_dioxide": { "elem1": "smoke" },
"dirty_water": { "elem1": "smoke" },
"salt_water": { "elem1": "smoke" },
"sugar_water": { "elem1": "smoke" },*/
},
tick: function(pixel) {
if(pixel.burning) {
delete pixel.burning;
delete pixel.burnStart;
pixel.nellburn = true;
pixel.nellburnStart ??= pixelTicks;
};
},
nellBurningWhenConverted: true,
temp:900,
nellFireSpawnChance: 0,
//tempLow:200,
//stateLow: "smoke",
category: "energy",
burning: true,
nellburnTime: 50,
nellburnInto: null,
state: "gas",
density: 0.06,
ignoreAir: true,
noMix: true,
desc: "Researchers first came into this place and thought it was Hell— it wasn't, so they renamed it Nell (Not Hell). They still named the materials in it hell references, though.",
},
elements.dantite = {
color: ["#5effba", "#85edd1", "#62d9c7", "#3efa9c", "#21b9db"],
tempHigh: 2000,
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 1442,
hardness: 0.47,
nellfireImmune: "torch",
};
elements.molten_dantite = {
color: ["#5eff6b", "#70faaa", "#31e08b", "#a1f051"],
density: 4012,
hardness: 0.84,
nellfireImmune: "torch",
};
elements.limtupyte = { //λίμνη τοῦ πυρός
color: ["#212121", "#212121", "#40221f", "#611d14"],
behavior: behaviors.WALL,
category: "solids",
state: "solid",
density: 8012,
hardness: 0.87,
nellfireImmune: true,
tempHigh: 9011,
stateHigh: "alpha_limtupyte",
};
elements.alpha_limtupyte = {
name: "α-limtupyte",
color: ["#6e1414", "#8f210b", "#a34910", "#c27115"],
density: 10112,
behavior: behaviors.MOLTEN,
category: "molten",
hidden: true,
state: "liquid",
hardness: 0.91,
nellfireImmune: true,
temp: 9500,
tempHigh: 11022,
stateHigh: "beta_limtupyte",
tempLow: 9011,
stateLow: "limtupyte",
};
elements.beta_limtupyte = {
name: "β-limtupyte",
color: ["#e68917", "#ffbd24", "#ffe940", "#ffff61"],
density: 13178,
behavior: behaviors.MOLTEN,
category: "molten",
hidden: true,
state: "liquid",
hardness: 0.93,
nellfireImmune: true,
temp: 12000,
tempHigh: 14316,
stateHigh: "limtupyte_gas",
tempLow: 11022,
stateLow: "alpha_limtupyte",
};
elements.limtupyte_gas = {
color: ["#ffff80", "#ffe940", "#feffd1", _cc.w.h],
density: 17.12,
behavior: behaviors.GAS,
category: "states",
hidden: true,
state: "gas",
hardness: 1,
nellfireImmune: true,
temp: 15000,
tempLow: 14316,
stateLow: "beta_limtupyte",
};
//Main preset
worldgentypes.star = {
layers: [
[0.9, "stellar_plasma"],
[0.65, "liquid_stellar_plasma"],
[0.4, "liquid_stellar_plasma", 1/2],
[0, "sun"],
],
complexity: 100,
baseHeight: 0.3,
temperature: 6500,
};
//Radioactive Desert
//Main preset
/*worldgentypes.nuclear_wasteland_desert = {
layers: [
[0.97, "fallout", 0.4],
[0.95, "radioactive_gravel", 0.6],
[0.65, "liquid_irradium", 0.01],
[0.65, "cancer", 0.02],
[0.65, "bone", 0.02],
[0.65, "radioactive_sand"],
[0.55, "cancer", 0.01],
[0.55, "bone", 0.01],
[0.3, "radioactive_sandstone"],
[0.05, "radioactive_rock"],
[-0.78, "radioactive_basalt"]
],
temperature: -13
};*/
runAfterLoad(function() {
elements.muddy_water.reactions.mud.elem2 = "soil_sediment";
elements.muddy_water.reactions.muddy_water.elem2 = "soil_sediment"
});
//PRIMITIVE IN-GAME CONSOLE ##
//featuring stars
customWorldTypes = {};
if(localStorage.getItem("customWorldTypes") == null) {
localStorage.setItem("customWorldTypes",JSON.stringify(customWorldTypes))
} else {
customWorldTypes = JSON.parse(localStorage.getItem("customWorldTypes"));
for(var name in customWorldTypes) {
worldgentypes[name] = customWorldTypes[name]
};
runAfterLoad(rebuildWorldgenList)
};
var promptInputNullishes = ["null","none","","n/a"];
var eightSpaces = " ".repeat(8);
commandHelpObject = {
"set": "Sets properties for every pixel of a given type.\nUsage: set [property] [element] [value] \nDon't include framing characters []<>.\nThe element can be \"all\" to set the property for every pixel.\nNote: Strings can't have spaces because spaces are the separator used in the parsing split().\nArguments in [brackets] are required and ones in are optional.",
"test": "Test.",
"setdimensions": "#This command clears the canvas#\nSets the width and height of the canvas and resets it to regenerate pixelMap.\nThis is offsetted so it doesn't count the OoB area on the top left; a 50x50 save will have a 50x50 usable area.\nUsage: setdimensions [width] [height] .\nDon't include framing characters []<>.\nArguments in [brackets] are required and ones in are optional.",
"pixelsize": "Sets the size of the pixels on screen. If no size is given, it instead alerts the current pixel size. Usage: pixelsize .\nDon't include framing characters <>.\nArguments in are optional.",
"dimensions": "Alerts the current dimensions. Usage: dimensions",
"fill": "Fills the screen with the given pixel(s). Usage: fill [Overwrite pixels? (bool)] [element] .\nDon't include framing characters []<>.\nArguments in [brackets] are required and ones in are optional.\nAdditional elements are separated by spaces.",
"randomfill": "Fills the screen with pixels from randomChoices. Usage: randomfill \nDon't include framing characters []<>.\nArguments in are optional.",
"count": "Tells you the amount of a specified pixel on the screen. Usage: count [element]\nDon't include framing characters []<>.\nArguments in [brackets] are required.",
"countall": "Logs to console a list of all elements on screen and their amounts. Usage: countall.",
"worldgen":
`Names or sets the current world type, lists all world types, or generates a given world type.
Usages:
${eightSpaces}Show the current worldgen setting: worldgen
${eightSpaces}List all available worldgen settings: worldgen list
${eightSpaces}Set the current worldgen setting: worldgen set [setting]
${eightSpaces}Generate a specified worldgen setting: worldgen generate [setting]`,
"defineworldgen":
`Creates or replaces a worldgen preset.
Usage (See below for formats): [name] [layers] .
Don't include framing characters []<>.
Arguments in [brackets] are required and ones in are optional.",
(Required) name: String. Cannot have spaces. Example: grass
(Required) layers:
${eightSpaces}Each layer is specified as [RelativeBottomStartPosition:ElementName]<:PixelProbability>
${eightSpaces}Layers are joined with the semicolon ;
${eightSpaces}Layer definitions must not have any spaces.
${eightSpaces}Example full layer definition: 0.85:grass;0.5:dirt;0.05:rock;-0.2:basalt`,
"defineworldgen2":
`(Optional) baseHeight: Number (ideally between 0 and 1). Default: 0.5.
(Optional) heightVariance: Number. Default: 0.5.
(Optional) complexity: Number. Default: 20.
(Optional) temperature: Number. No default value (use null or none to skip).
(Optional) decor:
${eightSpaces}Each decor layer is specified as [ElementName:PixelProbability]<:DistanceFromTop><:ListOfHexColors>
${eightSpaces}Distance from top, if not specified, defaults to 5.
${eightSpaces}The fourth part (optional) is a list of hex codes (like #FFFFFF) separated by commas.
${eightSpaces}Example full decor definition: bird:0.04:10:#FF0000,#FFFF00,#00FF00;diamond:0.3:5`,
"help": "Usage: help \nDon't include framing characters []<>\nArguments in are optional."
};
commandHelpObject.stars = "Clears the screen and replaces it with random stars. Usage: stars \nDon't include framing characters <>.\nArguments in are optional."
commandHelpObject.starseed = "Alerts the last used seed for stars. Usage: starseed";
var lastStarSeed = "[None]";
function seededCreateLargeStar(x,y,minRadius,maxRadius,minTemp,maxTemp,randomFunction) {
//console.log("start");
var sunPixels = fillCircleReturn("sun",x,y,seededRandBetween(minRadius,maxRadius,randomFunction),true);
//console.log("filled");
var randTemp = seededRandBetween(minTemp,maxTemp,randomFunction);
//console.log("setting temps");
for(pixelIndex = 0; pixelIndex < sunPixels.length; pixelIndex++) {
//console.log("pixel " + pixelIndex, sunPixels[pixelIndex].element);
sunPixels[pixelIndex].temp = randTemp;
};
//console.log(sunPixels.map(x => x.element));
//console.log("finished");
return true;
};
//G
elements.red_giant = {
color: "#f19898",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,3,4,1800,3300,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_giant = {
color: "#a085eb",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,2,3,20000,80000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_giant = {
color: "#fafad4",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,2,3,6000,11000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
//SG
elements.red_supergiant = {
color: "#f48585",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,6,8,1700,3200,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_supergiant = {
color: "#93b0ec",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,5,7,19000,83000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_supergiant = {
color: "#f4f9ae",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,5,7,5500,10500,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
//HG
elements.red_hypergiant = {
color: "#ee5d5d",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,9,12,1600,3100,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_hypergiant = {
color: "#719df4",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,8,11,18000,84000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_hypergiant = {
color: "#f7f990",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,8,11,5000,10000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
/* //Commented debug code: Yellow ultragiant spawner definition but for after the game has already fully loaded
elements.yellow_ultragiant = {
color: convertColorFormats("#f7f990","rgb"),
colorObject: convertColorFormats("#f7f990","json"),
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,14,17,5000,11000,Math.random);
},
category: "stars",
state: "gas",
density: 1000,
id: nextid,
};
nextid++;
elementCount++;
createElementButton("yellow_ultragiant");*/
//luminosity class -I
elements.red_ultragiant = {
color: "#f04343",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,15,18,1500,3000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_ultragiant = {
color: "#5488f0",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,14,17,17000,85000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_ultragiant = {
color: "#fafc7e",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,14,17,4500,9500,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
//luminosity class -II
elements.red_super_ultragiant = {
color: "#f23329",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,21,25,1400,2900,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_super_ultragiant = {
color: "#3b85ed",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,20,24,16000,86000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_super_ultragiant = {
color: "#fcfc65",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,20,24,4000,9000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
//luminosity class -III
elements.red_hyper_ultragiant = {
color: "#f51a0f",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,28,31,1300,2800,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_hyper_ultragiant = {
color: "#1b8bf2",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,27,30,15000,87000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_hyper_ultragiant = {
color: "#faeb46",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,27,30,4000,8500,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
//luminosity class -IV
elements.red_ultra_ultragiant = {
color: "#e01a00",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,34,37,1200,2700,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.blue_ultra_ultragiant = {
color: "#0782ed",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,33,36,14000,88000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
elements.yellow_ultra_ultragiant = {
color: "#f7d52a",
behavior: behaviors.WALL,
tick: function(pixel) {
seededCreateLargeStar(pixel.x,pixel.y,33,36,4000,8000,Math.random);
},
category: "stars",
state: "gas",
excludeRandom: true,
maxSize: 1,
cooldown: defaultCooldown,
density: 1000,
};
function rebuildWorldgenList() { //vanilla code
document.getElementById("worldgenselect").innerHTML = '';
for (var key in worldgentypes) {
document.getElementById("worldgenselect").innerHTML += "";
};
};
function bareClear() {
currentPixels = [];
pixelMap = [];
for (var i = 0; i < width; i++) {
pixelMap[i] = [];
for (var j = 0; j < height; j++) {
pixelMap[i][j] = undefined;
}
}
};
function alertIfError(alertError,text) {
if(alertError) {
alert(text);
return(true);
} else {
return(false);
}
}
function alertIfOutput(alertOutput,text) {
if(alertOutput) {
alert(text);
return(true);
} else {
return(false);
}
}
function parsefloatFirst(arr) { var array = arr; array[0] = parseFloat(array[0]); return array };
function stringToLayers(string) {
return string.split(";").map(x => x.split(":")).map(y => parsefloatFirst(y));
};
function validateSingleHexCode(hexCode) {
return !!_cc.w.h.match(/^#[0-9A-F]{6}$/);
};
function validateHexColorArray(colorsArray) {
if(!(colorsArray instanceof Array)) {
return false;
};
if(colorsArray.length == 0) {
return false;
};
var colorsIsValid = 1;
for(var i in colorsArray) {
colorsIsValid *= validateSingleHexCode(colorsArray[i]);
};
return !!colorsIsValid;
};
function validateSingleLayer(layerArray) {
if(layerArray.length < 2) {
return false;
};
if(isNaN(layerArray[0])) {
return false;
};
if(typeof(layerArray[1]) !== "string") {
return false;
};
if(!elements[layerArray[1]]) {
return false;
};
if(typeof(layerArray[2]) !== "undefined") {
if(isNaN(layerArray[2])) {
return false
};
};
return true;
};
function validateLayersStructure(layersArray) {
if(!(layersArray instanceof Array)) {
return false;
};
if(layersArray.length == 0) {
return false;
};
var layersIsValid = 1;
for(var i in layersArray) {
layersIsValid *= validateSingleLayer(layersArray[i]);
};
return !!layersIsValid;
};
function stringToDecor(string) {
decorLayers = string.split(";").map(x => x.split(":"));
for(var q in decorLayers) {
var decorLayer = decorLayers[q];
if(decorLayer[1]) {
decorLayer[1] = parseFloat(decorLayer[1]);
};
if(decorLayer[2]) {
decorLayer[2] = parseInt(decorLayer[2]);
};
if(decorLayer[3]) {
decorLayer[3] = decorLayer[3].split(",");
};
};
return decorLayers;
};
//console.log(stringToDecor("bird:0.025:10:#FF0000,#FFFF00,#00FF00"));
function validateSingleDecorLayer(decorLayer) {
if(decorLayer.length < 2) {
return false;
};
if(!elements[decorLayer[0]]) {
return false;
};
if(isNaN(decorLayer[1])) {
return false;
};
if(typeof(decorLayer[2]) !== "undefined") {
if(isNaN(decorLayer[2])) {
return false;
};
};
if(typeof(decorLayer[3]) !== "undefined") {
if(!(validateHexColorArray(decorLayer[3]))) {
return false;
};
};
return true;
};
function validateDecorStructure(decorArraysArray) {
if(!(decorArraysArray instanceof Array)) {
return false;
};
if(decorArraysArray.length == 0) {
return false;
};
var decorIsValid = 1;
for(var i in decorArraysArray) {
decorIsValid *= validateSingleDecorLayer(decorArraysArray[i]);
};
return !!decorIsValid;
};
function funniPrompt(argument=null,alertOutput=true,alertError=true) {
argument === null ? inputText = prompt("Enter command") : inputText = argument;
// replace spaces with underscores
if(["",null].includes(inputText)) {
console.log("Prompt canceled");
return false;
};
//console.log(inputText);
if(inputText.includes("|")) {
var commands = inputText.split("|");
var results = []; results.length = commands.length;
for(var cmdi in commands) {
commands[cmdi] = commands[cmdi].trim();
try {
results[cmdi] = funniPrompt(commands[cmdi]);
} catch(error) {
results[cmdi] = error;
};
};
console.log(results);
return results;
};
inputAsArray = inputText.split(" ");
var firstItem = inputAsArray[0];
switch(firstItem.toLowerCase()) {
case "set":
if(inputAsArray.length < 4) {
alertIfError(alertError,"Usage: set [property] [element] [value] \nDon't include framing characters []<>.\nThe element can be \"all\" to set the property for every pixel.\nNote: Strings can't have spaces because spaces are the separator used in the parsing split().\nArguments in [brackets] are required and ones in are optional.");
return false;
};
var property = inputAsArray[1];
//console.log("Property gotten: " + property);
var inputElement = inputAsArray[2];
//console.log("Element gotten: " + inputElement);
var value = inputAsArray[3];
//console.log("Value gotten: " + value);
var type = null; //dummy type for [value]-based assumption
if(inputAsArray.length >= 5) {
type = inputAsArray[4];
};
//console.log("Type gotten: " + type);
if(type === null) {
type = null; //catch null type
} else if(numberSynonyms.includes(type.toLowerCase())) {
type = "number";
} else if(booleanSynonyms.includes(type.toLowerCase())) {
type = "boolean";
} else if(stringSynonyms.includes(type.toLowerCase())) {
type = "string";
} else if(arraySynonyms.includes(type.toLowerCase())) {
type = "array";
} else if(objectSynonyms.includes(type.toLowerCase())) {
type = "object";
};
var typeWhitelist = [null,"string","number","boolean","array","object"];
if(!typeWhitelist.includes(type)) {
alertIfError(alertError,"Unrecognized type: \"" + type + "\".");
return false;
};
if(type === null) {
if(defaultStringTypeValues.includes(property)) {
type = "string";
} else if(defaultNumberTypeValues.includes(property)) {
type = "number";
} else if(defaultBooleanTypeValues.includes(property)) {
type = "boolean";
} else if(defaultArrayTypeValues.includes(property)) {
type = "array";
} else {
alertIfError(alertError,"Type could not be assumed from property. Please specify the type as a fourth argument.");
return false;
}
}
if(type === "number") {
value = parseFloat(value);
if(isNaN(value)) {
alertIfError(alertError,"Value is not a number!");
return false;
};
} else if(type === "boolean") {
if(synonymsOfTrue.includes(value.toLowerCase())) {
value = true;
} else if(synonymsOfFalse.includes(value.toLowerCase())) {
value = false;
} else {
alertIfError(alertError,"Unrecognized boolean value: " + value + ".");
return false;
}
} else if(type === "object") {
try {
value = JSON.parse(value);
} catch (error) {
alertIfError(alertError,"JSON is invalid! Note that it requires quotes around keys as well as those curly {} parentheses.");
return false;
};
} else if(type === "array") {
array = value.split(",");
for(i = 0; i < array.length; i++) {
if(array[i].startsWith("s")) { //String
array[i] = array[i].substring(1);
} else if(array[i].startsWith("n")) { //Number
array[i] = array[i].substring(1);
if(isNaN(parseFloat(array[i]))) {
alert(array[i] + " is not a number!");
return false;
};
array[i] = parseFloat(array[i]);
} else if(array[i].startsWith("o")) { //Object
array[i] = array[i].substring(1);
try {
array[i] = JSON.parse(array[i]);
} catch (error) {
alert(array[i] + " is not valid JSON!");
return false;
};
} else if(array[i].startsWith("b")) { //Boolean
array[i] = array[i].substring(1);
if(synonymsOfTrue.includes(array[i].toLowerCase())) {
array[i] = true;
} else if(synonymsOfFalse.includes(array[i].toLowerCase())) {
array[i] = false;
} else {
alert("Unrecognized boolean value: " + array[i] + ".");
return false;
};
} else {
alert(array[i] + ' must start with "s" for a string, "n" for a number, "o" for an object, or "b" for a boolean.');
return false;
};
};
value = array;
}
//The values start out as strings when split from the array, so string is kind of the default form.
//Special validation
if(property === "element") {
var originalInput = value; //for error display
value = mostSimilarElement(value);
if(!elements[value]) {
alertIfError(alertError,"Element " + originalInput + " does not exist!");
return false;
}
};
if(property === "x") {
if(!Number.isSafeInteger(value)) {
alertIfError(alertError,"X cannot be a decimal! And what are you doing trying to set position values anyway?");
return false;
}
};
if(property === "color") {
if(!value.startsWith("rgb(")) { //if not RGB
if(value.startsWith("hsl(")) { //if HSL
if(!(value.split(",")[1].endsWith('%')) || !(value.split(",")[2].endsWith('%)'))) { //if missing percent symbols
alertIfError(alertError,colorInvalidError);
return false;
};
} else { //if not RGB and not HSL
alertIfError(alertError,colorInvalidError);
return false;
};
}
if(value.split(",").length !== 3) { //if too short or long
alertIfError(alertError,colorInvalidError);
return false;
}
if(value.startsWith("rgb(")) { //if RGB
var checkedColorObject = rgbStringToUnvalidatedObject(value); //RGB NaN checking
if(isNaN(checkedColorObject.r) || isNaN(checkedColorObject.g) || isNaN(checkedColorObject.b)) {
//console.log(checkedColorObject);
alertIfError(alertError,"One or more color values are invalid!");
return false;
};
} else if(value.startsWith("hsl(")) { //if HSL
var checkedColorObject = hslStringToUnvalidatedObject(value); //HSL NaN checking
if(isNaN(checkedColorObject.h) || isNaN(checkedColorObject.s) || isNaN(checkedColorObject.l)) {
//console.log(checkedColorObject);
alertIfError(alertError,"One or more color values are invalid!");
return false;
};
} else { //if neither
alertIfError(alertError,colorInvalidError);
return false;
};
};
//Actual setting code;
var setCount = 0;
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
if (!isEmpty(i,j)) {
//console.log("Pixel (" + i + "," + j + ") exists")
if(pixelMap[i][j].element === inputElement || inputElement === "all") {
//console.log("Element is a match: " + inputElement + ", " + pixelMap[i][j].element)
pixelMap[i][j][property] = value;
if(property == "temp") { pixelTempCheck(pixelMap[i][j]) };
setCount++;
};
};
};
};
inputElement === "all" ? alertIfOutput(alertOutput,`Set ${property} of ${setCount} pixels to ${value}.`) : alertIfOutput(alertOutput,`Set ${property} of ${setCount} ${inputElement} pixels to ${value}.`)
return true;
case "deleteall":
var elementSpecified = false;
var attemptedCommaSplitOfPossibleElementSpecification = inputAsArray[1].split(","); //a comma-less string becomes a single-string array so it should still detect something like "deleteall fire"
var possibleElementsInACSOPES = attemptedCommaSplitOfPossibleElementSpecification.filter(elementExists);
elementSpecified = (possibleElementsInACSOPES.length > 0);
if(!elementSpecified) {
inputAsArray = inputAsArray.join(" ").replace("deleteall","delete all").split(" ")
};
//fall through to delete
case "delete":
if(inputAsArray.length < 2) {
alertIfError(alertError,"Usage: delete [element] \nDon't include framing characters []<>.\nThe element can be \"all\" to clear the canvas.\nNote: Strings can't have spaces because spaces are the separator used in the parsing split().\nArguments in [brackets] are required and ones in are optional.");
return false;
};
var inputElement = inputAsArray[1];
if(inputElement.indexOf(",") >= 0) {
inputElement = Array.from(new Set(inputElement.split(",")));
if(inputElement.includes("all")) {
inputElement = "all"
}
};
var probability;
if(inputAsArray[2]) {
probability = inputAsArray[2];
if(probability.match(/(%|cent|per_?hundred|ph)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 100
}
} else if(probability.match(/(‰|mille|per_?thousand)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 1000
}
} else if(probability.match(/(‱|myriad|per_?ten_?thousand|basis_?point|bp)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 10000
}
} else if(probability.match(/(ppm|parts_?per_?million)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 1e6
}
} else if(probability.match(/(ppb|parts_?per_?billion)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 1e9
}
} else if(probability.match(/(ppt|parts_?per_?trillion)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 1e12
}
} else if(probability.match(/(ppq|parts_?per_?quadrillion)$/i)) {
probability = probability.match(/\d+(\.\d+|)/)?.[0];
if(!probability) {
probability = 1
} else {
probability = parseFloat(probability) / 1e15
}
} else if(probability.match(/\d\.?[\/÷]\.?\d/)) {
probability = probability.split(/[\/÷]/).map(x => parseFloat(x));
if(isNaN(probability[0]) || isNaN(probability[1])) {
probability = 1
} else {
probability = probability[0] / probability[1]
}
} else {
var parsedProbability = parseFloat(probability);
if(isNaN(parsedProbability)) {
probability = 1
} else {
probability = parsedProbability;
if(probability > 1) { probability /= 100 }
}
}
} else {
probability = 1
};
//Actual setting code;
var deleteCount = 0;
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
if (!isEmpty(i,j)) {
//console.log("Pixel (" + i + "," + j + ") exists")
var doDelete = inputElement === "all" || (Array.isArray(inputElement) ? inputElement.includes(pixelMap[i][j].element) : pixelMap[i][j].element == inputElement);
if(doDelete) {
if(Math.random() < probability) {
deletePixel(i,j);
deleteCount++
}
}
}
}
};
var outputString = Array.isArray(inputElement) ? englishFormatList(inputElement) : inputElement;
inputElement === "all" ? alertIfOutput(alertOutput,`Deleted ${deleteCount} pixels.`) : alertIfOutput(alertOutput,`Deleted ${deleteCount} total ${outputString} pixels.`)
return true;
case "test":
alertIfOutput(alertOutput,"pong");
console.log("qwertyuiopasdfghjklzxcvbnm");
return true;
case "setdimensions":
if(inputAsArray.length < 3) {
alertIfError(alertError,commandHelpObject.setdimensions);
return false;
};
var argWidth = inputAsArray[1];
var argHeight = inputAsArray[2];
var argPixelSize = inputAsArray[3];
if(argWidth == undefined) {
alertIfError(alertError,commandHelpObject.setdimensions);
return false;
} else {
argWidth = parseInt(argWidth);
if(isNaN(argWidth)) {
alert("Error: width was NaN");
console.error("setdimensions: supplied width was NaN");
return false;
} else {
if(argWidth < 1) {
alert("Width must be greater than 0");
console.error("setdimensions: supplied width was zero or negative");
return false;
};
};
};
if(argHeight == undefined) {
alertIfError(alertError,commandHelpObject.setdimensions);
return false;
} else {
argHeight = parseInt(argHeight);
if(isNaN(argHeight)) {
alert("Error: height was NaN");
console.error("setdimensions: supplied height was NaN");
return false;
} else {
if(argHeight < 1) {
alert("Height must be greater than 0");
console.error("setdimensions: supplied height was zero or negative");
return false;
};
};
};
if(argPixelSize == undefined) {
argPixelSize = null;
} else {
argPixelSize = parseFloat(argPixelSize);
if(isNaN(argPixelSize)) {
argPixelSize = null;
alert("pixelSize was NaN, ignoring");
console.log("setdimensions: supplied pixelSize was NaN");
} else {
if(argPixelSize <= 0) {
alert("Pixel size was non-positive, ignoring");
console.error("setdimensions: supplied pixel size was zero or negative");
argPixelSize = null;
};
};
};
width = argWidth + 1;
height = argHeight + 1;
if(typeof(argPixelSize) === "number" && argPixelSize !== null && !isNaN(argPixelSize)) {
if(argPixelSize > 0) {
pixelSize = argPixelSize;
};
};
clearAll();
return true;
case "pixelsize":
if(inputAsArray.length < 1) { //?
alertIfError(alertError,commandHelpObject.setpixelsize);
return false;
};
var argPixelSize = inputAsArray[1];
if(argPixelSize == undefined) {
argPixelSize = null;
} else {
argPixelSize = parseFloat(argPixelSize);
if(isNaN(argPixelSize)) {
alert("Error: size was NaN");
console.error("pixelsize: supplied pixel size was NaN");
return false;
};
};
if(typeof(argPixelSize) === "number" && argPixelSize !== null && !isNaN(argPixelSize)) {
if(argPixelSize <= 0) {
alert("Pixel size must be greater than 0");
console.error("pixelsize: supplied pixel size was zero or negative");
return false;
} else {
var confirmation = confirm("Due to changes in the game, this command must reset the canvas. Proceed?")
if(confirmation) {
document.querySelector('span[setting="pixelsize"]').querySelector("select").selectedIndex = pixelSizeSettingDropdownOtherOptionIndex;
settings.pixelsize = argPixelSize;
resizeCanvas(ctx.canvas.height,ctx.canvas.width,settings.pixelsize,false);
clearAll();
return argPixelSize
} else {
return false
}
};
} else {
alert(pixelSize);
};
return pixelSize;
case "dimensions":
if(inputAsArray.length < 1) { //?
alertIfError(alertError,commandHelpObject.dimensions);
return false;
};
alert(`width: ${width}
height: ${height}
(Usable area is 1 pixel less in both dimensions)`);
return [width,height];
case "fill":
if(inputAsArray.length < 3) {
alertIfError(alertError,commandHelpObject.fill);
return false;
};
var doOverwrite = inputAsArray[1];
var elementList = inputAsArray.slice(2);
//console.log(elementList);
for(i = 0; i < elementList.length; i++) {
var elementInConsideration = elementList[i]
var originalElement = elementInConsideration; //also for error display
elementInConsideration = mostSimilarElement(elementInConsideration);
if(!elements[elementInConsideration]) {
alertIfError(alertError,"Element " + originalElement + " does not exist!");
return false;
}
elementList[i] = elementInConsideration;
};
//console.log(elementList);
if(synonymsOfTrue.includes(doOverwrite.toLowerCase())) {
doOverwrite = true;
} else if(synonymsOfFalse.includes(doOverwrite.toLowerCase())) {
doOverwrite = false;
} else {
alertIfError(alertError,"Unrecognized boolean value: " + doOverwrite + "\n Note that for this command, the boolean value goes first.");
return false;
}
//console.log(doOverwrite);
//console.log(elementList);
//Fill code
var fillCount = 0;
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
var randomElement = elementList[Math.floor(Math.random() * elementList.length)];
if(doOverwrite) {
if(!isEmpty(i,j,true)) { deletePixel(i,j) };
};
if (isEmpty(i,j,false)) {
createPixel(randomElement,i,j);
fillCount++;
};
};
};
alertIfOutput(alertOutput,`Placed ${fillCount} pixels`);
return fillCount;
case "randomfill":
if(inputAsArray.length < 1) { //somehow?
alertIfError(alertError,"Usage: randomfill \nDon't include framing characters []<>.\nArguments in are optional.");
return false;
};
var doOverwrite = null;
if(inputAsArray.length > 1) {
var doOverwrite = inputAsArray[1];
if(synonymsOfTrue.includes(doOverwrite.toLowerCase())) {
doOverwrite = true;
} else if(synonymsOfFalse.includes(doOverwrite.toLowerCase())) {
doOverwrite = false;
} else {
alertIfError(alertError,"Unrecognized boolean value: " + value);
return false;
};
} else {
doOverwrite = true;
};
var elementList = randomChoices;
//Fill code
var fillCount = 0;
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
var randomElement = elementList[Math.floor(Math.random() * elementList.length)];
if(doOverwrite) {
if(!isEmpty(i,j,true)) { deletePixel(i,j) };
};
if (isEmpty(i,j,false)) {
createPixel(randomElement,i,j);
fillCount++;
};
};
};
alertIfOutput(alertOutput,`Placed ${fillCount} random pixels`);
return fillCount;
case "count":
if(inputAsArray.length < 2) {
alertIfError(alertError,"Usage: count [element]\nDon't include framing characters []<>.\nNote: The element name can't have a space in it because spaces are the separator used in the parsing split().\nArguments in [brackets] are required.");
return false;
};
var inputElement = inputAsArray[1];
//console.log("Element gotten: " + inputElement);
var originalInput = inputElement; //for error display
inputElement = mostSimilarElement(inputElement);
//console.log("Element gotten: " + inputElement);
if(typeof(elements[inputElement]) === "undefined") {
alertIfError(alertError,"Element " + originalInput + " does not exist!");
return false;
}
//Actual counting code;
var count = 0;
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
if (!isEmpty(i,j)) {
//console.log("Pixel (" + i + "," + j + ") exists")
if(pixelMap[i][j].element === inputElement) {
//console.log("Element is a match: " + inputElement + ", " + pixelMap[i][j].element)
count++;
};
};
};
};
alertIfOutput(alertOutput,`There are ${count} pixels of ${inputElement}`);
return count;
case "countall":
var listObject = {};
//Listing code;
for (var i = 1; i < width; i++) {
for (var j = 1; j < height; j++) {
if (!isEmpty(i,j)) {
var pixel = pixelMap[i][j];
var element = pixel.element;
if(!listObject[pixel.element]) {
listObject[pixel.element] = 1;
} else {
listObject[pixel.element]++;
}
};
};
};
var formattedList = "";
var zelements = Object.keys(listObject);
for(k = 0; k < zelements.length; k++) {
var elementName = zelements[k];
var elementCount = listObject[elementName];
formattedList += `${elementName}: ${elementCount}\n`;
};
alertIfOutput(alertOutput,"Elements counts logged to console");
console.log(formattedList);
return listObject;
case "wg":
case "worldgen":
if(inputAsArray.length < 1) {
alertIfError(alertError,commandHelpObject.worldgen);
return false;
};
var action = inputAsArray[1];
if(!action) {
alertIfOutput(`Current worldgen setting: ${settings.worldgen}`);
return settings.worldgen;
};
var worldgenTypesList = Object.keys(worldgentypes).concat(["off"]);
if(["list","lst","ls","l"].includes(action)) {
alertIfOutput(alertOutput,worldgenTypesList.join(", "));
console.log(worldgenTypesList.map(x => " " + x).join("\n"));
return worldgenTypesList;
} else {
var targetPreset = inputAsArray[2];
if(!targetPreset) {
alertIfError(alertError,commandHelpObject.worldgen);
return false;
};
if(!(worldgenTypesList.includes(targetPreset))) {
alertIfError(alertError,`No such preset ${targetPreset}!`);
return false;
};
if(["select","sel","pick","set","s"].includes(action)) {
settings.worldgen = targetPreset;
alertIfOutput(alertOutput,`Worldgen setting set to ${targetPreset}`);
return true;
} else if(["generate","gen","make","worldgen","wg","g","w","world","run","do","world"].includes(action)) {
bareClear();
if(targetPreset == "off") {
alertIfOutput(alertOutput,`Cleared world`);
} else {
console.log(targetPreset,worldgentypes[targetPreset].complexity);
worldGen(worldgentypes[targetPreset]);
alertIfOutput(alertOutput,`Generated preset ${targetPreset}`);
};
return true;
} else {
alertIfError(alertError,commandHelpObject.worldgen);
return false;
};
};
return true;
case "dwg":
case "defineworldgen":
if(inputAsArray.length < 3) {
alertIfError(commandHelpObject.defineworldgen);
alertIfError(commandHelpObject.defineworldgen2);
return false;
};
var presetName = inputAsArray[1];
//overwrite confirm below
var newPreset = {};
var layers = stringToLayers(inputAsArray[2]);
if(!validateLayersStructure(layers)) {
alertIfError(alertError,"Layers definition is invalid or malformed!");
return false;
};
newPreset.layers = layers;
var baseHeight = inputAsArray[3];
if(typeof(baseHeight) !== "undefined") {
if(promptInputNullishes.includes(baseHeight)) {
baseHeight = "0.5";
};
baseHeight = parseFloat(baseHeight);
if(isNaN(baseHeight)) {
alertIfError(alertError,"Invalid baseHeight!");
return false;
};
newPreset.baseHeight = baseHeight;
};
var heightVariance = inputAsArray[4];
if(typeof(heightVariance) !== "undefined") {
if(promptInputNullishes.includes(heightVariance)) {
heightVariance = "0.5";
};
heightVariance = parseFloat(heightVariance);
if(isNaN(heightVariance)) {
alertIfError(alertError,"Invalid heightVariance!");
return false;
};
newPreset.heightVariance = heightVariance;
};
var complexity = inputAsArray[5];
if(typeof(complexity) !== "undefined") {
if(promptInputNullishes.includes(complexity)) {
complexity = "20";
};
complexity = parseFloat(complexity);
if(isNaN(complexity)) {
alertIfError(alertError,"Invalid complexity!");
return false;
};
newPreset.complexity = complexity;
};
var temperature = inputAsArray[6];
if(typeof(temperature) !== "undefined") {
if(promptInputNullishes.includes(temperature.toLowerCase())) {
temperature = null;
} else {
temperature = parseFloat(temperature);
if(isNaN(temperature)) {
alertIfError(alertError,"Invalid temperature!");
return false;
};
newPreset.temperature = temperature;
};
};
var decor = inputAsArray[7];
if(typeof(decor) !== "undefined") {
decor = stringToDecor(decor);
if(!validateDecorStructure(decor)) {
alertIfError(alertError,"Decor definition is invalid or malformed!");
return false;
};
newPreset.decor = decor;
};
if(worldgentypes[presetName]) {
var doOverwrite = confirm(`Overwrite worldgen preset ${presetName}?`);
if(!doOverwrite) {
alertIfError(alertError,"defineworldgen canceled");
return false;
};
};
worldgentypes[presetName] = newPreset;
customWorldTypes[presetName] = newPreset;
localStorage.setItem("customWorldTypes",JSON.stringify(customWorldTypes));
settings.worldgen = presetName;
rebuildWorldgenList();
alertIfOutput(alertOutput, `Defined worldgen preset ${presetName}.
Make sure to save your command in a file if you want to add this preset again.`
);
console.log(inputText);
return [presetName,newPreset];
case "stars":
var starDensity = inputAsArray[1];
var seed = inputAsArray[2]; //〜カクセイ〜
if(starDensity == undefined) {
starDensity = 0.001
} else {
starDensity = parseFloat(starDensity);
if(isNaN(starDensity)) {
alert("starDensity was NaN, defaulting to 0.001");
starDensity = 0.001;
};
};
var stringSeed = false;
var seedString = null;
if(seed === undefined) {
seed = Math.random();
stringSeed = false;
} else {
if(isNaN(parseFloat(seed))) {
stringSeed = true;
seedString = seed;
seed = cyrb128(seed)[2];
} else {
stringSeed = false;
seed = parseFloat(seed);
};
};
lastStarSeed = stringSeed ? seedString : seed;
//console.log(stringSeed);
//console.log(lastStarSeed);
var randomFunction = mulberry32(seed);
clearAll();
for(j = 1; j < height; j++) {
for(i = 1; i < width; i++) {
if(randomFunction() < starDensity) {
if(isEmpty(i,j,false)) {
var value = randomFunction() ** 4;
if(value < 0.3) {
createPixelReturn("sun",i,j).temp = seededRandBetween(1800,3300,randomFunction);
} else if(value < 0.55) {
createPixelReturn("sun",i,j).temp = seededRandBetween(3300,5500,randomFunction);
} else if(value < 0.70) {
createPixelReturn("sun",i,j).temp = seededRandBetween(5500,8000,randomFunction);
} else if(value < 0.8) {
createPixelReturn("sun",i,j).temp = seededRandBetween(8000,13000,randomFunction);
} else if(value < 0.85) {
createPixelReturn("sun",i,j).temp = seededRandBetween(13000,35000,randomFunction);
} else if(value < 0.88) {
createPixelReturn("sun",i,j).temp = seededRandBetween(35000,90000,randomFunction);
} else { //other stuff
var value2 = randomFunction();
if(value2 < 0.5) { //giant stars
var value3 = randomFunction();
if(value3 < 0.6) { //favor red giants
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(3,4,randomFunction));
var randTemp = seededRandBetween(1800,3300,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
} else if(value3 < 0.9) { //blue giants are rarer
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(2,3,randomFunction));
var randTemp = seededRandBetween(20000,80000,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
} else { //yellows are even rarer
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(2,3,randomFunction));
var randTemp = seededRandBetween(6000,11000,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
};
} else if(value2 < 0.6) { //supergiants
var value3 = randomFunction();
if(value3 < 0.6) {
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(6,8,randomFunction));
var randTemp = seededRandBetween(1700,3200,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
} else if(value3 < 0.9) {
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(5,7,randomFunction));
var randTemp = seededRandBetween(19000,83000,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
} else {
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(5,6,randomFunction));
var randTemp = seededRandBetween(5500,10500,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
};
} else if(value2 < 0.65) { //hypergiants
var value3 = randomFunction();
if(value3 < 0.6) {
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(9,12,randomFunction));
var randTemp = seededRandBetween(1600,3100,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
} else if(value3 < 0.94) {
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(8,11,randomFunction));
var randTemp = seededRandBetween(18000,84000,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
} else {
var sunPixels = fillCircleReturn("sun",i,j,seededRandBetween(8,11,randomFunction));
var randTemp = seededRandBetween(5000,10000,randomFunction);
for(pixel in sunPixels) {
sunPixels[pixel].temp = randTemp;
};
};
} else if(value2 < 0.8) { //white dwarfs/neutron stars
if(randomFunction() < 0.8) { //favor white dwarfs
createPixelReturn("sun",i,j).temp = seededRandBetween(100000,300000,randomFunction);
} else {
if(!elements.neutron_star) {
createPixelReturn("sun",i,j).temp = seededRandBetween(100000,300000,randomFunction);
} else {
createPixelReturn("neutron_star",i,j).temp = seededRandBetween(2000000,10000000,randomFunction);
};
};
} else { //brown dwarfs
createPixelReturn("sun",i,j).temp = seededRandBetween(100,800,randomFunction);
};
};
};
};
};
};
return true;
break;
case "kakusei":
case "starseed":
alertIfOutput(alertOutput,lastStarSeed);
console.log(lastStarSeed);
return lastStarSeed;
case "help":
var commandsWithoutDwg2 = Object.keys(commandHelpObject).filter(function(cmdName) { return cmdName !== "defineworldgen2" });
if(inputAsArray.length < 1) { //somehow
alertIfError(alertError,"Usage: help \nDon't include framing characters []<>.\nArguments in are optional.");
return false;
};
if(inputAsArray.length < 2) {
alertOutput ? alertIfOutput(alertOutput,"Commands: " + commandsWithoutDwg2.join("\n")) : console.log("Commands: " + commandsWithoutDwg2.join(", "));
} else {
var command = inputAsArray[1];
if(typeof(commandHelpObject[command]) === "undefined" || command == "defineworldgen2") {
alertIfError(alertError,"Cound not find help for " + command + ".");
return false;
} else {
if(command == "defineworldgen") {
if(alertOutput) {
alert(commandHelpObject.defineworldgen);
alert(commandHelpObject.defineworldgen2);
} else {
console.log(commandHelpObject.defineworldgen + "\n" + commandHelpObject.defineworldgen2);
};
} else {
if(alertOutput) {
alert(commandHelpObject[command]);
} else {
console.log(commandHelpObject[command]);
};
};
return true;
};
};
return true;
default:
alertIfError(alertError,`Command ${firstItem} not found!`);
return false;
};
};
document.addEventListener("keydown", function(e) { //prop prompt listener
// , = propPrompt()
if ([1,3].includes(shiftDown) && e.keyCode == 49) { //either shift + 1
funniPrompt();
};
});
elements.funni_prompt = {
color: [_cc.b.h,"#00ff00",_cc.b.h,"#00ff00",_cc.b.h,"#00ff00",_cc.b.h,"#00ff00",_cc.b.h,"#00ff00"],
behavior: behaviors.SELFDELETE,
desc: "Click here or press Shift+1 to open the command prompt.",
category:"special",
};
console.log("5/8 loaded");
//REPLACER TOOL ##
changeTo = "sand";
document.addEventListener("keydown", function(e) { //change prompt listener
// r = changeElementPrompt()
if (e.keyCode == 186) {
e.preventDefault();
changeElementPrompt();
}
});
function changeElementPrompt() {
var cmToElement = prompt("Enter what you want to change pixels to");
if(cmToElement == null) { return };
// replace spaces with underscores
cmToElement = cmToElement.replace(/ /g, "_");
cmToElementS = mostSimilarElement(cmToElement);
if (cmToElementS === null || cmToElementS === undefined || cmToElementS === "") {
alert("Element \"" + cmToElement + "\" not found! Defaulting to sand.");
cmToElementS = "sand";
};
changeTo = cmToElementS;
updateChangeDescriptions();
}
function updateChangeDescriptions() {
elements.change.desc = "Changes any pixels it is used on to a specified type. Currently replacing pixels with \"" + changeTo + "\". Press [;] or click here to open the change prompt.";
elements.alt_change.desc = "Changes any pixels it is used on to a specified type, but keeping their non-element-based properties. Currently replacing pixels with \"" + changeTo + "\". Press [;] or click here to open the change prompt.";
elements.alt_alt_change.desc = "Changes any pixels it is used on to a specified type, but keeping their non-element-based properties except for color. Currently replacing pixels with \"" + changeTo + "\". Press [;] or click here to open the change prompt.";
};
elements.change = {
color: ["#ff0000", "#ff0000", "#ff0000", "#7f00ff", "#0000ff", "#0000ff", "#0000ff"],
tool: function(pixel) {
changePixel(pixel,changeTo,true);
},
category: "tools",
desc: "Changes any pixels it is used on to a specified type. Currently replacing pixels with \"" + changeTo + "\". Press [;] or click here to open the change prompt.",
};
elements.alt_change = {
color: ["#ffff00", "#ffff00", "#ffff00", "#cf7f4f", "#ff00ff", "#ff00ff", "#ff00ff"],
tool: function(pixel) {
pixel.element = changeTo;
},
category: "tools",
desc: "Changes any pixels it is used on to a specified type, but keeping their non-element-based properties. Currently replacing pixels with \"" + changeTo + "\". Press [;] or click here to open the change prompt.",
hidden: true,
};
elements.alt_alt_change = {
color: ["#00ff00", "#00ff00", "#00ff00", "#cfcf00", "#ff0000", "#ff0000", "#ff0000"],
tool: function(pixel) {
pixel.element = changeTo;
pixel.color = pixelColorPick(pixel);
},
category: "tools",
desc: "Changes any pixels it is used on to a specified type, but keeping their non-element-based properties except for color. Currently replacing pixels with \"" + changeTo + "\". Press [;] or click here to open the change prompt.",
hidden: true,
};
//ADDITIONAL RAYS ##
runAfterAutogen(function() {
snowAndIceCache = Object.keys(elements).filter(function(name) {
return name.endsWith("snow") || name.endsWith("ice") || name == "rime"
})
});
lightlikes = ["light","flash","laser","radiation","insulate_flash"];
firelikes = ["fire","plasma","smoke","stellar_plasma","liquid_plasma","liquid_stellar_plasma"];
grbBreakIntos = Object.keys(elements).filter(function(elemName) {
var to = typeof(elements[elemName]);
if(to == "undefined") {
return false
} else {
var to2 = typeof(elements[elemName].breakInto);
if(to2 == "undefined") {
return false
} else {
if(elements[elemName].breakInto instanceof Array) {
return elements[elemName].breakInto.includes("gamma_ray_burst")
} else {
return elements[elemName].breakInto == "gamma_ray_burst"
}
}
}
});
elements.insulate_flash = {
hidden: true,
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.cold_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.cold_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
};
elements.melt_ray = {
color: ["#ffbf7f","#ffffbf"],
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: Heat, always penetrate
if (otherInfo.isGas) {
if(Math.random() < 0.05 && otherInfo.stateLow) {
meltPixel(otherPixel)
};
if(elements[otherPixel.element].isSun) {
otherPixel.temp += 0.5;
} else {
otherPixel.temp += 50;
};
continue;
};
//Self: Break
if (otherInfo.id === elements.melt_ray.id) { break }
//Non-gas, Melt chance, heat more, half penetrate
if(Math.random() < 0.05 && !otherInfo.isGas) {
meltPixel(otherPixel)
};
pixelMap[x][y].temp += 200;
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 newPlasma = tryCreatePixelReturn("liquid_plasma",x,y-1);
if(newPlasma) { newPlasma.temp += 500 };
};
//Penetrate snow and ice
if(firelikes && firelikes.includes(otherPixel.element)) {
continue;
};
if(Math.random() < 0.7) { //thanks, I hate random continue
continue;
};
break;
}
}
deletePixel(pixel.x, pixel.y);
},
temp: 4000,
category: "energy",
state: "gas",
excludeRandom: true,
noMix: true
};
elements.smash_ray = {
color: ["#ff9999", "#8c8279"],
tick: function(pixel) {
if(!pixel) { return };
if(pixel?.done) { deletePixel(pixel.x,pixel.y); return };
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(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(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;
}
}
}
pixel.done = true;
deletePixel(pixel.x, pixel.y);
},
temp: 20,
category: "energy",
state: "gas",
excludeRandom: true,
noMix: true
};
//combines heat ray and smash ray
elements.death_ray = {
color: ["#a88d77", "#ff4a36"],
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 = "#eb7b59";
}
else {
var otherPixel = pixelMap[x][y]
var otherInfo = elements[otherPixel.element];
otherPixel.temp += (400 * (shiftDown + 1));
if(otherPixel.del) { continue };
if (!(grbBreakIntos.includes(otherPixel.element))) {
if (otherInfo.isGas) {
if(Math.random() > ((otherInfo.hardness ?? 0) ** (4 + shiftDown))) { breakPixel(otherPixel,false,false) };
if(otherPixel && !(lightlikes.includes(otherPixel.element))) {
var vels = [randomIntegerBetweenTwoValues(-7 - (shiftDown * 2),7 + (shiftDown * 2)),randomIntegerBetweenTwoValues(-7 - (shiftDown * 2),7 + (shiftDown * 2))];
otherPixel.vx = vels[0];
otherPixel.vy = vels[1];
};
continue;
};
if (otherInfo.id === elements[pixel.element].id) { break }
if(Math.random() > ((otherInfo.hardness ?? 0) ** (2 + shiftDown))) { breakPixel(otherPixel,false,false) };
if(otherPixel) {
var vels = [randomIntegerBetweenTwoValues(-9 - (shiftDown * 2),9 + (shiftDown * 2)),randomIntegerBetweenTwoValues(-7 - (shiftDown * 2),0 + (shiftDown * 2))];
otherPixel.vx = vels[0];
otherPixel.vy = vels[1];
};
if(Math.random() < ((shiftDown / 20) + (Math.max(0.9,0.4 + ((1 - (otherInfo.hardness ?? 0)) / 2))))) { //thanks, I hate random continue
continue;
};
break;
}
}
}
deletePixel(pixel.x, pixel.y);
},
temp: 4000,
category: "energy",
state: "gas",
excludeRandom: true,
noMix: true
};
elements.annihilation_ray = {
color: ["#220c0c", "#c11515"],
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 = "#292929";
}
else {
var otherPixel = pixelMap[x][y];
var otherInfo = elements[otherPixel?.element];
if(otherPixel) {
otherPixel.temp += 2500 * (shiftDown + 1);
if(otherPixel.del || !otherPixel) { continue };
if (otherPixel && grbBreakIntos.includes(otherPixel.element)) {
if(Math.random() < 0.01 && otherPixel) {
deletePixel(otherPixel.x,otherPixel.y);
};
continue;
} else if(otherPixel) {
breakPixel(otherPixel,false,false);
if(otherPixel.del || !otherPixel) {
continue
};
if(otherPixel ) {
var vels = [randomIntegerBetweenTwoValues(-8,8),randomIntegerBetweenTwoValues(-6,0)];
otherPixel.vx = vels[0];
otherPixel.vy = vels[1];
};
if(otherPixel && Math.random() < (otherInfo.isGas ? 0.2 : 0.1)) {
deletePixel(otherPixel.x,otherPixel.y);
continue;
};
if(Math.random() > 0.8) {
continue;
};
};
if (otherInfo.id === elements[pixel.element].id) { break }
};
}
}
deletePixel(pixel.x, pixel.y);
},
temp: 150000000,
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 };
elements.bless.reactions.pus = { elem2: null };
elements.bless.reactions.crimson_grass = { elem2: "grass" };
elements.bless.reactions.crimstone = { elem2: "rock" };
elements.bless.reactions.crimsand = { elem2: "sand" };
elements.bless.reactions.red_ice = { elem2: "ice" };
elements.bless.reactions.crimgravel = { elem2: "gravel" };
elements.bless.reactions.crimwater = { elem2: "water" };
elements.bless.reactions.crimsnow = { elem2: "snow" };
elements.bless.reactions.vicious_mushroom = { elem2: null };
elements.bless.reactions.crimson_vine = { elem2: "vine" };
elements.bless.reactions.shadewood = { elem2: "wood" };
elements.bless.reactions.shadewood_tree_branch = { elem2: "tree_branch" };
elements.bless.reactions.shadewood_sapling = { elem2: "sapling" };
elements.bless.reactions.shadewood_sawdust = { elem2: "sawdust" };
elements.bless.reactions.crimson_leaf = { elem2: "leaf" };
elements.bless.reactions.ichor = { elem2: null }; //per blood, absent the gods' immune systems (if they're immortal then do they need immune systems?)
elements.bless.reactions.virus_bomb = { elem2: null };
elements.bless.reactions.life_eater_slurry = { elem2: null };
elements.bless.reactions.life_eater_explosion = { elem2: null };
elements.bless.reactions.life_eater_virus = { elem2: null };
elements.bless.reactions.injector_poison = { elem2: null };
elements.bless.reactions.dead_matter = { elem2: null };
elements.bless.reactions.life_eater_infected_dirt = { elem2: "dirt" };
elements.bless.reactions.poisoned_dirt = { func: function(pixel1,pixel2) {
// console.log(3);
// console.log(pixel1.element,pixel2.element);
if(pixel1.was && elementExists(pixel1.was)) {
changePixel(pixel1,pixel1.was,true)
} else {
changePixel(pixel1,"dirt",true)
}
}};
elements.bless.reactions.vicious_goldfish = { elem2: "fish" };
elements.bless.reactions.nellfire = { elem2: "bless" };
elements.bless.reactions.gloomwind = { elem2: null };
elements.bless.reactions.gloomfly = { elem2: null };
elements.bless.reactions.meat_monster = { elem2: null };
elements.bless.reactions.rotten_ravager = { elem2: null };
elements.bless.reactions.bone_beast = { elem2: null };
elements.bless.reactions.poisonwater = { elem2: "water" };
elements.bless.reactions.poisoned_ice = { elem2: "ice" };
elements.bless.reactions.poisoned_gas = { elem2: "steam" };
elements.bless.reactions.corrupt_land = { elem2: "dirt" };
elements.bless.reactions.corrupt_rock = { elem2: "rock" };
elements.bless.reactions.withery = { elem2: null };
elements.bless.reactions.withery_plant = { elem2: null };
elements.bless.reactions.corrupt_solid_rock = { elem2: "rock_wall" };
elements.bless.reactions.toxin = { elem2: "antidote" };
elements.bless.reactions.dead = { elem2: null };
elements.bless.reactions.brain = { elem2: null };
elements.bless.reactions.bio_ooze = { elem2: null };
elements.bless.tool = function(pixel) {
// console.log(10);
if (elements.bless.ignore.indexOf(pixel.element) !== -1) { return; }
if (pixel.burning && !elements[pixel.element].burning) { // stop burning
delete pixel.burning;
delete pixel.burnStart;
}
// console.log(11);
if (!elements[pixel.element].insulate) {
if (pixel.temp > 100) {
pixel.temp = (pixel.temp+100)/2;
pixelTempCheck(pixel);
if (pixel.del) {return}
}
if (pixel.temp < -200) {
pixel.temp = (pixel.temp-200)/2;
pixelTempCheck(pixel);
if (pixel.del) {return}
}
}
// console.log(12);
if (pixel.origColor) {
pixel.color = "rgb("+pixel.origColor.join(",")+")";
delete pixel.origColor;
}
// console.log(13);
if (pixel.charge) {
delete pixel.charge;
pixel.chargeCD = 16;
}
// console.log(14);
if (elements.bless.reactions[pixel.element] && Math.random()<0.25) {
var r = elements.bless.reactions[pixel.element];
var elem2 = r.elem2;
if (elem2 !== undefined) {
if (Array.isArray(elem2)) { elem2 = elem2[Math.floor(Math.random()*elem2.length)]; }
if (elem2 === null) { deletePixel(pixel.x,pixel.y) }
else { changePixel(pixel, elem2); }
}
if (r.func) { /*console.log(4);*/ r.func(pixel,pixel) }
if (r.color2) { pixel.color = pixelColorPick(pixel,r.color2) }
}
// console.log(15);
};
rayAbsorbElements = [];
rayPassElements = [];
function summonRay(element,xIn,intensity,radius) {
var forMin = 0 - radius;
var forMax = radius + 1;
if(intensity < 1) { return };
for(var i = forMin; i < forMax; i++) {
for(var j = 1; j < intensity + 1; j++) {
var pos = {x: xIn + i, y: j};
if(isEmpty(pos.x,pos.y)) {
createPixel(element,pos.x,pos.y)
} else {
if(outOfBounds(pos.x,pos.y)) {
break
} else {
var pixel = pixelMap[pos.x][pos.y];
var pElem = pixel.element;
var data = elements[pElem];
if(rayAbsorbElements.includes(pElem)) {
break
} else if(rayPassElements.includes(pElem)) {
continue
} else {
if(data.state == "gas") {
continue
} else {
break
}
}
}
}
}
}
};
elements.orbital_ray_beacon = {
color: "#ebdf91",
behavior: [
"XX|M2 AND SA|XX",
"SA|XX|SA",
"XX|M1|XX"
],
breakInto: ["steel_scrap","iron_scrap","copper_scrap","gold_scrap","battery","sapphire","magic"],
temp: 0,
tempHigh: 5010,
insulate: true,
conduct: 1,
stateHigh: ["molten_steel","molten_iron","molten_copper","molten_gold","acid_gas","titanium_gas","molten_sapphire","magic"],
tick: function(pixel) {
pixelTempCheck(pixel);
if(!pixel.charge) { return };
if(pixel.charge) {
//var intensity = Math.max(1,Math.floor((pixel.temp + 1) / 100));
if(isEmpty(pixel.x,pixel.y+1,true)) { return };
var pixelUnder = pixelMap[pixel.x]?.[pixel.y+1];
if(!pixelUnder) { return };
switch(pixelUnder.element) {
case "fire":
summonRay("heat_ray",pixel.x,10,5);
break;
case "ultramafic_magma":
case "magma":
case "intermediate_magma":
case "intermediate_felsic_magma":
case "felsic_magma":
case "nellish_magma":
case "rainbow_magma":
case "crimson_magma":
summonRay("heat_ray",pixel.x,16,10);
break;
case "vaporized_ultramafic_magma":
case "vaporized_magma":
case "vaporized_intermediate_magma":
case "vaporized_intermediate_felsic_magma":
case "vaporized_felsic_magma":
case "vaporized_nellish_magma":
case "vaporized_rainbow_magma":
case "vaporized_crimson_magma":
summonRay("heat_ray",pixel.x,24,18);
break;
case "greek_fire":
summonRay("heat_ray",pixel.x,16,25);
break;
case "quark_matter":
summonRay("heat_ray",pixel.x,45,80);
break;
case "cold_fire":
summonRay("cold_ray",pixel.x,10,5);
break;
case "chilly_water":
summonRay("cold_ray",pixel.x,14,8);
break;
case "frostwind":
summonRay("cold_ray",pixel.x,20,15);
break;
case "liquid_frostwind":
summonRay("cold_ray",pixel.x,30,20);
break;
case "gelid_cryotheum":
summonRay("cold_ray",pixel.x,36,25);
break;
case "snow":
summonRay("freeze_ray",pixel.x,3,6);
break;
case "slush":
summonRay("freeze_ray",pixel.x,4,6);
break;
case "packed_snow":
summonRay("freeze_ray",pixel.x,4,7);
break;
case "ice":
summonRay("freeze_ray",pixel.x,4,8);
break;
case "alcohol_ice":
summonRay("freeze_ray",pixel.x,6,11);
break;
case "liquid_nitrogen":
summonRay("freeze_ray",pixel.x,9,18);
break;
case "nitrogen_ice":
summonRay("freeze_ray",pixel.x,11,19);
break;
case "liquid_hydrogen":
summonRay("freeze_ray",pixel.x,14,26);
break;
case "hydrogen_ice":
summonRay("freeze_ray",pixel.x,15,27);
break;
case "liquid_helium":
summonRay("freeze_ray",pixel.x,18,34);
break;
case "tectonic_petrotheum":
summonRay("smash_ray",pixel.x,2,10);
break;
case "bomb":
case "tnt":
summonRay("smash_ray",pixel.x,5,7);
break;
case "cluster_bomb":
summonRay("death_ray",pixel.x,7,11);
break;
case "nuke":
summonRay("annihilation_ray",pixel.x,20,40);
break;
case "cluster_nuke":
summonRay("annihilation_ray",pixel.x,30,60);
break;
case "armageddon":
summonRay("annihilation_ray",pixel.x,40,80);
break;
};
//if(pixelUnder) { deletePixel(pixelUnder.x,pixelUnder.y) };
delete pixel.charge;
pixel.chargeCD = 4;
return true;
}
},
conduct: 1,
category: "machines",
hardness: 0.6
};
//PUSHERS ##
elements.up_pusher = {
color: "#9fafdf",
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x,pixel.y-1-i,true)) {
tryMove(pixelMap[pixel.x][pixel.y-1-i],pixel.x,pixel.y-2-i);
};
};
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.down_pusher = {
color: "#9fafdf",
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x,pixel.y+1+i,true)) {
tryMove(pixelMap[pixel.x][pixel.y+1+i],pixel.x,pixel.y+2+i);
};
};
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.left_pusher = {
color: "#9fafdf",
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x-1-i,pixel.y,true)) {
tryMove(pixelMap[pixel.x-1-i][pixel.y],pixel.x-2-i,pixel.y);
};
};
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.right_pusher = {
color: "#9fafdf",
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x+1+i,pixel.y,true)) {
tryMove(pixelMap[pixel.x+1+i][pixel.y],pixel.x+2+i,pixel.y);
};
};
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.up_e_pusher = {
color: "#9f9f6f",
properties: {
pushTime: 0,
},
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
showSetterColumn("numeric",2);
var p2 = document.getElementById("propertynumeric2input");
var p2h = document.getElementById("propertynumeric2heading");
if(p2) {
p2.setAttribute("set","ePusherLength");
p2.setAttribute("min","1");
p2.value = ambaPlaceProperties.ePusherLength;
};
if(p2h) {
p2h.innerText = "Duration";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
pixel.pushLength ??= (ambaPlaceProperties?.ePusherLength ?? 5);
pixel.pushTime ??= 0;
if(isNaN(pixel.pushTime) || pixel.pushTime < 0) { pixel.pushTime = 0 };
if(pixel.charge) {
pixel.pushTime = pixel.pushLength;
};
if(pixel.pushTime > 0) {
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x,pixel.y-1-i,true)) {
tryMove(pixelMap[pixel.x][pixel.y-1-i],pixel.x,pixel.y-2-i);
};
};
};
pixel.pushTime--;
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.down_e_pusher = {
color: "#9f9f6f",
properties: {
pushTime: 0,
},
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
showSetterColumn("numeric",2);
var p2 = document.getElementById("propertynumeric2input");
var p2h = document.getElementById("propertynumeric2heading");
if(p2) {
p2.setAttribute("set","ePusherLength");
p2.setAttribute("min","1");
p2.value = ambaPlaceProperties.ePusherLength;
};
if(p2h) {
p2h.innerText = "Duration";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
pixel.pushLength ??= (ambaPlaceProperties?.ePusherLength ?? 5);
pixel.pushTime ??= 0;
if(isNaN(pixel.pushTime) || pixel.pushTime < 0) { pixel.pushTime = 0 };
if(pixel.charge) {
pixel.pushTime = pixel.pushLength;
};
if(pixel.pushTime > 0) {
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x,pixel.y+1+i,true)) {
tryMove(pixelMap[pixel.x][pixel.y+1+i],pixel.x,pixel.y+2+i);
};
};
};
pixel.pushTime--;
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum0", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.left_e_pusher = {
color: "#9f9f6f",
properties: {
pushTime: 0,
},
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
showSetterColumn("numeric",2);
var p2 = document.getElementById("propertynumeric2input");
var p2h = document.getElementById("propertynumeric2heading");
if(p2) {
p2.setAttribute("set","ePusherLength");
p2.setAttribute("min","1");
p2.value = ambaPlaceProperties.ePusherLength;
};
if(p2h) {
p2h.innerText = "Duration";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
pixel.pushLength ??= (ambaPlaceProperties?.ePusherLength ?? 5);
pixel.pushTime ??= 0;
if(isNaN(pixel.pushTime) || pixel.pushTime < 0) { pixel.pushTime = 0 };
if(pixel.charge) {
pixel.pushTime = pixel.pushLength;
};
if(pixel.pushTime > 0) {
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x-1-i,pixel.y,true)) {
tryMove(pixelMap[pixel.x-1-i][pixel.y],pixel.x-2-i,pixel.y);
};
};
};
pixel.pushTime--;
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
elements.right_e_pusher = {
color: "#9f9f6f",
properties: {
pushTime: 0,
},
onSelect: function() {
showPropertySetter();
showSetterColumn("numeric",0);
var p0 = document.getElementById("propertynumeric0input");
var p0h = document.getElementById("propertynumeric0heading");
if(p0) {
p0.setAttribute("set","pusherRange");
p0.setAttribute("min","1");
p0.value = ambaPlaceProperties.pusherRange;
};
if(p0h) {
p0h.innerText = "Range";
};
showSetterColumn("numeric",1);
var p1 = document.getElementById("propertynumeric1input");
var p1h = document.getElementById("propertynumeric1heading");
if(p1) {
p1.setAttribute("set","pusherStrength");
p1.setAttribute("min","1");
p1.value = ambaPlaceProperties.pusherStrength;
};
if(p1h) {
p1h.innerText = "Strength";
};
showSetterColumn("numeric",2);
var p2 = document.getElementById("propertynumeric2input");
var p2h = document.getElementById("propertynumeric2heading");
if(p2) {
p2.setAttribute("set","ePusherLength");
p2.setAttribute("min","1");
p2.value = ambaPlaceProperties.ePusherLength;
};
if(p2h) {
p2h.innerText = "Duration";
};
},
onUnselect: function() {
hideAllSetterColumns();
hidePropertySetter()
},
tick: function(pixel) {
pixel.range ??= (ambaPlaceProperties?.pusherRange ?? 10);
pixel.pushStrength ??= (ambaPlaceProperties?.pusherStrength ?? 1);
pixel.pushLength ??= (ambaPlaceProperties?.ePusherLength ?? 5);
pixel.pushTime ??= 0;
if(isNaN(pixel.pushTime) || pixel.pushTime < 0) { pixel.pushTime = 0 };
if(pixel.charge) {
pixel.pushTime = pixel.pushLength;
};
if(pixel.pushTime > 0) {
for(h = 0; h < pixel.pushStrength; h++) {
for(i=(pixel.range - 1); i>=0; i--) {
if (!isEmpty(pixel.x+1+i,pixel.y,true)) {
tryMove(pixelMap[pixel.x+1+i][pixel.y],pixel.x+2+i,pixel.y);
};
};
};
pixel.pushTime--;
};
doDefaults(pixel);
},
category: "machines",
breakInto: ["metal_scrap", "steel", "iron", "glass", "uranium", "tin"],
tempHigh: 2400,
stateHigh: ["molten_aluminum", "molten_steel", "molten_iron", "molten_glass", "molten_uranium", "molten_tin"],
density: 10000,
hardness: 0.85,
conduct: 1,
state: "solid",
movable: false
}
//PORTALS have been added to vanilla Sandboxels. Congratulations to our graduate. ##
//MOBS ##
//Prerequisite Functions and Variables
minimumCreeperTries = 3;
maximumCreeperTries = 3;
minimumZombieTries = 3;
maximumZombieTries = 3;
minimumSkeletonTries = 3;
maximumSkeletonTries = 3;
eLists.CREEPER = ["creeper", "angelic_creeper", "hell_creeper", "bombing_creeper", "baby_creeper"];
headBodyObject = {
"head": "body",
"creeper_head": "creeper_body",
"angelic_creeper_head": "angelic_creeper_body",
"hell_creeper_head": "hell_creeper_body",
"bombing_creeper_head": "bombing_creeper_body",
"zombie_head": "zombie_body",
"skeleton_head": "skeleton_body",
"nothing_there_phase_3_head": "nothing_there_phase_3_body",
};
var style = document.createElement('style'); //Initialize CSS for creeper spawning's status indicator
style.type = 'text/css';
style.id = 'creeperStatusStylesheet';
//initial style conditional branch
if(typeof(settings.creeperSpawning) === "undefined") { //undefined (falsy but it needs special handling)
style.innerHTML = '.creeperStatus { color: #E11; text-decoration: none; }';
} else {
if(!settings.creeperSpawning) { //falsy: red
style.innerHTML = '.creeperStatus { color: #E11; text-decoration: none; }';
} else if(settings.creeperSpawning) { //truthy: green
style.innerHTML = '.creeperStatus { color: #1E1; text-decoration: none; }';
};
};
document.getElementsByTagName('head')[0].appendChild(style);
function coordPyth(xA,yA,xB,yB) { //Distance function, used for explosion trigger
var a = Math.abs(xB - xA);
var b = Math.abs(yB - yA);
var c = Math.sqrt(a**2 + b**2);
return c;
};
function pythSpeed(number1,number2) {
return Math.sqrt(number1**2 + number2**2);
};
function rgbColorBound(number) { //RGB bounding function, used for safety checking color changes
return Math.min(255,Math.max(0,number));
};
function slBound(number) { //SL bounding function (not hue), same use as above
return Math.min(100,Math.max(0,number));
};
function angelicUpwardVelocity(pixel,x,y,radius,fire,smoke,power) { //Angelic Creeper's effect, "compatible" with velocity.js by including the modified version of its code in itself
var info = elements[pixel.element]
//console.log("yeet");
// set the pixel.vx and pixel.vy depending on the angle and power
if (!elements[pixel.element].excludeRandom) {
//console.log("LOOKS LIKE IT'S YEETING TIME!");
var angle = Math.atan2(pixel.y-y,pixel.x-x);
//console.log(`angle calculated (${angle})`);
pixel.vx = Math.round((pixel.vx|0) + Math.cos(angle) * (radius * power/10));
//console.log(`vx calculated (${pixel.vx}) for pixel (${pixel.x},${pixel.y})`);
pixel.vy = 0 - Math.abs(Math.round((pixel.vy|0) + Math.sin(angle) * (radius * power/4)) + 4); //massively increased Y velocities even for objects below
//pixel.color = "rgb(255,0,0)";
//console.log(`vy calculated (${pixel.vy}) for pixel (${pixel.x},${pixel.y})`);
};
//console.log(`Velocities set`);
//console.log(`end`);
};
//afterFunction(pixel,x,y,radius,fire,smoke,power,damage);
function hellExplosionFire(pixel,x,y,radius,fire,smoke,power,damage) { //Angelic Creeper's effect, "compatible" with velocity.js by including the modified version of its code in itself
var coords = circleCoords(pixel.x,pixel.y,radius);
for (var i = 0; i < coords.length; i++) {
var x = coords[i].x;
var y = coords[i].y;
if(!isEmpty(x,y,true)) {
var pixel = pixelMap[x][y];
var info = elements[pixel.element]
if (info.burn) { //Light everything on fire
pixel.burning = true;
pixel.burnStart = pixelTicks;
pixel.temp += 10; //smoke prevention
} else if(Math.random() < 0.05) { //5%/px cursed burning
pixel.burning = true;
pixel.burnStart = pixelTicks;
pixel.temp += 10;
};
} else if(isEmpty(x,y)) { //if there's space for fire
if (Array.isArray(fire)) { //this should remain "fire"
var newfire = fire[Math.floor(Math.random() * fire.length)];
} else {
var newfire = fire;
};
createPixel(newfire,x,y); //add fire
var firePixel = pixelMap[x][y];
firePixel.temp = Math.max(elements[newfire].temp,firePixel.temp);
firePixel.burning = true;
};
};
};
//explodeAtPlus moved to separate file
if(typeof(settings.creeperSpawning) === "undefined") { //Default creeper setting
setSetting("creeperSpawning",false);
};
function updateCreeperPreferences() { //Creeper setting handler
if(settings.creeperSpawning) { //If the setting is on
if(typeof(randomEvents.creeper) !== "function") { //add the event if it's missing
randomEvents.creeper = function() {
var amount = Math.floor((Math.random() * maximumCreeperTries)+minimumCreeperTries); //1-3
//In worldgen worlds, you can expect about half of this because about half of the world is pixels in it.
for(i = 0; i < amount; i++) { //dummy for to break
if(settings.creeperSpawning) { //setting validation
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable creepers
var element = spawnCreepers[Math.floor(Math.random()*spawnCreepers.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents.creeper; //self-disable
//substitute event
var event = randomEvents[Object.keys(randomEvents)[Math.floor(Math.random()*Object.keys(randomEvents).length)]];
event();
break;
};
};
};
};
} else if(!settings.creeperSpawning) { //and if it's off
if(randomEvents.creeper) { delete randomEvents.creeper }; //delete it if it exists.
};
};
function toggleCreeperSpawning() { //Creeper toggle handler
if(settings.creeperSpawning != true) { //If it's false
setSetting("creeperSpawning",true); //make it true and update the status display CSS
updateCreeperPreferences(); //apply
document.getElementById("creeperStatusStylesheet").innerHTML = '.creeperStatus { color: #1E1; text-decoration: underline; }'; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element, like with find.js (RIP).
} else { //and the inverse if it's true
setSetting("creeperSpawning",false);
updateCreeperPreferences();
document.getElementById("creeperStatusStylesheet").innerHTML = '.creeperStatus { color: #E11; text-decoration: none; }';
};
};
//Functions used by Nothing There
function hasPixel(x,y,elementInput) {
if(isEmpty(x,y,true)) { //if empty, it can't have a pixel
return false;
} else {
if(elementInput.includes(",")) { //CSTA
elementInput = elementInput.split(",");
};
if(Array.isArray(elementInput)) { //if element list
return elementInput.includes(pixelMap[x][y].element);
} else { //if single element
return pixelMap[x][y].element === elementInput;
};
};
};
function arrowAltTb(pixel,breakChanceMultiplier,changetemp=false,defaultBreakIntoDust=false) {
var info = elements[pixel.element];
var hardness = defaultHardness;
if(typeof(info.hardness) === "number") {
hardness = info.hardness;
};
hardness = 1 - hardness; //invert hardness, so a hardness of 0 becomes a 100% chance and a hardness of 1 becomes a 0% chance
hardness *= breakChanceMultiplier;
if(Math.random() < hardness) {
return breakPixel(pixel,changetemp=false,defaultBreakIntoDust=false);
} else {
return false;
};
};
function nothingThereBulletMovement(pixel,x,y) {
if(!tryMove(pixel,x,y)) {
if(!isEmpty(x,y,true)) {
var thisDensity = elements[pixel.element].density;
var newPixel = pixelMap[x][y];
var newElement = newPixel.element;
var newInfo = elements[newElement];
var newHardness = 0;
if(nothingThereBulletExcludedElements.includes(newElement)) {
return false;
};
if(typeof(newInfo.hardness) === "number") {
newHardness = newInfo.hardness;
//it's inverted later
};
if(typeof(newInfo.state) === "undefined" && newElement !== pixel.element) { //Copy-paste of "break" code
if(Math.random() < ((1 - newHardness) ** 0.6)) {
swapPixels(pixel,newPixel);
//console.log(`nothingThereBulletMovement: Breaking pixel (${newPixel.element}, ${newPixel.x}, ${newPixel.y}))`)
breakPixel(newPixel,false,0.3);
return true;
} else {
deletePixel(pixel.x,pixel.y);
return false;
};
} else {
if(newElement == pixel.element) {
swapPixels(pixel,newPixel);
return true;
} else if(newInfo.state == "gas") {
swapPixels(pixel,newPixel);
return true;
} else if(newInfo.state == "liquid") {
var newDensity = 1000;
if(typeof(newInfo.density) === "number") {
newDensity = newInfo.density;
//console.log(`density ${newInfo.density} for ${newElement}`);
//} else {
//console.log(`undef density for ${newElement}, 1000 default`);
};
//console.log(`thisDensity: ${thisDensity}`);
//console.log(`newDensity: ${newDensity}`);
var chance = thisDensity/(thisDensity+newDensity);
//console.log(`${newElement}, ${chance}`)
if(Math.random() < chance) {
swapPixels(pixel,newPixel);
};
return true;
} else if(newInfo.state == "solid") {
if(Math.random() < ((1 - newHardness) ** 0.6)) {
swapPixels(pixel,newPixel);
//console.log(`nothingThereBulletMovement: Breaking pixel (${newPixel.element}, ${newPixel.x}, ${newPixel.y}))`)
breakPixel(newPixel,false,0.3);
return true;
} else {
deletePixel(pixel.x,pixel.y);
return false;
};
};
};
} else {
return false;
};
} else {
return true;
};
};
//End NT functions
nothingThereBulletExcludedElements = ["wall","nothing_there_phase_1","nothing_there_phase_2","nothing_there_phase_3_body","nothing_there_phase_3_head", "nothing_there_cleaver", "nothing_there_mace"];
enemyHumanoidArray = ["head","body"] //just in case
spawnCreepers = ["creeper","baby_creeper","angelic_creeper","bombing_creeper","hell_creeper"];
if(settings.creeperSpawning) { //creeper spawning option
randomEvents.creeper = function() {
var amount = Math.floor((Math.random() * maximumCreeperTries)+minimumCreeperTries); //1-3
for(i = 0; i < amount; i++) { //dummy for to break
if(settings.creeperSpawning) { //setting validation
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable creepers
var element = spawnCreepers[Math.floor(Math.random()*spawnCreepers.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents.creeper; //self-disable
//substitute event
var event = randomEvents[Object.keys(randomEvents)[Math.floor(Math.random()*Object.keys(randomEvents).length)]];
event();
break;
};
};
};
};
standaloneSpawnCreeper = function(amount=1) {
/* The amount is the maximum amount of *attempts*. Often, less creepers will spawn due to things in the way.
In a generated world, which uses half of the space, you can expect about half of this number to spawn. */
for(i = 0; i < amount; i++) { //dummy for to break
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable creepers
var element = spawnCreepers[Math.floor(Math.random()*spawnCreepers.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
};
};
//Prerequisite Functions and Variables
function headHasBody(pixel) {
var pX = pixel.x;
var pY = pixel.y;
//console.log("Checking head for body");
if(Object.keys(headBodyObject).includes(pixel.element)) {
//console.log("The head has a corresponding body element.");
if(typeof(pixelMap[pX][pY+1]) === "undefined") {
//console.log("The body's place is empty.");
return false;
} else {
var bodyPixel = pixelMap[pX][pY+1];
//console.log("The body's place is not empty.");
return (bodyPixel.element === headBodyObject[pixel.element]);
};
} else {
//console.log("The head does not have corresponding body element.");
return null;
};
};
function bodyHasHead(pixel) {
var pX = pixel.x;
var pY = pixel.y;
//console.log("Checking body for head");
if(Object.values(headBodyObject).includes(pixel.element)) {
//console.log("The body has a corresponding head element.");
if(typeof(pixelMap[pX][pY-1]) === "undefined") {
//console.log("The head's place is empty.");
return false;
} else {
var headPixel = pixelMap[pX][pY-1];
//console.log("The head's place is not empty.");
return (headPixel.element === getKeyByValue(headBodyObject,pixel.element));
};
} else {
//console.log("The body does not have corresponding head element.");
return null;
};
};
function zombifyHuman(pixel) {
var pX = pixel.x;
var pY = pixel.y;
if(!["head","body"].includes(pixel.element)) {
//console.log("Not part of a human");
return false;
} else {
if(pixel.element === "head") {
//console.log("Head");
if(headHasBody(pixel)) {
//console.log("There's also a body");
var body = pixelMap[pX][pY+1];
changePixel(body,"zombie_body",false);
//console.log("Body turned (head path)");
};
changePixel(pixel,"zombie_head");
//console.log("Head turned (head path)");
} else {
//console.log("Not head (i.e. body)");
if(bodyHasHead(pixel)) {
//console.log("There's also a head");
var head = pixelMap[pX][pY-1];
changePixel(head,"zombie_head",false);
//console.log("Head turned (body path)");
};
changePixel(pixel,"zombie_body");
//console.log("Body turned (body path)");
};
};
};
function dezombifyHuman(pixel) {
var pX = pixel.x;
var pY = pixel.y;
if(!["zombie_head","zombie_body"].includes(pixel.element)) {
return false;
} else {
if(pixel.element === "zombie_head") {
if(headHasBody(pixel)) {
var body = pixelMap[pX][pY+1];
changePixel(body,"body",false);
};
changePixel(pixel,"head");
} else {
if(bodyHasHead(pixel)) {
var head = pixelMap[pX][pY-1];
changePixel(head,"head",false);
};
changePixel(pixel,"body");
};
};
};
elements.spawner = {
color: "#1c3038",
breakInto: ["steel","steel","smoke","magic",null,null,null,null,null],
properties: {
spawnCounter: 0,
spawnTime: 160,
spawn: null,
squadiusX: 4,
squadiusY: 4,
spawnTries: 4,
//spawnRangeMax: null, //Disabled by default for performance and because I can't think of how to make it count MPL elements towards the limit
},
tick: function(pixel) {
//validation
if(Array.isArray(pixel.spawn)) {
pixel.spawn = pixel.spawn.filter(function(e){ return elementExists(e) });
if(pixel.spawn.length == 0) {
pixel.spawn = null;
};
} else {
if(!elementExists(pixel.spawn)) {
pixel.spawn = null;
};
};
if(pixel.spawn === null) {
return false;
};
if(pixel.spawnCounter <= 0) {
//var pixelsOfSpawnElement = 0;
var newSpawn = pixel.spawn;
if(Array.isArray(newSpawn)) {
newSpawn = newSpawn[Math.floor(Math.random() * newSpawn.length)];
};
var xForMin = -1 * pixel.squadiusX;
var xForMax = pixel.squadiusX + 1;
var yForMin = -1 * pixel.squadiusY;
var yForMax = pixel.squadiusY + 1;
/*if(pixel.spawnRangeMax !== null) {
for(xOffset = xForMin; xOffset < xForMax; xOffset++) {
for(yOffset = yForMin; yOffset < yForMax; yOffset++) {
var newX = pixel.x + xOffset;
var newY = pixel.y + yOffset;
if(isEmpty(newX,newY,true) || outOfBounds(newX,newY)) {
continue;
};
newPixel = pixelMap[newX][newY];
if(newPixel.element == pixel.spawn || pixel.spawn.includes(newPixel.element)) {
pixelsOfSpawnElement++;
};
};
};
if(pixelsOfSpawnElement > pixel.spawnRangeMax) {
return false;
};
};*/
for(s = 0; s < pixel.spawnTries; s++) {
var randomX = pixel.x + randomIntegerBetweenTwoValues(0 - pixel.squadiusX, pixel.squadiusX);
var randomY = pixel.y + randomIntegerBetweenTwoValues(0 - pixel.squadiusY, pixel.squadiusY);
if(isEmpty(randomX,randomY,false)) {
createPixel(newSpawn,randomX,randomY);
};
};
pixel.spawnCounter = pixel.spawnTime;
} else {
pixel.spawnCounter--;
};
},
hardness: 0.7,
state: "solid",
}
elements.frozen_rotten_meat = {
color: ["#8FB588", "#8FA888"],
behavior: [
"XX|CR:plague,stench,stench%0.125 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85|XX",
"SP%99 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85|XX|SP%99 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85",
"XX|M1 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85|XX",
],
temp: -18,
tempHigh: 0,
stateHigh: "rotten_meat",
category:"food",
hidden:true,
state: "solid",
density: 1037.5,
};
elements.rotten_meat.tempLow = -18;
elements.rotten_meat.stateLow = "frozen_rotten_meat";
elements.zombie_blood = {
color: ["#d18228", "#9a9e2f"],
behavior: behaviors.LIQUID,
reactions: {
"vaccine": { "elem2":null, "chance": 0.01 },
"plague": { "elem2":null, "chance": 0.01 },
"virus": { "elem2":null, "chance": 0.01 },
"cancer": { "elem1":"cancer", "chance": 0.02 },
/*"rat": { "elem2":"infection", "chance":0.075 },
"flea": { "elem1":"infection", "chance":0.03 },
"dirt": { "elem1":null, "elem2":"mud" },
"sand": { "elem1":null, "elem2":"wet_sand" },
"mercury": { "elem1":"infection", "elem2":null, "chance":0.05 },
"carbon_dioxide": { "elem2":null, "chance":0.05 },
"alcohol": { "elem1":[null,"dna"], "chance":0.02 },*/
"oxygen": { "elem2":null, "chance":0.04 },
"blood": { "elem2":"zombie_blood", "chance":0.1 }
},
viscosity: 30,
tempHigh: 127.55,
stateHigh: ["steam","salt","oxygen","plague"],
tempLow: 0,
category:"liquids",
state: "liquid",
density: 1160,
stain: 0.06,
tick: function(pixel) {
if(Math.random() < 0.2) {
var pX = pixel.x;
var pY = pixel.y;
for(i = 0; i < adjacentCoords.length; i++) {
var coord = adjacentCoords[i];
var oX = coord[0];
var oY = coord[1];
var nX = pX+oX;
var nY = pY+oY;
if(isEmpty(nX,nY,true)) {
continue;
} else {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
if(Math.random() < 0.1) { zombifyHuman(newPixel) };
};
};
};
};
},
};
var style = document.createElement('style'); //Initialize CSS for zombie spawning's status indicator
style.type = 'text/css';
style.id = 'zombieStatusStylesheet';
//initial style conditional branch
if(typeof(settings.zombieSpawning) === "undefined") { //undefined (falsy but it needs special handling)
style.innerHTML = '.zombieStatus { color: #E11; text-decoration: none; }';
} else {
if(!settings.zombieSpawning) { //falsy: red
style.innerHTML = '.zombieStatus { color: #E11; text-decoration: none; }';
} else if(settings.zombieSpawning) { //truthy: green
style.innerHTML = '.zombieStatus { color: #1E1; text-decoration: none; }';
};
};
document.getElementsByTagName('head')[0].appendChild(style);
if(typeof(settings.zombieSpawning) === "undefined") { //Default zombie setting
setSetting("zombieSpawning",false);
};
function updateZombiePreferences() { //Zombie setting handler
if(settings.zombieSpawning) { //If the setting is on
if(typeof(randomEvents.zombie) !== "function") { //add the event if it's missing
randomEvents.zombie = function() {
var amount = Math.floor((Math.random() * maximumZombieTries)+minimumZombieTries); //1-3
//In worldgen worlds, you can expect about half of this because about half of the world is pixels in it.
for(i = 0; i < amount; i++) { //dummy for to break
if(settings.zombieSpawning) { //setting validation
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable zombies
var element = spawnZombies[Math.floor(Math.random()*spawnZombies.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents.zombie; //self-disable
//substitute event
var event = randomEvents[Object.keys(randomEvents)[Math.floor(Math.random()*Object.keys(randomEvents).length)]];
event();
break;
};
};
};
};
} else if(!settings.zombieSpawning) { //and if it's off
if(randomEvents.zombie) { delete randomEvents.zombie }; //delete it if it exists.
};
};
function toggleZombieSpawning() { //Zombie toggle handler
if(settings.zombieSpawning != true) { //If it's false
setSetting("zombieSpawning",true); //make it true and update the status display CSS
updateZombiePreferences(); //apply
document.getElementById("zombieStatusStylesheet").innerHTML = '.zombieStatus { color: #1E1; text-decoration: underline; }'; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element, like with find.js (RIP).
} else { //and the inverse if it's true
setSetting("zombieSpawning",false);
updateZombiePreferences();
document.getElementById("zombieStatusStylesheet").innerHTML = '.zombieStatus { color: #E11; text-decoration: none; }';
};
};
spawnZombies = ["zombie","baby_zombie"];
if(settings.zombieSpawning) { //zombie spawning option
randomEvents.zombie = function() {
var amount = Math.floor((Math.random() * maximumZombieTries)+minimumZombieTries); //1-3
for(i = 0; i < amount; i++) { //dummy for to break
if(settings.zombieSpawning) { //setting validation
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable zombies
var element = spawnZombies[Math.floor(Math.random()*spawnZombies.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents.zombie; //self-disable
//substitute event
var event = randomEvents[Object.keys(randomEvents)[Math.floor(Math.random()*Object.keys(randomEvents).length)]];
event();
break;
};
};
};
};
standaloneSpawnZombie = function(amount=1) {
/* The amount is the maximum amount of *attempts*. Often, less zombies will spawn due to things in the way.
In a generated world, which uses half of the space, you can expect about half of this number to spawn. */
for(i = 0; i < amount; i++) { //dummy for to break
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable zombies
var element = spawnZombies[Math.floor(Math.random()*spawnZombies.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
};
};
var style = document.createElement('style'); //Initialize CSS for skeleton spawning's status indicator
style.type = 'text/css';
style.id = 'skeletonStatusStylesheet';
//initial style conditional branch
if(typeof(settings.skeletonSpawning) === "undefined") { //undefined (falsy but it needs special handling)
style.innerHTML = '.skeletonStatus { color: #E11; text-decoration: none; }';
} else {
if(!settings.skeletonSpawning) { //falsy: red
style.innerHTML = '.skeletonStatus { color: #E11; text-decoration: none; }';
} else if(settings.skeletonSpawning) { //truthy: green
style.innerHTML = '.skeletonStatus { color: #1E1; text-decoration: none; }';
};
};
document.getElementsByTagName('head')[0].appendChild(style);
if(typeof(settings.skeletonSpawning) === "undefined") { //Default skeleton setting
setSetting("skeletonSpawning",false);
};
function updateSkeletonPreferences() { //Skeleton setting handler
if(settings.skeletonSpawning) { //If the setting is on
if(typeof(randomEvents.skeleton) !== "function") { //add the event if it's missing
randomEvents.skeleton = function() {
var amount = Math.floor((Math.random() * maximumSkeletonTries)+minimumSkeletonTries); //1-3
//In worldgen worlds, you can expect about half of this because about half of the world is pixels in it.
for(i = 0; i < amount; i++) { //dummy for to break
if(settings.skeletonSpawning) { //setting validation
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable skeletons
var element = spawnSkeletons[Math.floor(Math.random()*spawnSkeletons.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents.skeleton; //self-disable
//substitute event
var event = randomEvents[Object.keys(randomEvents)[Math.floor(Math.random()*Object.keys(randomEvents).length)]];
event();
break;
};
};
};
};
} else if(!settings.skeletonSpawning) { //and if it's off
if(randomEvents.skeleton) { delete randomEvents.skeleton }; //delete it if it exists.
};
};
function toggleSkeletonSpawning() { //Skeleton toggle handler
if(settings.skeletonSpawning != true) { //If it's false
setSetting("skeletonSpawning",true); //make it true and update the status display CSS
updateSkeletonPreferences(); //apply
document.getElementById("skeletonStatusStylesheet").innerHTML = '.skeletonStatus { color: #1E1; text-decoration: underline; }'; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element, like with find.js (RIP).
} else { //and the inverse if it's true
setSetting("skeletonSpawning",false);
updateSkeletonPreferences();
document.getElementById("skeletonStatusStylesheet").innerHTML = '.skeletonStatus { color: #E11; text-decoration: none; }';
};
};
spawnSkeletons = ["skeleton"];
if(settings.skeletonSpawning) { //skeleton spawning option
randomEvents.skeleton = function() {
var amount = Math.floor((Math.random() * maximumSkeletonTries)+minimumSkeletonTries); //1-3
for(i = 0; i < amount; i++) { //dummy for to break
if(settings.skeletonSpawning) { //setting validation
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable skeletons
var element = spawnSkeletons[Math.floor(Math.random()*spawnSkeletons.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents.skeleton; //self-disable
//substitute event
var event = randomEvents[Object.keys(randomEvents)[Math.floor(Math.random()*Object.keys(randomEvents).length)]];
event();
break;
};
};
};
};
standaloneSpawnSkeleton = function(amount=1) {
/* The amount is the maximum amount of *attempts*. Often, less skeletons will spawn due to things in the way.
In a generated world, which uses half of the space, you can expect about half of this number to spawn. */
for(i = 0; i < amount; i++) { //dummy for to break
// random x between 1 and width-1
var x = Math.floor(Math.random()*(width-1))+1;
// random y between 1 and height
var y = Math.floor(Math.random()*height-1)+1;
if (isEmpty(x,y)) {
// random element from the list of spawnable skeletons
var element = spawnSkeletons[Math.floor(Math.random()*spawnSkeletons.length)];
// if element is an array, choose a random element from the array
if (Array.isArray(element)) {
element = element[Math.floor(Math.random()*element.length)];
}
createPixel(element,x,y);
};
};
};
/*Start Main Zombie
..................
........%%%%......
.......%%%%%%.....
......%%%%%OOOOO..
....%%%%%%OOOOOOO.
...%%%%%%%%OOOOO..
...%%%%%%%%%%%....
...%%%%%%%%%%%....
...%%%%%%%%%%%....
....%%%%%%%%%%....
......%%%%%%%%....
.......%%...%%....
.......%%...%%....
..................
*/
elements.zombie = {
color: ["#567C44","#199A9A","#41369B"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("zombie_body", pixel.x, pixel.y+1);
pixel.element = "zombie_head";
pixel.color = pixelColorPick(pixel)
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("zombie_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "zombie_body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["zombie_body","zombie_head"],
desc: "I'd rather this be toggleable mid-game than require a reload.
If this text is green or underlined, zombies (all types) can spawn.Click here to toggle zombie spawning. If it's on, zombies can spawn through random events."
};
elements.zombie_body = {
color: "#27719D",
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "rotten_meat",
tempLow: -30,
stateLow: "frozen_rotten_meat",
burn: 10,
burnTime: 250,
burnInto: "rotten_meat",
breakInto: ["zombie_blood","rotten_meat"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","rotten_meat","rotten_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.025 }
},
properties: {
dead: false,
dir: 1,
panic: 0
},
movable: true,
tick: function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "zombie_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 100
if (pixelTicks-pixel.dead > 100) {
changePixel(pixel,"rotten_meat");
};
return;
};
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true)) {
if(pixelMap[pixel.x][pixel.y-1].element == "head") {
changePixel(pixelMap[pixel.x][pixel.y-1],"zombie_head");
} else if(pixelMap[pixel.x][pixel.y-1].element == "zombie_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
};
} else {
var head = null;
};
} else { var head = null };
if (isEmpty(pixel.x, pixel.y-1)) {
// create zombie blood if decapitated 10% chance
if (Math.random() < 0.1) {
createPixel("zombie_blood", pixel.x, pixel.y-1);
// set dead to true 10% chance
if (Math.random() < 0.10) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return }
else if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
},
};
elements.zombie_head = {
color: "#567C44",
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "rotten_meat",
tempLow: -30,
stateLow: "frozen_rotten_meat",
burn: 10,
burnTime: 250,
burnInto: "rotten_meat",
breakInto: ["zombie_blood","rotten_meat"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","rotten_meat","rotten_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.025 }
},
properties: {
dead: false,
following: false,
dir: 1,
panic: 0
},
movable: true,
tick: function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 100
if (pixelTicks-pixel.dead > 100) {
changePixel(pixel,"rotten_meat");
};
return;
};
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true)) {
if(pixelMap[pixel.x][pixel.y+1].element == "body") {
changePixel(pixelMap[pixel.x][pixel.y+1],"zombie_body");
} else if(pixelMap[pixel.x][pixel.y+1].element == "zombie_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill body
pixel.dead = body.dead;
};
} else {
var body = null;
};
} else { var body = null };
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create zombie blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("zombie_blood", pixel.x, pixel.y+1);
// set dead to true 10% chance
if (Math.random() < 0.10) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
if(pixelTicks % 2 == 0) { //reduce rate for performance
/*var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};*/
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-35 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/3) { //One-third chance to mutilate (changePixel)
if(Math.random() < 1/3) { //One-third chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
} else { //Remaining 2/3 chance to turn the human
zombifyHuman(newPixel);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/3) { //One-third chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 35 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/3) { //One-third chance to mutilate (changePixel)
if(Math.random() < 1/3) { //One-third chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
} else { //Remaining 2/3 chance to turn the human
zombifyHuman(newPixel);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/3) { //One-third chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
//Baby Zombie
elements.baby_zombie = {
color: "#199A9A",
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "rotten_meat",
tempLow: -30,
stateLow: "frozen_rotten_meat",
burn: 10,
burnTime: 250,
burnInto: "rotten_meat",
breakInto: ["zombie_blood","rotten_meat"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","rotten_meat","rotten_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.025 }
},
properties: {
dead: false,
dir: 1,
panic: 0
},
movable: true,
tick: function(pixel) {
tryMove(pixel, pixel.x, pixel.y+1); // Fall
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 100
if (pixelTicks-pixel.dead > 100) {
changePixel(pixel,"rotten_meat");
};
return;
};
if (Math.random() < 0.15) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0], //dash move
[1*pixel.dir,-1], //slash move
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if(tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!pixel.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
var pX = pixel.x;
var pY = pixel.y;
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
if(pixelTicks % 2 == 0) { //reduce rate for performance
/*var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};*/
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-35 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/3) { //One-third chance to mutilate (changePixel)
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
} else { //Remaining 2/3 chance to turn the human
zombifyHuman(newPixel);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 35 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/3) { //One-third chance to mutilate (changePixel)
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
} else { //Remaining 2/3 chance to turn the human
zombifyHuman(newPixel);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"zombie_blood",false); //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel(newPixel,"rotten_meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
related: ["zombie"],
desc: "Baby zombies: smaller, faster, and more annoying.",
};
/*Start Main Creeper
%%%%%%%%%%%%%%%%%%
%%%%%%%% %%%%%%
%%%%%%% %%%%%
%%%%%% OOOOO%%
%%%% OOOOOOO%
%%% OOOOO%%
%%% %%%%
%%% %%%%
%%% %%%%
%%%% %%%%
%%%%%% %%%%
%%%%%%% %%% %%%%
%%%%%%% %%% %%%%
%%%%%%%%%%%%%%%%%%
*/
elements.creeper = {
color: ["#D2D2D2", "#BFDFB9", "#94CE89", "#78D965", "#5ED54C", "#58C546", "#50B143", "#479143", "#559552", "#3F8738", "#5B8B59"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("creeper_body", pixel.x, pixel.y+1);
pixel.element = "creeper_head";
pixel.color = pixelColorPick(pixel)
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("creeper_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "creeper_body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["creeper_body","creeper_head"],
desc: "I'd rather this be toggleable mid-game than require a reload.
If this text is green or underlined, creepers can spawn.Click here to toggle creeper spawning. If it's on, creepers (all types) can spawn through random events. To enable automatic creeper generation, set the generateCreepers query parameter."
};
elements.creeper_body = {
color: ["#D2D2D2", "#BFDFB9", "#94CE89", "#78D965", "#5ED54C", "#58C546", "#50B143", "#479143", "#559552", "#3F8738", "#5B8B59"],
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
breakInto: ["blood","gunpowder"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "creeper_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
}
return
}
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "creeper_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
}
}
else { var head = null }
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 10% chance
if (Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return }
else if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
if(pixel.charge) {
pixel.charged = true;
};
if(head) {
if(typeof(head.charge) !== "undefined") {
if(head.charge) {
pixel.charged = true;
};
};
if(typeof(head.charged) !== "undefined") {
if(head.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 7;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 5;
};
if(pixel.burning) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
if(!pixel.burnStart) { //I don't like errors.
pixel.burnStart = pixel.ticks;
};
if(pixelTicks - pixel.burnStart > 30) {
//console.log("Kaboom?");
explodeAt(pixel.x,pixel.y,explosionRadius);
//console.log("Yes, Rico, kaboom.");
};
};
//Head hissing color handler: keeps track of head's hissing for coloring purposes
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.dead || !head || head.dead) { //can't hiss without a head according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(head.hissing) {
//console.log("Ssssssss");
if(!head.hissStart) {
//console.log("t-30 ticks or whatever it was");
head.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - head.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
//console.log("the j");
lightness = slBound(lightness + 1.176);
//console.log(lightness);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
};
};
},
};
elements.creeper_head = {
color: ["#5B8B59", "#3F8738", "#559552", "#479143", "#50B143", "#58C546"],
category: "life",
hidden: true,
density: 1080,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
breakInto: "blood",
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.5 }
},
properties: {
dead: false,
following: false,
hissing: false,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
return
}
}
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "creeper_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill head
pixel.dead = body.dead;
}
}
else { var body = null }
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
if(pixel.charge) {
pixel.charged = true;
};
if(body) {
if(typeof(body.charge) !== "undefined") {
if(body.charge) {
pixel.charged = true;
};
};
if(typeof(body.charged) !== "undefined") {
if(body.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) { //probably misapplying the tolerance from the MC Wiki line: "Creepers will chase after any player, as long as it is within a 16 block (±5%) radius"
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
break;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break;
};
};
};
};
};
//Pre-explosion handler: keeps track of time before the kaboom
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.hissing) {
//console.log("Ssssssss");
if(pixel.dead || !body || body.dead) { //can't explode without a body according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(!pixel.hissStart) {
//console.log("t-30 ticks or whatever it was");
pixel.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - pixel.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
lightness = slBound(lightness + 1.176);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
if(pixelTicks - pixel.hissStart > 30) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAt(body.x,body.y,explosionRadius);
//console.log("Yes, Rico, kaboom.");
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
/*End Main Creeper
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&X&X&&&&&&
&&&&&&&&&XXX&&&&&&
&&&&&&&&&&X&&&&&&&
&&&&&&&&&&X&&&&&&&
&&& & & & X & &&&&
&&& &&&&
&&&& &&&&
&&&&&& &&&&
&&&&&&& &&& &&&&
&&&&&&& &&& &&&&
&&&&&&&&&&&&&&&&&&
*/
//Baby Creeper
elements.baby_creeper = {
color: ["#D2D2D2", "#BFDFB9", "#94CE89", "#78D965", "#5ED54C", "#58C546", "#50B143", "#479143", "#559552", "#3F8738", "#5B8B59"],
category: "life",
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
breakInto: ["blood","gunpowder"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
tryMove(pixel, pixel.x, pixel.y+1); // Fall
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
}
return
}
if (Math.random() < 0.15) { // Move 15% chance (should be 12.5 but 15 looks better)
var movesToTry = [
[1*pixel.dir,0], //dash move
[1*pixel.dir,-1], //slash move
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if(tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!pixel.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charge) {
pixel.charged = true;
};
var pX = pixel.x;
var pY = pixel.y;
if(pixel.charged) {
var explosionRadius = 6;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 4; //should be half of the original creeper's radius
};
if(pixel.burning) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
if(!pixel.burnStart) { //I don't like errors.
pixel.burnStart = pixel.ticks;
};
if(pixelTicks - pixel.burnStart > 15) {
//console.log("Kaboom?");
explodeAt(pixel.x,pixel.y,explosionRadius);
//console.log("Yes, Rico, kaboom.");
};
};
//Pre-explosion handler: keeps track of time before the kaboom
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.hissing) {
//console.log("Ssssssss");
if(pixel.dead) {
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(!pixel.hissStart) {
//console.log("t-30 ticks or whatever it was");
pixel.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - pixel.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + (2 * ticksHissing));
green = rgbColorBound(green + (2 * ticksHissing));
blue = rgbColorBound(blue + (2 * ticksHissing));
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
lightness = slBound(lightness + (2 * 1.176));
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
if(pixelTicks - pixel.hissStart > 15) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAt(pixel.x,pixel.y,explosionRadius);
//console.log("Yes, Rico, kaboom.");
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) { //probably misapplying the tolerance from the MC Wiki line: "Creepers will chase after any player, as long as it is within a 16 block (±5%) radius"
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
break;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break;
};
};
};
};
};
},
related: ["creeper"],
};
//Angelic Creeper
elements.angelic_creeper = { //let's get this one out of the way first
color: ["#f5ef56", "#fcbddf", "#de8aa8", "#e35d95", "#eb4974", "#ed3ea7", "#d645a3", "#a84556", "#9e4f6c", "#91315b", "#8c4963"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("angelic_creeper_body", pixel.x, pixel.y+1);
pixel.element = "angelic_creeper_head";
pixel.color = pixelColorPick(pixel)
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("angelic_creeper_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "angelic_creeper_body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["angelic_creeper_body","angelic_creeper_head"],
desc: 'A creeper type from Extra Creeper Types(CF). It sends things upward.'
};
elements.angelic_creeper_body = {
color: ["#d2d2d2", "#fcbddf", "#de8aa8", "#e35d95", "#eb4974", "#ed3ea7", "#d645a3", "#a84556", "#9e4f6c", "#91315b", "#8c4963"],
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
breakInto: ["blood","blood","gunpowder","gunpowder","feather"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
if(!pixel.hissing) { //If not hissing (it floats when hissing)
if(Math.random() < 0.2) { //20% chance to fall
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "angelic_creeper_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
} else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
};
};
};
};
};
} else {
if((pixelTicks - pixel.start) % 3 == 0) {
if (!isEmpty(pixel.x, pixel.y-1, true)) { // Find head
var headPixel = pixelMap[pixel.x][pixel.y-1];
if (headPixel.element == "angelic_creeper_head") { //Validate head
if (tryMove(headPixel, pixel.x, pixel.y-2)) { // Float
if (isEmpty(pixel.x, pixel.y-1)) { //If the head didn't swap with something
movePixel(pixel, pixel.x, pixel.y-1); //Pull body up
} else { //If it did swap
swapPixels(pixel, pixelMap[pixel.x][pixel.y-1]); //Pull body up through other pixel
};
};
};
};
};
};
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
}
return
}
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "angelic_creeper_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
}
}
else { var head = null }
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 10% chance
if (Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return }
else if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
if(pixel.charge) {
pixel.charged = true;
};
if(head) {
if(typeof(head.charge) !== "undefined") {
if(head.charge) {
pixel.charged = true;
};
};
if(typeof(head.charged) !== "undefined") {
if(head.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
if(pixel.burning) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
if(!pixel.burnStart) { //I don't like errors.
pixel.burnStart = pixel.ticks;
};
if(pixelTicks - pixel.burnStart > 30) {
//console.log("GOTTA YEET YEET YEET!");
explodeAtPlus(pixel.x,pixel.y,explosionRadius,"fire","smoke",null,angelicUpwardVelocity); //Special effect: Flings you upwards (extended to all movable tiles because it's easier).
//It also floats when hissing, but that will come soon.
//console.log("Yes, Rico, kaboom.");
};
};
//Head hissing color handler: keeps track of head's hissing for coloring purposes
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.dead || !head || head.dead) { //can't hiss without a head according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(head.hissing) {
//console.log("Ssssssss");
if(!head.hissStart) {
//console.log("t-30 ticks or whatever it was");
head.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - head.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
//console.log("the j");
lightness = slBound(lightness + 1.176);
//console.log(lightness);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
};
};
},
},
elements.angelic_creeper_head = {
color: ["#f5ef56", "#f0ea4f", "#f0ea60"],
category: "life",
hidden: true,
density: 1080,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
breakInto: ["blood","blood","blood","blood","feather"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.5 }
},
properties: {
dead: false,
following: false,
hissing: false,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
return
}
}
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "angelic_creeper_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill head
pixel.dead = body.dead;
}
}
else { var body = null }
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
if(pixel.charge) {
pixel.charged = true;
};
if(body) {
if(typeof(body.charge) !== "undefined") {
if(body.charge) {
pixel.charged = true;
};
};
if(typeof(body.charged) !== "undefined") {
if(body.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) { //probably misapplying the tolerance from the MC Wiki line: "Creepers will chase after any player, as long as it is within a 16 block (±5%) radius"
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
break;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break;
};
};
};
};
};
//Pre-explosion handler: keeps track of time before the kaboom
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.hissing) {
//console.log("Ssssssss");
if(pixel.dead || !body || body.dead) { //can't explode without a body according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(!pixel.hissStart) {
//console.log("t-30 ticks or whatever it was");
pixel.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - pixel.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
lightness = slBound(lightness + 1.176);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
if(pixelTicks - pixel.hissStart > 30) {
//console.log("GOTTA YEET YEET YEET!");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAtPlus(body.x,body.y,explosionRadius,"fire","smoke",null,angelicUpwardVelocity);
//console.log("Yes, Rico, kaboom.");
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
//Bombing Creeper
elements.bombing_creeper = {
color: ["#5b8b59", "#3f8738", "#559552", "#479143", "#50b143", "#58c546", "#e83c3c", "#c92a2a", "#f53d3d", "#ad3131"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("bombing_creeper_body", pixel.x, pixel.y+1);
pixel.element = "bombing_creeper_head";
pixel.color = pixelColorPick(pixel)
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("bombing_creeper_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "bombing_creeper_body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["bombing_creeper_body","bombing_creeper_head"],
desc: 'A creeper type from Extra Creeper Types(CF). It spawns more explosives when it explodes.'
};
elements.bombing_creeper_body = {
color: ["#e83c3c", "#c92a2a", "#f53d3d", "#ad3131"],
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","dynamite","gunpowder"],
breakInto: ["blood","dynamite","dynamite"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "bombing_creeper_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
}
return
}
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "bombing_creeper_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
}
}
else { var head = null }
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 10% chance
if (Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return }
else if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
if(pixel.charge) {
pixel.charged = true;
};
if(head) {
if(typeof(head.charge) !== "undefined") {
if(head.charge) {
pixel.charged = true;
};
};
if(typeof(head.charged) !== "undefined") {
if(head.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
if(pixel.burning) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
if(!pixel.burnStart) { //I don't like errors.
pixel.burnStart = pixel.ticks;
};
if(pixelTicks - pixel.burnStart > 30) {
//console.log("Kaboom?");
explodeAt(pixel.x,pixel.y,explosionRadius,"fire,dynamite"); //Effect: Places (originally 5) primed TNT when it explodes (i.e. cluster bomb creeper)
//Dynamite is the closest thing we have to powder TNT (i.e. good enough)
//console.log("Yes, Rico, kaboom.");
};
};
//Head hissing color handler: keeps track of head's hissing for coloring purposes
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.dead || !head || head.dead) { //can't hiss without a head according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(head.hissing) {
//console.log("Ssssssss");
if(!head.hissStart) {
//console.log("t-30 ticks or whatever it was");
head.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - head.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
//console.log("the j");
lightness = slBound(lightness + 1.176);
//console.log(lightness);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
};
};
},
};
elements.bombing_creeper_head = {
color: ["#5B8B59", "#3F8738", "#559552", "#479143", "#50B143", "#58C546"],
category: "life",
hidden: true,
density: 1080,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "cooked_meat",
tempLow: -30,
stateLow: "frozen_meat",
burn: 10,
burnTime: 250,
burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","dynamite","gunpowder"],
breakInto: ["blood","dynamite"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.5 }
},
properties: {
dead: false,
following: false,
hissing: false,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
return
}
}
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "bombing_creeper_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill head
pixel.dead = body.dead;
}
}
else { var body = null }
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
if(pixel.charge) {
pixel.charged = true;
};
if(body) {
if(typeof(body.charge) !== "undefined") {
if(body.charge) {
pixel.charged = true;
};
};
if(typeof(body.charged) !== "undefined") {
if(body.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) { //probably misapplying the tolerance from the MC Wiki line: "Creepers will chase after any player, as long as it is within a 16 block (±5%) radius"
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
break;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break;
};
};
};
};
};
//Pre-explosion handler: keeps track of time before the kaboom
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.hissing) {
//console.log("Ssssssss");
if(pixel.dead || !body || body.dead) { //can't explode without a body according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(!pixel.hissStart) {
//console.log("t-30 ticks or whatever it was");
pixel.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - pixel.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
lightness = slBound(lightness + 1.176);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
if(pixelTicks - pixel.hissStart > 30) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAt(body.x,body.y,explosionRadius,"fire,dynamite");
//console.log("Yes, Rico, kaboom.");
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
//Hell Creeper
elements.hell_creeper = {
color: ["#D2D2D2", "#ff141e", "#fc3232", "#DFAFAF", "#e84a4a", "#ce7979", "#d95555", "#d53c3c", "#c53636", "#b13333", "#913535", "#954242", "#872828", "#8b4949", "#2b0304"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("hell_creeper_body", pixel.x, pixel.y+1);
pixel.element = "hell_creeper_head";
pixel.color = pixelColorPick(pixel)
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("hell_creeper_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "hell_creeper_body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["hell_creeper_body","hell_creeper_head"],
desc: 'A creeper type from Extra Creeper Types(CF). It has a small explosion radius, but spawns a lot of fire around its explosion.'
};
elements.hell_creeper_body = {
color: ["#D2D2D2", "#ff141e", "#fc3232", "#DFAFAF", "#e84a4a", "#ce7979", "#d95555", "#d53c3c", "#c53636", "#b13333", "#913535", "#954242", "#872828", "#8b4949", "#2b0304"],
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 2000, //they are immune to lava, and minecraft's lava is presumably mafic, so at least 1200*C
stateHigh: "ash",
breakInto: ["blood","gunpowder","fire"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "hell_creeper_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
}
return
}
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "hell_creeper_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
}
}
else { var head = null }
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 10% chance
if (Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return }
else if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
if(pixel.charge) {
pixel.charged = true;
};
if(head) {
if(typeof(head.charge) !== "undefined") {
if(head.charge) {
pixel.charged = true;
};
};
if(typeof(head.charged) !== "undefined") {
if(head.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
if(pixel.burning) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
if(!pixel.burnStart) { //I don't like errors.
pixel.burnStart = pixel.ticks;
};
if(pixelTicks - pixel.burnStart > 30) {
//console.log("Kaboom?");
explodeAtPlus(pixel.x,pixel.y,explosionRadius,"fire","fire",null,hellExplosionFire);
//console.log("Yes, Rico, kaboom.");
};
};
//Head hissing color handler: keeps track of head's hissing for coloring purposes
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.dead || !head || head.dead) { //can't hiss without a head according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(head.hissing) {
//console.log("Ssssssss");
if(!head.hissStart) {
//console.log("t-30 ticks or whatever it was");
head.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - head.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
//console.log("the j");
lightness = slBound(lightness + 1.176);
//console.log(lightness);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
};
};
},
};
elements.hell_creeper_head = {
color: ["#D2D2D2", "#ff141e", "#fc3232", "#e84a4a", "#b13333", "#913535", "#954242", "#872828", "#8b4949", "#2b0304", "#111111", "#faae3c", "#f5e131"],
category: "life",
hidden: true,
density: 1080,
state: "solid",
conduct: 25,
tempHigh: 2000,
stateHigh: "ash",
tempLow: -30,
stateLow: "frozen_meat",
breakInto: ["blood","fire"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 },
"oxygen": { "elem2":"carbon_dioxide", "chance":0.5 }
},
properties: {
dead: false,
following: false,
hissing: false,
charged: false,
didChargeBlueTinted: false
},
movable: true,
tick: function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
return
}
}
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "hell_creeper_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill head
pixel.dead = body.dead;
}
}
else { var body = null }
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
if(pixel.charge) {
pixel.charged = true;
};
if(body) {
if(typeof(body.charge) !== "undefined") {
if(body.charge) {
pixel.charged = true;
};
};
if(typeof(body.charged) !== "undefined") {
if(body.charged) {
pixel.charged = true;
};
};
};
if(typeof(pixel.charged) === "undefined") {
pixel.charged = false;
};
if(pixel.charged) {
var explosionRadius = 10;
if(!pixel.didChargeBlueTinted) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel.color;
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + 51);
green = rgbColorBound(green + 51);
blue = rgbColorBound(blue + 102);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
hue = hue % 360; //piecewise hue shift
if(hue <= 235 && hue >= 135) {
hue = 185;
} else if(hue < 135) {
hue += 50;
} else if(hue > 235 && hue < 360) {
hue -= 50;
};
saturation = slBound (saturation + 10);
lightness = slBound(lightness + 20);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
pixel.didChargeBlueTinted = true;
};
} else {
var explosionRadius = 7;
};
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) { //probably misapplying the tolerance from the MC Wiki line: "Creepers will chase after any player, as long as it is within a 16 block (±5%) radius"
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Start "hissing" if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 3.15) {
pixel.hissing = true;
if(!pixel.hissStart) {
pixel.hissStart = pixelTicks;
};
};
break;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break;
};
};
};
};
};
//Pre-explosion handler: keeps track of time before the kaboom
for(i = 0; i < 1; i++) { //dummy for loop
if(pixel.hissing) {
//console.log("Ssssssss");
if(pixel.dead || !body || body.dead) { //can't explode without a body according to the classic creeper anatomy
//console.log("ss-- oof");
pixel.hissing = false;
break;
};
if(!pixel.hissStart) {
//console.log("t-30 ticks or whatever it was");
pixel.hissStart = pixelTicks;
};
//Color code {
var ticksHissing = pixelTicks - pixel.hissStart;
var color = pixel.color; //do on each hissing tick
if(color.startsWith("rgb")) {
//console.log("rgb detected");
color = color.split(","); //split color for addition
var red = parseFloat(color[0].substring(4));
var green = parseFloat(color[1]);
var blue = parseFloat(color[2].slice(0,-1));
red = rgbColorBound(red + ticksHissing);
green = rgbColorBound(green + ticksHissing);
blue = rgbColorBound(blue + ticksHissing);
color = `rgb(${red},${green},${blue})`;
pixel.color = color;
//console.log("color set");
} else if(color.startsWith("hsl")) {
//console.log("hsl detected");
color = color.split(","); //split color for addition
var hue = parseFloat(color[0].substring(4));
var saturation = parseFloat(color[1].slice(0,-1));
var lightness = parseFloat(color[2].slice(0,-2));
lightness = slBound(lightness + 1.176);
color = `hsl(${hue},${saturation}%,${lightness}%)`;
pixel.color = color;
//console.log("color set");
};
//}
if(pixelTicks - pixel.hissStart > 30) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAtPlus(pixel.x,pixel.y,explosionRadius,"fire","fire",null,hellExplosionFire);
//console.log("Yes, Rico, kaboom.");
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
//Lightning strikes charge creepers
elements.lightning.tick = function(pixel) {
if (!pixel.stage) { // create bolt
var y = pixel.y;
var xoffset = 0;
var last = [pixel.x,pixel.y]
for (var i = 0; i < 100; i++) {
y++;
// randomly go back and forth
if (Math.random() > 0.5) { xoffset++; }
else { xoffset--; }
var x = pixel.x + xoffset;
if (isEmpty(x, y)) {
createPixel("lightning",x,y);
pixelMap[x][y].stage = 1;
pixelMap[x][y].color = pixel.color;
last = [x,y];
}
else if (outOfBounds(x,y) || !elements[pixelMap[x][y].element].isGas) {
var newPixel = pixelMap[x]?.[y] ?? null;
if(newPixel && newPixel.element.includes("creeper") && newPixel.dir !== undefined && !(newPixel.charged) && !(newPixel.dead)) {
//Charge creeper
newPixel.charged = true;
getMooreNeighbors(newPixel).forEach(function(pixel) { if(pixel.element == "lightning") { deletePixel(pixel.x,pixel.y) } });
break;
} else {
//strike
if (Math.random() < 0.01) { // BALL LIGHTNING
pixelMap[last[0]][last[1]].stage = 9;
}
if (!outOfBounds(x,y)) { pixelMap[x][y].temp = 27760 }
explodeAt(x, y, 13, ["plasma","plasma","plasma","electric"]);
break;
}
}
}
doDefaults(pixel);
deletePixel(pixel.x, pixel.y);
}
else if (pixel.stage === 9) { // BALL LIGHTNING
// move either left or right randomly
if (Math.random() > 0.5) { tryMove(pixel, pixel.x + 1, pixel.y) }
else { tryMove(pixel, pixel.x - 1, pixel.y) }
// create electric in a 3x3 area around pixel
for (var x = pixel.x - 1; x <= pixel.x + 1; x++) {
for (var y = pixel.y - 1; y <= pixel.y + 1; y++) {
if (isEmpty(x, y)) {
createPixel("electric",x,y);
pixelMap[x][y].color = pixel.color;
}
}
}
doDefaults(pixel);
if (pixelTicks - pixel.start >= 250) { deletePixel(pixel.x, pixel.y); }
}
else if (pixelTicks - pixel.start >= 4) {
doDefaults(pixel);
//deletePixel(pixel.x, pixel.y);
changePixel(pixel, "electric")
}
else { doDefaults(pixel); }
};
/* +-----------------------------------+
| Nothing There |
| |
| amogus |
| |
| red imposter |
| |
| |
| |
| |
| |
| |
| |
+-----------------------------------+ */
elements.nothing_there_bullet = {
flippableX: true,
movable: true,
density: 10000,
desc: "A hypersonic bullet made of Nothing There's flesh. I don't remember if it can turn humans into red clouds.",
color: "#a3281a",
related: ["nothing_there_phase_3_body","nothing_there_phase_3_head"],
movable: true,
tick: function(pixel) {
if(typeof(pixel.flipX) == undefined) {
pixel.flipX = !!Math.floor(Math.random() * 2);
};
var dir = pixel.flipX ? -1 : 1;
for(i = 0; i < 6; i++) {
if(outOfBounds(pixel.x+dir,pixel.y)) {
deletePixel(pixel.x,pixel.y);
break;
};
if(!nothingThereBulletMovement(pixel,pixel.x+dir,pixel.y)) {
return true;
};
};
},
};
elements.nothing_there_mace = {
movable: true,
density: 10000,
desc: "A spiky mace attached to Nothing There, which can turn humans into red clouds.",
color: "#fa4632",
properties: {
counter: 2
},
related: ["nothing_there_phase_3_body","nothing_there_phase_3_head"],
movable: true,
tick: function(pixel) {
if(outOfBounds(pixel.x,pixel.y + 1)) {
deletePixel(pixel.x,pixel.y);
return false;
};
if(!tryMove(pixel,pixel.x,pixel.y + 1)) {
var newPixel = pixelMap[pixel.x][pixel.y + 1];
var newElement = newPixel.element;
var newInfo = elements[newElement];
if(newElement !== pixel.element) {
if(newInfo.state === "gas") {
swapPixels(pixel,newPixel);
} else {
if(pixel.counter > 0) {
explodeAtPlus(pixel.x,pixel.y + 1,5,null,null);
pixel.counter--;
} else {
deletePixel(pixel.x,pixel.y);
return true;
};
};
};
};
},
};
elements.nothing_there_cleaver = {
movable: true,
density: 10000,
desc: "A very sharp blade attached to Nothing There, which can turn humans into red clouds.",
color: "#a33c3c",
properties: {
counter: 4
},
related: ["nothing_there_phase_3_body","nothing_there_phase_3_head"],
movable: true,
tick: function(pixel) {
if(outOfBounds(pixel.x,pixel.y + 1)) {
deletePixel(pixel.x,pixel.y);
return false;
};
if(!tryMove(pixel,pixel.x,pixel.y + 1)) {
var newPixel = pixelMap[pixel.x][pixel.y + 1];
var newElement = newPixel.element;
var newInfo = elements[newElement];
if(!nothingThereBulletExcludedElements.includes(newElement)) {
if(pixel.counter > 0) {
swapPixels(pixel,newPixel);
breakPixel(newPixel,false,false);
pixel.counter--;
} else {
deletePixel(pixel.x,pixel.y);
return true;
};
} else {
deletePixel(pixel.x,pixel.y);
return false;
};
};
},
};
testSwapArray = ["meat","cooked_meat","rotten_meat","blood","infection","antibody","plague","zombie_blood","frozen_meat","frozen_rotten_meat"];
elements.nothing_there_phase_1 = {
color: "#faacac",
category: "life",
density: 2000,
desc: "O-06-20 (ALEPH) In this phase, it looks like a dog made of misshapen human parts. It can easily turn humans into unrecognizable messes.",
state: "solid",
tempHigh: 3000,
hardness: 0.995,
stateHigh: "cooked_meat",
burn: 1,
burnTime: 250000,
burnInto: "cooked_meat",
breakInto: ["blood","meat","magic"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.00002 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.00004 },
"plague": { "elem1":"plague", "chance":0.000003 }
},
related: ["nothing_there_phase_2", "nothing_there_phase_3_body", "nothing_there_phase_3_head"],
properties: {
dead: false,
dir: 1,
following: false
},
movable: true,
tick: function(pixel) {
var pixelBreakInto = elements[pixel.element].breakInto;
tryMove(pixel, pixel.x, pixel.y+1); // Fall
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Break if pixelTicks-dead > 5
if (pixelTicks-pixel.dead > 5) {
changePixel(pixel,pixelBreakInto[Math.floor(Math.random() * pixelBreakInto.length)],false);
};
return;
};
if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0], //dash move
[1*pixel.dir,-1], //cleave move
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if(tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
break;
} else { //move through given pixels
if(!isEmpty(pixel.x+move[0], pixel.y+move[1], true)) {
var blockingPixel = pixelMap[pixel.x+move[0]][pixel.y+move[1]];
//console.log(blockingPixel);
var blockingElement = blockingPixel.element;
if(testSwapArray.includes(blockingElement)) {
swapPixels(pixel,blockingPixel);
break;
};
};
};
};
// 15% chance to change direction while not chasing a human
if(!pixel.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
var pX = pixel.x;
var pY = pixel.y;
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
if(pixelTicks % 2 == 0 && !pixel.dead) { //reduce rate for performance
/*var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};*/
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-35 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 35 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
};
};
if(pixelTicks - pixel.start > 300 && (Math.random() < 0.003)) {
var dir = pixel.dir;
changePixel(pixel,"nothing_there_phase_2",false);
pixel.dir = dir;
};
//End
},
};
elements.nothing_there_phase_2 = {
behavior: behaviors.POWDER_OLD,
color: "#d90b0b",
category: "life",
density: 4000,
desc: "O-06-20 (ALEPH) In this phase, it looks like a red, fibrous cocoon. It will soon hatch into its third phase.",
state: "solid",
tempHigh: 3500,
hardness: 0.999,
stateHigh: "cooked_meat",
burn: 1,
burnTime: 350000,
burnInto: "cooked_meat",
breakInto: ["blood","meat","magic"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.000001 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.000001 },
"plague": { "elem1":"plague", "chance":0.000001 }
},
related: ["nothing_there_phase_1", "nothing_there_phase_3_body", "nothing_there_phase_3_head"],
properties: {
dead: false,
dir: 1,
timer: 0
},
movable: true,
tick: function(pixel) {
var pixelBreakInto = elements[pixel.element].breakInto;
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Break if pixelTicks-dead > 5
if (pixelTicks-pixel.dead > 5) {
changePixel(pixel,pixelBreakInto[Math.floor(Math.random() * pixelBreakInto.length)],false);
};
return;
};
if(pixelTicks - pixel.start > 300) {
var dir = pixel.dir;
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("nothing_there_phase_3_body", pixel.x, pixel.y+1);
pixel.element = "nothing_there_phase_3_head";
pixel.color = pixelColorPick(pixel)
pixelMap[pixel.x][pixel.y+1].dir = dir;
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("nothing_there_phase_3_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "nothing_there_phase_3_body";
pixel.color = pixelColorPick(pixel)
pixel.dir = dir;
};
};
//End
},
};
elements.nothing_there_phase_3 = {
color: "#fc1e35",
category: "life",
desc: "Spawns Nothing There in its humanoid third phase, for when you don't want to wait for it to go through the other phases.",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("nothing_there_phase_3_body", pixel.x, pixel.y+1);
pixel.element = "nothing_there_phase_3_head";
pixel.color = pixelColorPick(pixel)
} else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("nothing_there_phase_3_head", pixel.x, pixel.y-1);
pixel.element = "nothing_there_phase_3_body";
pixel.color = pixelColorPick(pixel)
} else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["nothing_there_phase_3_body","nothing_there_phase_3_head"],
};
elements.nothing_there_phase_3_body = {
color: "#fc1e35",
category: "life",
density: 3000,
desc: "O-06-20 (ALEPH) In this phase, it looks like a humanoid made of misarranged flesh. It is almost indestructible and has a variety of ways to destroy your canvas and annihilate any humans inside of it. Let's hope it doesn't learn to blend in and walk among us.",
state: "solid",
tempHigh: 3000,
hardness: 0.9975,
hidden: true,
stateHigh: "cooked_meat",
burn: 1,
burnTime: 300000,
burnInto: "cooked_meat",
breakInto: ["blood","meat","magic"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.00001 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.00002 },
"plague": { "elem1":"plague", "chance":0.0000015 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
related: ["nothing_there_phase_1", "nothing_there_phase_2", "nothing_there_mace", "nothing_there_cleaver", "nothing_there_bullet"],
tick: function(pixel) {
var pixelBreakInto = elements[pixel.element].breakInto;
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "nothing_there_phase_3_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Break if pixelTicks-dead > 5
if (pixelTicks-pixel.dead > 5) {
changePixel(pixel,pixelBreakInto[Math.floor(Math.random() * pixelBreakInto.length)],false);
};
return;
};
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true)) {
if(pixelMap[pixel.x][pixel.y-1].element == "nothing_there_phase_3_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
};
} else {
var head = null;
};
} else { var head = null };
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 30% chance
if (Math.random() < 0.3) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 10% chance
if (Math.random() < 0.1) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return } //do not proceed if headless
else if (Math.random() < 0.08) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
},
};
elements.nothing_there_phase_3_head = {
color: "#ff3046",
category: "life",
density: 3000,
desc: "O-06-20 (ALEPH) In this phase, it looks like a humanoid made of misarranged flesh. It is almost indestructible and has a variety of ways to destroy your canvas and annihilate any humans inside of it. Let's hope it doesn't learn to blend in and walk among us.",
state: "solid",
tempHigh: 3000,
hardness: 0.9975,
hidden: true,
stateHigh: "cooked_meat",
burn: 1,
burnTime: 300000,
burnInto: "cooked_meat",
breakInto: ["blood","meat","magic"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.00001 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.00002 },
"plague": { "elem1":"plague", "chance":0.0000015 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
related: ["nothing_there_phase_1", "nothing_there_phase_2", "nothing_there_mace", "nothing_there_cleaver", , "nothing_there_bullet"],
tick: function(pixel) {
var pixelBreakInto = elements[pixel.element].breakInto;
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Break if pixelTicks-dead > 5
if (pixelTicks-pixel.dead > 5) {
changePixel(pixel,pixelBreakInto[Math.floor(Math.random() * pixelBreakInto.length)],false);
};
return;
};
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true)) {
if(pixelMap[pixel.x][pixel.y+1].element == "nothing_there_phase_3_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill body
pixel.dead = body.dead;
};
} else {
var body = null;
};
} else { var body = null };
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 30% chance
if (isEmpty(pixel.x, pixel.y+1) && Math.random() < 0.3) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 10% chance
if (Math.random() < 0.10) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
//Human detection loop
if(pixelTicks % 2 == 0 && !pixel.dead) { //reduce rate for performance
/*var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};*/
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
//do action every 40 ticks
var bulletPositions = [[-1, -1], [-1, 0]];
var bulletPosition = bulletPositions[Math.floor(Math.random() * 2)];
var smashPosition = [-1, -1];
var cleavePositions = [[-1, -1], [-2, -1], [-3, -1]];
var start = 2 * Math.floor(pixel.start/2);
if((pixelTicks - start) % 40 == 0) {
var action = Math.floor(Math.random() * 3);
if(action == 0) { //bullet
var bX = pX + bulletPosition[0];
var bY = pY + bulletPosition[1];
if(!outOfBounds(bX,bY)) {
if(isEmpty(bX,bY)) {
createPixel("nothing_there_bullet",bX,bY);
pixelMap[bX][bY].flipX = true;
} else {
if(!nothingThereBulletExcludedElements.includes(pixelMap[bX][bY].element)) {
deletePixel(bX,bY);
createPixel("nothing_there_bullet",bX,bY);
pixelMap[bX][bY].flipX = true;
};
};
};
} else if(action == 1) { //smash
var sX = pX + smashPosition[0];
var sY = pY + smashPosition[1];
if(!outOfBounds(sX,sY)) {
if(isEmpty(sX,sY)) {
createPixel("nothing_there_mace",sX,sY);
} else {
if(!nothingThereBulletExcludedElements.includes(pixelMap[sX][sY].element)) {
deletePixel(sX,sY);
createPixel("nothing_there_mace",sX,sY);
};
};
};
} else if(action == 2) { //cleave
for(cleaverIndex = 0; cleaverIndex < cleavePositions.length; cleaverIndex++) {
var cX = pX + cleavePositions[cleaverIndex][0];
var cY = pY + cleavePositions[cleaverIndex][1];
if(!outOfBounds(cX,cY)) {
if(isEmpty(cX,cY)) {
createPixel("nothing_there_cleaver",cX,cY);
} else {
if(!nothingThereBulletExcludedElements.includes(pixelMap[cX][cY].element)) {
deletePixel(cX,cY);
createPixel("nothing_there_cleaver",cX,cY);
};
};
};
};
};
};
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-35 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
//do action every 40 ticks
var bulletPositions = [[1, -1], [1, 0]];
var bulletPosition = bulletPositions[Math.floor(Math.random() * 2)];
var smashPosition = [1, -1];
var cleavePositions = [[1, -1], [2, -1], [3, -1]];
var start = 2 * Math.floor(pixel.start/2);
if((pixelTicks - start) % 40 == 0) {
var action = Math.floor(Math.random() * 3);
if(action == 0) { //bullet
var bX = pX + bulletPosition[0];
var bY = pY + bulletPosition[1];
if(!outOfBounds(bX,bY)) {
if(isEmpty(bX,bY)) {
createPixel("nothing_there_bullet",bX,bY);
pixelMap[bX][bY].flipX = false;
} else {
if(!nothingThereBulletExcludedElements.includes(pixelMap[bX][bY].element)) {
deletePixel(bX,bY);
createPixel("nothing_there_bullet",bX,bY);
pixelMap[bX][bY].flipX = false;
};
};
};
} else if(action == 1) { //smash
var sX = pX + smashPosition[0];
var sY = pY + smashPosition[1];
if(!outOfBounds(sX,sY)) {
if(isEmpty(sX,sY)) {
createPixel("nothing_there_mace",sX,sY);
} else {
if(!nothingThereBulletExcludedElements.includes(pixelMap[sX][sY].element)) {
deletePixel(sX,sY);
createPixel("nothing_there_mace",sX,sY);
};
};
};
} else if(action == 2) { //cleave
for(cleaverIndex = 0; cleaverIndex < cleavePositions.length; cleaverIndex++) {
var cX = pX + cleavePositions[cleaverIndex][0];
var cY = pY + cleavePositions[cleaverIndex][1];
if(!outOfBounds(cX,cY)) {
if(isEmpty(cX,cY)) {
createPixel("nothing_there_cleaver",cX,cY);
} else {
if(!nothingThereBulletExcludedElements.includes(pixelMap[cX][cY].element)) {
deletePixel(cX,cY);
createPixel("nothing_there_cleaver",cX,cY);
};
};
};
};
};
};
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 35 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) { //If not dead
pixel.following = true;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
if(coordPyth(pX,pY,nX,nY) <= 1.5) { //approx. sqrt(2)
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else { //Mutilate if dead
if(Math.random() < 1/4) { //One-fourth chance to change to blood
changePixel(newPixel,"blood",false);
} else { //Remaining 3/4 chance to change to meat
changePixel(newPixel,"meat",false);
};
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
console.log("3/4 loaded"); //the real 3/4 point was inside Nothing There's tick function
runAfterLoad(function() {
if(typeof(badPixels) === "object") {
badPixels.nothing_there_phase_1 = { panicIncrease: 1, panicIncreaseChance: 1 } //insta-panic for "aleph" thing and "level 1" humans
badPixels.nothing_there_phase_2 = { panicIncrease: 1, panicIncreaseChance: 1 }
badPixels.nothing_there_phase_3_body = { panicIncrease: 1, panicIncreaseChance: 1 }
badPixels.nothing_there_phase_3_head = { panicIncrease: 1, panicIncreaseChance: 1 }
}
});
/* +-----------------------------------+
| End Nothing There elements |
| |
| |
| |
| |
| |
+-----------------------------------+ */
/* +++++++++++++++++++++++++++
+ Start skeleton elements +
+++++++++++++++++++++++++++ */
arrowExcludedElements = ["wall"];
arrowPlacementExcludedElements = ["skeleton_head", "skeleton_body", "arrow", "wall"];
elements.rock.hardness = 0.55;
elements.arrow = {
cooldown: 2,
flippableX: true,
movable: true,
properties: {
flipY: false,
speed: 5,
fall: 0,
attached: false,
attachOffsets: [null, null],
penetrateCounter: 7
},
density: 2471,
color: "#cacdcf",
related: ["skeleton_body","skeleton_head"],
movable: true,
burn: 20,
//burnInto: "flint",
burnInto: "rock",
burnTime: 250,
breakInto: ["gravel","gravel","sawdust","feather"],
tick: function(pixel) {
if(pixel.attachOffsets.includes(null)) {
pixel.attached = false;
};
if(pixel.attached) {
var attachCoords = [pixel.x+pixel.attachOffsets[0], pixel.y+pixel.attachOffsets[1]];
var attachX = pixel.x + pixel.attachOffsets[0];
var attachY = pixel.y + pixel.attachOffsets[1];
if(isEmpty(attachX,attachY,true)) {
pixel.attached = false;
} else {
var attachPixel = pixelMap[attachX][attachY];
var attachInfo = elements[attachPixel.element];
var attachState = "solid";
if(typeof(attachInfo.state) === "string") {
attachState = attachInfo.state;
};
var attachBlacklistStates = ["liquid","gas"];
if(attachBlacklistStates.includes(attachState)) {
pixel.attached = false;
};
};
} else { //Move if not attached
var speedForBreakMult = pythSpeed(pixel.speed,pixel.y);
var breakMult = speedForBreakMult/5;
if(typeof(pixel.flipX) == undefined) {
pixel.flipX = !!Math.floor(Math.random() * 2);
};
var dir = pixel.flipX ? -1 : 1;
if(Math.random() < (1/(pixel.speed**1.585))) { //1/0 is Infinity in JavaScript, so this should always be true at 0 speed)
pixel.fall++;
};
//Horizontal movement
for(i = 0; i < pixel.speed; i++) {
if(outOfBounds(pixel.x+dir,pixel.y)) {
deletePixel(pixel.x,pixel.y);
break;
};
if(!isEmpty(pixel.x+dir,pixel.y,true)) {
var otherPixel = pixelMap[pixel.x+dir][pixel.y];
var otherElement = otherPixel.element;
var otherInfo = elements[otherElement];
if(arrowExcludedElements.includes(otherElement)) {
pixel.attached = true; //attach
pixel.speed = 0;
pixel.fall = 0;
pixel.attachOffsets = [dir, 0];
break;
};
var otherDensity = (typeof(otherInfo.density) === "undefined" ? 1000 : otherInfo.density);
var swapChance = 1 - Math.max(0,(otherDensity / 2471));
if(Math.random() < swapChance && pixel.penetrateCounter > 0) {
swapPixels(pixel,otherPixel);
arrowAltTb(otherPixel,breakMult);
pixel.speed = Math.max(0,--pixel.speed);
pixel.penetrateCounter--;
} else {
if(!arrowAltTb(otherPixel,breakMult)) { //if this didn't break it
pixel.attached = true; //attach
pixel.speed = 0;
pixel.fall = 0;
pixel.attachOffsets = [dir, 0];
};
};
break;
} else {
tryMove(pixel,pixel.x+dir,pixel.y);
};
};
if(Math.random() < 0.1) {
pixel.speed = Math.max(0,--pixel.speed);
};
var dirY = 1;
//Vertical movement
if(typeof(pixel.flipY) !== "undefined") {
if(pixel.flipY) {
pixel.dirY = -1;
};
};
for(j = 0; j < pixel.fall; j++) {
if(outOfBounds(pixel.x,pixel.y+dirY)) {
deletePixel(pixel.x,pixel.y);
break;
};
if(!isEmpty(pixel.x,pixel.y+dirY,true)) {
var otherPixel = pixelMap[pixel.x][pixel.y+dirY];
var otherElement = otherPixel.element;
var otherInfo = elements[otherElement];
if(arrowExcludedElements.includes(otherElement)) {
pixel.attached = true; //attach
pixel.speed = 0;
pixel.fall = 0;
pixel.attachOffsets = [0, dirY];
break;
};
var otherDensity = (typeof(otherInfo.density) === "undefined" ? 1000 : otherInfo.density);
var swapChance = 1 - Math.max(0,(otherDensity / 2471));
if(Math.random() < swapChance && pixel.penetrateCounter > 0) {
swapPixels(pixel,otherPixel);
arrowAltTb(otherPixel,breakMult);
pixel.speed = Math.max(0,--pixel.speed);
pixel.penetrateCounter--;
} else {
if(!arrowAltTb(otherPixel,breakMult)) { //if this didn't break it
pixel.attached = true; //attach
pixel.speed = 0;
pixel.fall = 0;
pixel.attachOffsets = [0, dirY];
};
};
break;
} else {
tryMove(pixel,pixel.x,pixel.y+dirY);
};
};
//End
};
},
};
elements.skeleton = {
color: ["#ebebe6", "#cfcfc8"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
following: false
},
movable: true,
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("skeleton_body", pixel.x, pixel.y+1);
pixel.element = "skeleton_head";
pixel.color = pixelColorPick(pixel)
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("skeleton_head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "skeleton_body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
related: ["skeleton_body","skeleton_head"],
desc: "If this text is green or underlined, skeletons can spawn.Click here to toggle skeleton spawning. If it's on, skeletons (all types) can spawn through random events."
};
elements.skeleton_body = {
color: "#ebebe6",
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "bone",
burn: 10,
burnTime: 250,
burnInto: ["bone","ash","arrow"],
hardness: 0.55,
breakInto: ["bone","bone","bone","bone_marrow"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0,
chargeCounter: 20,
shooting: false
},
movable: true,
tick: function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headPixel = pixelMap[pixel.x][pixel.y-2];
if (headPixel.element == "skeleton_head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into bone if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
changePixel(pixel,"bone");
}
return
}
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "skeleton_head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
}
}
else { var head = null }
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 10% chance (bone marrow)
if (Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
else if (head == null) { return }
else if (Math.random() < 0.1) { // Move 10% chance
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
break;
};
};
};
// 15% chance to change direction while not chasing a human
if(!head.following) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
}/* else {
//console.log("*chases cutely*");
};*/
};
if(pixel.shooting) {
if(pixel.chargeCounter <= 0) {
var bX = pixel.x + pixel.dir;
var bY = pixel.y - 1;
var arrowFlipX = null;
if(pixel.dir < 0) {
arrowFlipX = true;
} else if(pixel.dir > 0) {
arrowFlipX = false;
};
if(!outOfBounds(bX,bY)) {
if(isEmpty(bX,bY)) {
createPixel("arrow",bX,bY);
pixelMap[bX][bY].flipX = arrowFlipX;
} else {
if(!arrowExcludedElements.includes(pixelMap[bX][bY].element) && !arrowPlacementExcludedElements.includes(pixelMap[bX][bY].element)) {
deletePixel(bX,bY);
createPixel("arrow",bX,bY);
pixelMap[bX][bY].flipX = arrowFlipX;
};
};
};
pixel.chargeCounter = 20;
};
if(pixel.chargeCounter > 0) {
pixel.chargeCounter--;
};
};
},
};
elements.skeleton_head = {
color: ["#ebebe6", "#cfcfc8"],
category: "life",
hidden: true,
density: 1500,
state: "solid",
conduct: 25,
tempHigh: 250,
stateHigh: "bone",
burn: 10,
burnTime: 250,
burnInto: ["bone","ash","arrow"],
hardness: 0.55,
breakInto: ["bone","bone","bone","bone_marrow"],
reactions: {
"cancer": { "elem1":"cancer", "chance":0.005 },
"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"plague": { "elem1":"plague", "chance":0.05 }
},
properties: {
dead: false,
dir: 1,
panic: 0
},
movable: true,
tick: function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if (pixel.dead) {
// Turn into bone if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
changePixel(pixel,"bone");
}
return
}
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "skeleton_body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill head
pixel.dead = body.dead;
}
}
else { var body = null }
if(body) {
if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
pixel.dir = body.dir;
};
};
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
//start of most new code
var pX = pixel.x;
var pY = pixel.y;
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
var directionAdverb = "left";
if(pixel.dir > 0) {
directionAdverb = "right";
};
//console.log(`Looking ${directionAdverb}`)
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
if(body) body.shooting = true;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(enemyHumanoidArray.includes(newElement)) {
//console.log(`Human part found at (${nX},${nY})`)
if(!newPixel.dead) {
pixel.following = true;
if(body) body.shooting = true;
};
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break;
};
};
};
};
};
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.following = false;
//console.log("Meh.");
};
},
};
/* -------------------------
- End skeleton elements -
------------------------- */
mobsLoaded = true;
//CHANGES TO HUMANS ##
function hasPixel(x,y,elementInput) {
if(isEmpty(x,y,true)) { //if empty, it can't have a pixel
return false;
} else {
if(elementInput.includes(",")) { //CSTA
elementInput = elementInput.split(",");
};
if(Array.isArray(elementInput)) { //if element list
return elementInput.includes(pixelMap[x][y].element);
} else { //if single element
return pixelMap[x][y].element === elementInput;
};
};
};
elements.brain = {
color: ["#fce3e3","#deb6c5","#f5ced5","#e87b8f"],
behavior: [
"XX|XX|XX",
"XX|CH:rotten_meat%1|XX",
"M2|M1|M2",
],
reactions: {
"dirty_water": { "elem1":"rotten_meat", "chance":0.1 },
"fly": { "elem1":"rotten_meat", "chance":0.2 },
"dioxin": { "elem1":"rotten_meat", "elem2":null, "chance":0.1 },
"uranium": { "elem1":"rotten_meat", "chance":0.1 },
"cancer": { "elem1":"rotten_meat", "chance":0.1 },
"plague": { "elem1":"rotten_meat", "elem2":null, "chance":0.3 },
"ant": { "elem1":"rotten_meat", "chance":0.1 },
"worm": { "elem1":"rotten_meat", "chance":0.1 },
"rat": { "elem1":"rotten_meat", "chance":0.3 },
"mushroom_spore": { "elem1":"rotten_meat", "chance":0.1 },
"mushroom_stalk": { "elem1":"rotten_meat", "chance":0.1 },
"mercury": { "elem1":"rotten_meat", "elem2":null, "chance":0.2 },
"mercury_gas": { "elem1":"rotten_meat", "elem2":null, "chance":0.1 },
"virus": { "elem1":"rotten_meat", "chance":0.1 },
"poison": { "elem1":"rotten_meat", "elem2":null, "chance":0.5 },
"infection": { "elem1":"rotten_meat", "elem2":null, "chance":0.1 },
"ink": { "elem1":"rotten_meat", "elem2":null, "chance":0.1 },
"acid": { "elem1":"rotten_meat", "elem2":null, "chance":0.5 },
"acid_gas": { "elem1":"rotten_meat", "chance":0.4 },
"cyanide": { "elem1":"rotten_meat", "elem2":null, "chance":0.5 }
},
tempHigh: 100,
stateHigh: "cooked_meat",
tempLow: -18,
stateLow: "frozen_meat",
category:"life",
hidden: true,
breakInto: ["meat", "blood"],
burn:10,
burnTime:200,
burnInto:["cooked_meat","steam","steam","salt"],
state: "solid",
density: 1081,
conduct: 1,
};
elements.cerebrospinal_fluid = {
color: "#ced7db",
behavior: behaviors.LIQUID,
state: "liquid",
tempHigh: 100,
stateHigh: "steam",
breakInto: "steam",
reactions: JSON.parse(JSON.stringify(elements.water.reactions)),
};
function validatePanic(pixel) {
//console.log(`validatePanic: validatePanic called on pixel ${pixel.element} at (${pixel.x},${pixel.y}) with panic level ${pixel.panic || 0}`);
if(pixel.element.endsWith("body")) {
//console.log("validatePanic called on body pixel (panic is stored in the head)");
};
if(Number.isNaN(pixel.panic)) {
//console.log("NaN case: panic set to 0");
pixel.panic = 0;
};
//console.log(`Bounding code running from value of ${pixel.panic}`);
pixel.panic = Math.max(0,Math.min(1,pixel.panic));
//console.log(`Validation result: Panic set to ${pixel.panic}`);
if(Number.isNaN(pixel.mood)) {
//console.log("NaN case: mood set to 0");
pixel.mood = 0;
};
//console.log(`Bounding code running from value of ${pixel.mood}`);
pixel.mood = Math.max(-3,Math.min(3,pixel.mood));
//console.log(`Validation result: Mood set to ${pixel.mood}`);
};
goodPixels = {
silver: { panicChange: 0.01, panicChangeChance: 0.1, moodChange: 0.004 },
gold: { panicChange: 0.02, panicChangeChance: 0.15, moodChange: 0.01 },
diamond: { panicChange: 0.03, panicChangeChance: 0.2, moodChange: 0.02 },
}; //effectively, the difference is that good pixels don't make the human flip direction (run away);
badPixels = {
rotten_meat: { panicChange: 0.02, panicChangeChance: 0.15, moodChange: -0.015 },
blood: { panicChange: 0.06, panicChangeChance: 0.2, moodChange: -0.006 },
brain: { panicChange: 0.1, panicChangeChance: 0.3, moodChange: -0.005 },
fire: { panicChange: 0.1, panicChangeChance: 0.1, moodChange: 0 },
poison: { panicChange: 0.2, panicChangeChance: 0.05, moodChange: -0.01 },
grenade: { panicChange: 0.2, panicChangeChance: 0.4, moodChange: -0.3 },
bomb: { panicChange: 0.2, panicChangeChance: 0.4, moodChange: -0.3 },
tnt: { panicChange: 0.2, panicChangeChance: 0.4, moodChange: 0 },
dynamite: { panicChange: 0.2, panicChangeChance: 0.4, moodChange: -0.3 },
upward_bomb: { panicChange: 0.2, panicChangeChance: 0.4, moodChange: -0.3 },
cluster_bomb: { panicChange: 0.2, panicChangeChance: 0.4, moodChange: -0.4 },
landmine: { panicChange: 0.25, panicChangeChance: 0.1, moodChange: -0.3 },
fireball: { panicChange: 0.25, panicChangeChance: 0.45, moodChange: -0.35 },
magma: { panicChange: 0.3, panicChangeChance: 0.2, moodChange: 0 },
plasma: { panicChange: 0.3, panicChangeChance: 0.2, moodChange: 0 },
nuke: { panicChange: 1, panicChangeChance: 1, moodChange: -1 }, //insta-panic
cluster_nuke: { panicChange: 1, panicChangeChance: 1, moodChange: -1 }, //insta-panic
nothing_there_phase_1: { panicChange: 10, panicChangeChance: 1, moodChange: -1 }, //insta-panic
nothing_there_phase_2: { panicChange: 10, panicChangeChance: 1, moodChange: -1 }, //insta-panic
nothing_there_phase_3: { panicChange: 10, panicChangeChance: 1, moodChange: -1 }, //insta-panic
}; //testing
otherPixels = ["head","body"]; //do custom code here
var initialTransparencyArray = ["glass","water","salt_water","sugar_water","steam","oxygen","nitrogen","neon","methane","propane","anesthesia","ammonia","carbon_dioxide","helium","hydrogen","ozone","radiation","pool_water"];
for(transparentElementIndex = 0; transparentElementIndex < initialTransparencyArray.length; transparentElementIndex++) {
var transparentElement = initialTransparencyArray[i];
if(typeof(elements[transparentElement]) !== "undefined") {
elements[transparentElement].transparent = true;
};
};
elements.body.properties = {
dead: false,
dir: 1,
extremePanicStart: null,
};
elements.body.tick = function(pixel) {
var heat;
if(pixel.temp < 20) {
heat = 0.02
} else if(pixel.temp < 0) {
heat = 0.024
} else if(pixel.temp > 30) {
heat = 0.008
} else if(pixel.temp > 40) {
heat = 0.01
} else {
heat = 0.012
}
if(typeof(pixel.extremePanicStart) == "undefined") {
//console.log("oops");
pixel.extremePanicStart = null
};
if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
var headpixel = pixelMap[pixel.x][pixel.y-2];
if (headpixel.element == "head") {
if (isEmpty(pixel.x, pixel.y-1)) {
movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
}
else {
swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
}
}
}
}
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if(pixel.dead === false && pixel.temp >= 38) {
var deathChance = 0.01 + (Math.max(0,pixel.temp - 38) / 100) + (Math.max(0,pixel.temp - 41.1) / 3);
if(Math.random() < deathChance) { pixel.dead = pixelTicks };
}
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
changePixel(pixel,"rotten_meat");
}
return
}
// Find the head
if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "head") {
var head = pixelMap[pixel.x][pixel.y-1];
if (head.dead) { // If head is dead, kill body
pixel.dead = head.dead;
}
}
else { var head = null }
if (isEmpty(pixel.x, pixel.y-1)) {
// create blood if decapitated 10% chance
if (Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y-1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
if (head == null) { return };
heat -= (head.panic * 0.006);
pixel.temp += heat;
head.temp += heat;
if (Math.random() < (0.1 + head.panic)) { // Move 10% chance, varying depending on panic value
var movesToTry = [
[1*pixel.dir,0],
[1*pixel.dir,-1],
];
// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
while (movesToTry.length > 0) {
var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
/*
console.log(move);
console.log("Body X:", pixel.x, "to", pixel.x+move[0]);
console.log("Body Y:", pixel.y, "to", pixel.y+move[1]);
console.log("Head X:",head.x, "to", head.x+move[0]);
console.log("Head Y:", head.y, "to", head.y+move[1]);
*/
//If head coords are empty
if (isEmpty(pixel.x+move[0], pixel.y+move[1]) && isEmpty(head.x+move[0], head.y+move[1])) {
//console.log("Head target coords are empty");
if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
movePixel(head, head.x+move[0], head.y+move[1]);
//console.log(`Moved body to (${pixel.x},${pixel.y}) and head to (${head.x},${head.y})`);
//console.log(`Head-body offset (should always be [0,-1]): [${head.x-pixel.x},${head.y-pixel.y}]`)
break;
}
}
}
// 15% chance to change direction
if(!head.dirLocked) {
if (Math.random() < 0.15) {
pixel.dir *= -1;
//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
};
};
};
//if not flagged for extreme panic
//extreme panic will not be flagged in good moods, just to be nice
if(pixel.extremePanicStart == null && head.panic > 0.8 && head.mood <= 0) {
//flag extreme panic
pixel.extremePanicStart = pixelTicks;
}
//if flagged for extreme panic and panic is still extreme
else if(pixel.extremePanicStart != null && (head.panic > 0.8 && head.mood <= 0)) {
//if extreme panic lasts too long
if(pixelTicks - pixel.extremePanicStart > 350) {
//random chance to die from exhaustion/a heart attack/whatever
if(Math.random() < 0.001) {
pixel.dead = pixelTicks;
};
};
}
//if flagged for extreme panic and extreme panic is no longer extreme
else if(pixel.extremePanicStart != null && (head.panic <= 0.8 || head.mood > 0)) {
//unflag
pixel.extremePanicStart = null;
};
};
elements.body.onTryMoveInto = function(pixel,otherPixel) {
var pX = pixel.x;
var pY = pixel.y;
if(!pixel.dead && hasPixel(pX,pY-1,"head")) { //if this body pixel is alive and has a head
var head = pixelMap[pX][pY-1];
var otherElement = otherPixel.element;
var oX = otherPixel.x;
var oY = otherPixel.y;
if(oY !== (pY - 1)) { //exclude the head above this body
if(otherElement === "head") { //if the pixel hitting this body is a head
if(hasPixel(oX,oY+1,"body")) { //if the pixel hitting this pixel has a body under it
var otherBody = pixelMap[oX][oY+1];
if(otherPixel.dead || otherBody.dead) { //if either part of that human is dead
head.panic += 0.08; //being hit by a dead ******* body is terrifying
} else {
if(otherPixel.panic > 0.04 && otherPixel.mood <= 0) { head.panic += 0.04 }; //living, normal, bodied heads scare only if that incoming human is already scared
};
} else { //if it's a severed head
if(otherPixel.dead) { //if the head is dead
head.panic += 0.08; //being hit by a /severed ******* head/ is terrifying
} else {
head.panic += 0.1; //being hit by a //******* severed head that's still alive// is even worse
};
};
} else if(otherElement === "body") { //if the pixel hitting this body is a body
if(hasPixel(oX,oY-1,"head")) { //if the pixel hitting this pixel has a head on it
var otherHead = pixelMap[oX][oY-1];
if(otherPixel.dead || otherHead.dead) { //if either part of that human is dead
head.panic += 0.06; //dead whole body case
} else {
if(otherHead.panic > 0.04) { head.panic += 0.04 }; //living, normal, bodied heads scare only if that incoming human is already scared
};
} else { //severed body case
if(otherPixel.dead) { //if the body is dead
head.panic += 0.08; //imagine being hit by a severed human without the head
} else {
head.panic += 0.1; //imagine the above but the heart is still beating
};
};
};
};
};
};
elements.head.properties = {
dead: false,
dirLocked: false,
panic: 0,
};
elements.head.tempHigh = 100;
elements.head.stateHigh = "cooked_meat";
elements.body.tempHigh = 100;
elements.body.stateHigh = "cooked_meat";
elements.head.tick = function(pixel) {
doHeat(pixel);
doBurning(pixel);
doElectricity(pixel);
if(pixel.dead === false && pixel.temp >= 38) {
var deathChance = 0.01 + (Math.max(0,pixel.temp - 38) / 100) + (Math.max(0,pixel.temp - 41.1) / 3);
if(Math.random() < deathChance) { pixel.dead = pixelTicks };
}
if (pixel.dead) {
// Turn into rotten_meat if pixelTicks-dead > 500
if (pixelTicks-pixel.dead > 200) {
changePixel(pixel,"rotten_meat");
return
}
}
// Find the body
if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "body") {
var body = pixelMap[pixel.x][pixel.y+1];
if (body.dead) { // If body is dead, kill head
pixel.dead = body.dead;
}
}
else { var body = null }
if (isEmpty(pixel.x, pixel.y+1)) {
tryMove(pixel, pixel.x, pixel.y+1);
// create blood if severed 10% chance
if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
createPixel("blood", pixel.x, pixel.y+1);
// set dead to true 15% chance
if (Math.random() < 0.15) {
pixel.dead = pixelTicks;
}
}
}
pixel.mood ??= 0;
if((pixelTicks-pixel.start) % 5 === 0) {
//Vision loop
var pX = pixel.x;
var pY = pixel.y;
if(pixel.dir === -1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = (-1); j > (-16 - 1); j--) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(Object.keys(goodPixels).includes(newElement)) {
//no dir flip
if(Math.random() > goodPixels[newElement].panicChangeChance) {
pixel.panic = Math.max(0.25,pixel.panic + goodPixels[newElement].panicChange);
pixel.mood += goodPixels[newElement].moodChange; //like if there was a pretty painting item, it would make you feel better but you wouldn't necessarily feel the need to run towards it
};
pixel.dirLocked = true;
} else if(Object.keys(badPixels).includes(newElement)) {
body.dir = 1; //flip dir
if(Math.random() > badPixels[newElement].panicChangeChance) {
pixel.panic += badPixels[newElement].panicChange;
pixel.mood += badPixels[newElement].moodChange;
};
pixel.dirLocked = true;
}; //good and bad should be mutually exclusive; good will be evaulated first because one inevitably has to be considered first
if(otherPixels.includes(newElement)) {
//specific custom code
if(newElement === "head") {
if(hasPixel(nX,nY+1,"body")) {
var newBody = pixelMap[nX][nY+1];
if(newPixel.dead || newBody.dead) {
pixel.panic += 0.02; //if it's seeing a whole human, it's likely to see the dead head and the dead body, thus double-executing
//it would be nice if there was a way to avoid double/multiple detection of the same human
if(hasPixel(pX,pY+1,"body")) { //mix error-proofing
var body = pixelMap[pX][pY+1];
body.dir = 1; //run away
};
} else {
if(newPixel.panic > 0.04) {
if(newPixel.panic > 0.8) {
pixel.panic += 0.015; //it will add up
} else if(newPixel.panic > 0.6) {
pixel.panic += 0.012;
} else if(newPixel.panic > 0.4) {
pixel.panic += 0.009;
} else if(newPixel.panic > 0.2) {
pixel.panic += 0.006;
} else {
pixel.panic += 0.003;
};
//the vision loop is in the head, and this is in the "seeing head" case, then this will happen when the head sees another head, and heads store panic; this is in the "other head" is panicking case so this will ultimately be the code that runs when its human sees another human panicking
if(Math.random() < 0.5) {
//run in same direction as panicking person
pixel.dir = newPixel.dir
};
};
};
} else { //severed head
newPixel.dead ? pixel.panic += 0.03 : pixel.panic += 0.04;
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = 1; //run away
};
};
} else if(newElement === "body") {
if(hasPixel(nX,nY-1,"head")) {
var newHead = pixelMap[nX][nY-1];
if(newPixel.dead || newHead.dead) {
pixel.panic += 0.02;
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = 1; //run away
};
} else {
if(newHead.panic > 0.04) {
if(newHead.panic > 0.8) {
pixel.panic += 0.014; //it will add up
} else if(newHead.panic > 0.6) {
pixel.panic += 0.011;
} else if(newHead.panic > 0.4) {
pixel.panic += 0.008;
} else if(newHead.panic > 0.2) {
pixel.panic += 0.005;
} else {
pixel.panic += 0.002;
};
};
};
} else { //severed body
newPixel.dead ? pixel.panic += 0.025 : pixel.panic += 0.035;
if(hasPixel(pX,pY+1,"body")) { //mix error-proofing
var body = pixelMap[pX][pY+1];
body.dir = 1; //run away
};
};
};
};
//code outside of those three if blocks will be applied to pixels of all elements
if(!elements[newElement].transparent) {
break; //can't see through humans
};
};
};
};
} else if(pixel.dir === 1) {
for(i = -4; i < 4+1; i++) {
var oY = i;
//console.log(`Starting row look at row ${pY+oY}`)
for(j = 1; j < 16 + 1; j++) {
var oX = j;
var nX = pX+oX;
var nY = pY+oY;
if(outOfBounds(nX,nY)) {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
break;
};
if(isEmpty(nX,nY)) {
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
continue;
};
if(!isEmpty(nX,nY,true)) {
var newPixel = pixelMap[nX][nY];
var newElement = newPixel.element;
if(Object.keys(goodPixels).includes(newElement)) {
//no dir flip
if(Math.random() > goodPixels[newElement].panicChangeChance) {
pixel.panic = Math.max(0.25,pixel.panic + goodPixels[newElement].panicChange);
pixel.mood += goodPixels[newElement].moodChange;
};
pixel.dirLocked = true;
} else if(Object.keys(badPixels).includes(newElement)) {
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = -1; //run away
};
if(Math.random() > badPixels[newElement].panicChangeChance) {
pixel.panic += badPixels[newElement].panicChange;
pixel.mood += badPixels[newElement].moodChange;
};
pixel.dirLocked = true;
}; //good and bad should be mutually exclusive; good will be evaulated first because one inevitably has to be considered first
if(otherPixels.includes(newElement)) {
if(newElement === "head") {
if(hasPixel(nX,nY+1,"body")) {
var newBody = pixelMap[nX][nY+1];
if(newPixel.dead || newBody.dead) {
pixel.panic += 0.02; //if it's seeing a whole human, it's likely to see the dead head and the dead body, thus double-executing
//it would be nice if there was a way to avoid double/multiple detection of the same human
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = -1; //run away
};
} else {
if(newPixel.panic > 0.04) {
if(newPixel.panic > 0.8) {
pixel.panic += 0.015; //it will add up
} else if(newPixel.panic > 0.6) {
pixel.panic += 0.012;
} else if(newPixel.panic > 0.4) {
pixel.panic += 0.009;
} else if(newPixel.panic > 0.2) {
pixel.panic += 0.006;
} else {
pixel.panic += 0.003;
};
};
};
} else { //severed head
newPixel.dead ? pixel.panic += 0.03 : pixel.panic += 0.04;
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = -1; //run away
};
};
} else if(newElement === "body") {
if(hasPixel(nX,nY-1,"head")) {
var newHead = pixelMap[nX][nY-1];
if(newPixel.dead || newHead.dead) {
pixel.panic += 0.02;
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = -1; //run away
};
} else {
if(newHead.panic > 0.04) {
if(newHead.panic > 0.8) {
pixel.panic += 0.014; //it will add up
} else if(newHead.panic > 0.6) {
pixel.panic += 0.011;
} else if(newHead.panic > 0.4) {
pixel.panic += 0.008;
} else if(newHead.panic > 0.2) {
pixel.panic += 0.005;
} else {
pixel.panic += 0.002;
};
};
};
} else { //severed body
newPixel.dead ? pixel.panic += 0.025 : pixel.panic += 0.035;
if(hasPixel(pX,pY+1,"body")) {
var body = pixelMap[pX][pY+1];
body.dir = -1; //run away
};
};
};
};
//code outside of those three if blocks will be applied to pixels of all elements
if(!elements[newElement].transparent) {
break; //can't see through humans
};
};
};
};
};
};
validatePanic(pixel);
if(Math.random() < 0.01) { //1% chance each tick to lose interest
pixel.dirLocked = false;
//console.log("Meh.");
};
if(Math.random() < ((pixel.panic) > 0.8 ? 0.04 : 0.02)) { //2% chance each tick to decrease panic (4% if the panic is extreme)
//console.log("Decreasing panic");
pixel.panic < 0.05 ? pixel.panic = 0 : pixel.panic -= 0.05;
};
if(pixel.dead !== false && (pixelTicks - pixel.dead <= 1)) { elements.grayscale.tool(pixel) }
};
elements.head.breakInto = ["bone","brain","brain","cerebrospinal_fluid","blood","blood","meat"];
elements.head.onTryMoveInto = function(pixel,otherPixel) {
var pX = pixel.x;
var pY = pixel.y;
if(!pixel.dead) {
var otherElement = otherPixel.element;
var oX = otherPixel.x;
var oY = otherPixel.y;
if(oY !== (pY + 1)) { //exclude the body under this head
if(otherElement === "head") { //if the pixel hitting this head is also a head
//console.log("head.onTryMoveInto: Head has tried to move into head");
if(hasPixel(oX,oY+1,"body")) { //if the pixel hitting this pixel has a body under it
var otherBody = pixelMap[oX][oY+1];
if(otherPixel.dead || otherBody.dead) { //if either part of that human is dead
pixel.panic += 0.08; //being hit by a dead ******* body is terrifying
//console.log("head.onTryMoveInto: panic increase, case: head hit by dead whole body (head's code branch)");
} else {
//if(otherPixel.panic > 0.04) { pixel.panic += 0.04; console.log("head.onTryMoveInto: panic increase, case: head hit by panicked whole body (head's code branch)"); }; //living, normal, headed bodies scare only if that incoming human is already scared
};
} else { //if it's a severed head
if(otherPixel.dead) { //if the head is dead
pixel.panic += 0.08; //being hit by a /severed ******* head/ is terrifying
//console.log("head.onTryMoveInto: panic increase, case: head hit by dead severed head");
} else {
pixel.panic += 0.1; //being hit by a //******* severed head that's still alive// is even worse
//console.log("head.onTryMoveInto: panic increase, case: head hit by living severed head");
};
};
} else if(otherElement === "body") { //if the pixel hitting this head is a body
if(hasPixel(oX,oY-1,"head")) { //if the body hitting this pixel has a head on it
var otherHead = pixelMap[oX][oY-1];
if(otherPixel.dead || otherHead.dead) { //if either part of that human is dead
pixel.panic += 0.03; //dead whole body case
//console.log("head.onTryMoveInto: panic increase, case: head hit by dead whole body (body's code branch)");
} else {
if(otherHead.panic > 0.04) {
pixel.panic += 0.03;
//console.log("head.onTryMoveInto: panic increase, case: head crushed by panicked whole body (body's code branch)");
} else {
pixel.panic += 0.02;
//console.log("head.onTryMoveInto: panic increase, case: head crushed by whole body (body's code branch)");
};
};
} else { //severed body case
if(otherPixel.dead) { //if the body is dead
pixel.panic += 0.04; //imagine being hit by a severed human without the head
//console.log("head.onTryMoveInto: panic increase, case: head hit by dead severed body");
} else {
pixel.panic += 0.05; //imagine the above but the heart is still beating
//console.log("head.onTryMoveInto: panic increase, case: head hit by living severed body");
};
};
} else {
if(oX === pX && oY === pY-1) {
var otherInfo = elements[otherElement];
var otherState; typeof(otherInfo.state) === "undefined" ? otherState = null : otherState = otherInfo.state;
var otherDensity = typeof(otherInfo.density) === "undefined" ? otherDensity = null : otherDensity = otherInfo.density;
if(otherState === "solid") {
if(otherDensity > 5000) {
var chance = (0.1 + (otherDensity/50000)) / 5;
if(Math.random() < chance) {
breakPixel(pixel);
};
} else if(otherDensity >= 500) {
pixel.panic += (0.01 * (otherDensity / 500));
} else if(otherDensity >= 100) {
pixel.panic += (0.001 * (otherDensity / 100));
};
};
};
};
};
};
};
//Worldgen preset for testing
worldgentypes.basalt_dirt = {
layers: [
[0, "basalt", 0.05],
[0, "dirt"]
]
};
kep1er = [
//Conn. 0 Conn. - Conn. 1
["first_impact", ["#E34B6E","#FE9F19","#8E5ECE"]],
//Lemon Bl. B1ue Bl.
["doublast", ["#FFFB1D","#2B8FFF"]],
//not edition colors because i'm not doing all of those and they're all really similar anyway (the kep1ian editions are too similar to each other)
["fly-up", ["#f2f2f2","#15a667","#de0180"]],
//K Midn. Daydr.; physical albums do not look like their "theme colors" and are mostly black
["troubleshooter", ["#EE378E","#088EE7","#FDDC03"]],
//see fly-up
["fly-by", ["#e7e6dd","#fcf0ef","#efa1ba","#8d7cb6","#5e74ba","#2b5db5","#e292b7"]],
//Eye Cont. L. Str. 1st Blush
["lovestruck", ["#C1CCE6","#F5E4CE","#FFD9E0"]],
//Beloved S.kissed Moonlighted
["magic_hour", ["#EDC1D2","#EFCBB1","#7585B6"]],
//Standard Limited A Limited B
["fly-high", ["#CBB4BB","#BF888F","#635A69","#635A69","#DDDBDE","BA5069"]],
//Standard Limited A Limited B
["kep1going", ["#1B1B1D","#20252B","#3D4546","#8B8988","#101010","#101010","#252527","#D0D3D6","#130908","#130908","#65302C","#E09C9F"]],
//gee that's not co- //Scene Nous -nfusing at all, wakeone
["kep1going_on", ["#BAABD4","#403A76"]],
//Connect N Lost Love & Seek
["tipi-tap", ["#EA99AD","#FCCEDB","#FCFBFC","#DEDEDE","#1D63A9","#BCE1F0",]]
];
for(index in kep1er) {
index = parseInt(index);
var newName = kep1er[index][0];
var newColor = kep1er[index][1];
var newDisplayName = newName.replaceAll("_"," ").replaceAll("-"," - ").split(" ").map(x => x.substring(0,1).toUpperCase() + x.substring(1)).join(" ").replace(" - ","-");
elements[newName] = {
name: newDisplayName,
color: newColor,
tempHigh: 200,
stateHigh: ["ash","molten_plastic"],
density: 332, //based off of First Impact: https://www.amazon.com/Kep1er-IMPACT-Contents-Tracking-Connect/dp/B09MQMNZ62
//there's only one way to find out the real density of each album and i CANNOT afford that
tick: function(pixel) {
if(!(tryMove(pixel,pixel.x,pixel.y+1))) {
var directions = [];
if(isEmpty(pixel.x-1,pixel.y+1) && isEmpty(pixel.x-1,pixel.y+2)) {
directions.push(-1)
};
if(isEmpty(pixel.x+1,pixel.y+1) && isEmpty(pixel.x+1,pixel.y+2)) {
directions.push(1)
};
if(directions.length > 0) {
tryMove(pixel,pixel.x+directions[Math.floor(Math.random() * directions.length)],pixel.y)
};
};
doHeat(pixel);
},
reactions: {
water: { elem1: ["plastic","cellulose","cellulose"], elem2: ["water","water","cellulose",null,null], chance: 0.8 }
},
burn: 40,
burnTime: 150,
burnInto: ["ash","molten_plastic","carbon_dioxide","smoke"],
category: "other"
};
goodPixels[newName] = { panicChange: 0.01, panicChangeChance: 0.2, moodChange: 0.035 };
};
//CHANGES TO SPONGES ##
elements.sponge.properties ??= {};
elements.sponge.properties.maxAbsorb = 250;
elements.sponge.tick = function(pixel) {
pixel.absorbed ??= {};
var coordsToCheck = [
[pixel.x-1,pixel.y],
[pixel.x+1,pixel.y],
[pixel.x,pixel.y-1],
[pixel.x,pixel.y+1],
];
shuffleArray(coordsToCheck);
for (var i = 0; i < coordsToCheck.length; i++) {
if(sumNumericArray(Object.values(pixel.absorbed)) >= pixel.maxAbsorb) {
break;
};
var coord = coordsToCheck[i];
if (!isEmpty(coord[0],coord[1],true)) {
var newPixel = pixelMap[coord[0]][coord[1]];
if (elements[newPixel.element].state === "liquid" && ((elements[newPixel.element].density || 0) < 2500)) {
pixel.absorbed[newPixel.element] ??= 0;
pixel.absorbed[newPixel.element]++;
deletePixel(coord[0],coord[1]);
};
};
};
if((pixel.absorbed.water ?? 0) < 5) {
doBurning(pixel);
};
};
elements.sponge.onTryMoveInto = function(pixel,otherPixel) {
var absorbedElements = Object.keys(pixel.absorbed ?? {});
if(absorbedElements.length == 0) {
return false;
};
var otherInfo = elements[otherPixel.element]
if((otherInfo.state ?? "solid") == "solid" && (otherInfo.density ?? 1000) >= 200) {
//console.log(otherPixel.element,otherInfo.state);
var outputOffsets = [pixel.x - otherPixel.x, pixel.y - otherPixel.y];
var twiceOffsets = outputOffsets.map(x => x * 2);
var newCoords = [pixel.x + outputOffsets[0], pixel.y + outputOffsets[1]];
var twiceCoords = [pixel.x + twiceOffsets[0], pixel.y + twiceOffsets[1]];
if(!isEmpty(newCoords[0],newCoords[1],true)) {
if(outOfBounds(newCoords[0],newCoords[1])) { //fail if OOB
return false;
};
var newPixel = pixelMap[newCoords[0]][newCoords[1]];
if((elements[newPixel.element].state ?? "solid") !== "gas") { //only displace gases
return false;
};
if(!tryMove(newPixel,twiceCoords[0],twiceCoords[1])) { //if it can't push the gas out to the next pixel over
return false; //then return false because perpendicular expulsion too complex and multifaceted to deal with
};
};
if(isEmpty(pixel.x,pixel.y+1)) {
var randomElement = randomChoice(absorbedElements);
if(pixel.absorbed[randomElement] > 0) {
if(tryCreatePixel(randomElement,newCoords[0],newCoords[1])) { pixel.absorbed[randomElement]-- };
} else {
delete pixel.absorbed[randomChoice]
};
};
};
};
//MIX OF PRIMORDIAL SOUP AND BIRTHPOOL (also primordial soup freezing, and state fixes) ##
elements.primordial_soup.tempLow = 0;
elements.birthpool.tempHigh = 100;
elements.birthpool.stateHigh = ["magic","steam"];
elements.birthpool.tempLow = 0;
elements.birthpool.state = "liquid";
elements.birthpool.forceAutoGen = true;
elements.primordial_birthpool = {
color:["#5E7453","#5E745D","#5E744B","#6C7C50","#6C7C59","#6C7C47"],
state: "liquid",
tempHigh: 100,
stateHigh: ["steam","steam","magic"],
behavior: [
"CR:foam%1|CR:sapling,wheat_seed,flower_seed,algae,cell,mushroom_spore,lichen,yeast,antibody,cellulose%0.5 AND CR:foam%2|CR:foam%1",
"M2|XX|M2",
"M1|M1|M1",
],
reactions: {
"cancer": { "elem1":["toxic_mistake","dirty_water"] },
"cyanide": { "elem1":["toxic_mistake","dirty_water"] },
"infection": { "elem1":["toxic_mistake","dirty_water"] },
"plague": { "elem1":["toxic_mistake","dirty_water"] },
"ammonia": { "elem1":["algae","cell","mushroom_spore","lichen","yeast","antibody"], "chance":0.05 },
"radiation": { "elem1":["algae","cell","mushroom_spore","lichen","yeast","antibody"], "chance":0.15 },
"light": { "elem1":["algae","cell","mushroom_spore","lichen","yeast","antibody"], "chance":0.5 },
"oxygen": { "elem1":["algae","cell","mushroom_spore","lichen","yeast","antibody"], "chance":0.02 }
},
density: 1110,
tempHigh: 100,
stateHigh: "steam",
conduct: 0.33,
category: "liquids",
hidden: true,
reactions: {
concoction: { "elem1": ["primordial_soup", "birthpool", "primordial_birthpool"], "elem2": ["primordial_soup", "birthpool", "primordial_birthpool"], "chance":0.0045}
},
};
if(!elements.birthpool.reactions) {
elements.birthpool.reactions = {}
}
elements.birthpool.reactions.primordial_soup = { "elem1":"primordial_birthpool", "elem2":"primordial_birthpool" }
//AUTOGENERATED CONTENT ##
//Required secondary function
function canvasfooterTemplate() { //CURSED AF
return `Changelog(NEW) • Feedback • Wiki • YouTube • Discord • Install Offline
v${currentversion} • ${elementCount} elements, with ${hiddenCount} hidden.