sandboxels/index.html

8239 lines
338 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sandboxels</title>
<meta name="description" content="A falling sand simulation game, with heat transfer, electricity, density, fire, explosions, and more.">
<meta name="keywords" content="falling sand, elements, pixel art, simulator, powder">
<meta name="author" content="R74n">
<meta name="copyright" content="R74n">
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="all">
<!--Favicons-->
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-touch-icon.png?v=2">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png?v=2">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png?v=2">
<link rel="manifest" href="manifest.json">
<link rel="mask-icon" href="icons/safari-pinned-tab.svg?v=2" color="#2167ff">
<link rel="shortcut icon" href="icons/favicon.ico?v=2">
<meta name="msapplication-TileColor" content="#e6d577">
<meta name="theme-color" content="#000000">
<!--OpenGraph-->
<meta property="og:locale" content="en_US">
<meta property="og:type" content="website">
<meta property="og:title" content="Sandboxels">
<meta property="og:description" content="A falling sand simulation game, with heat transfer, electricity, density, fire, explosions, and more.">
<meta property="og:url" content="https://sandboxels.r74n.com">
<meta property="og:site_name" content="Sandboxels">
<meta property="og:image" content="https://sandboxels.r74n.com/icons/wallpaper.png">
<meta property="og:image:width" content="1980">
<meta property="og:image:height" content="971">
<meta property="og:image:type" content="image/png">
<meta property="og:image:alt" content="A rainforest made in Sandboxels">
<!--Twitter-->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:description" content="A falling sand simulation game, with heat transfer, electricity, density, fire, explosions, and more.">
<meta name="twitter:title" content="Sandboxels">
<meta name="twitter:site:id" content="1436857621827530753">
<meta name="twitter:image" content="https://sandboxels.r74n.com/icons/card.png">
<meta name="twitter:image:alt" content="A rainforest made in Sandboxels">
<meta name="twitter:creator:id" content="1436857621827530753">
<!-- Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": ["VideoGame","MobileApplication","WebApplication"],
"gamePlatform":"Web Browser",
"image":"https://sandboxels.r74n.com/icons/icon.png",
"url": "https://sandboxels.r74n.com",
"name":"Sandboxels",
"author":"R74n",
"creator":"R74n",
"description":"Sandboxels is an in-browser falling sand simulation game, with mechanics such as heat simulation, electricity, density, chemical reactions, fire, and over 200 unique elements to play with.",
"offers":{
"@type":"Offer",
"price":"0",
"priceCurrency":"USD",
"availability":"https://schema.org/InStock"
},
"genre": "Falling-sand game",
"softwareVersion":"1.2",
"datePublished":"2021-12-15",
"dateCreated":"2021-12-15",
"gameTip":"https://sandboxels.r74n.com/controls.txt",
"screenshot": "https://sandboxels.r74n.com/icons/wallpaper.png",
"softwareRequirements": "HTML5",
"archivedAt": "https://web.archive.org/web/20211230010640000/https://sandboxels.r74n.com/",
"copyrightYear": 2022
}</script>
<script src="https://R74n.com/load.js"></script>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0;
}
body {
font-family: 'Press Start 2P';
background-color: #000000;
color: #ffffff;
}
.pagetitle {
padding: 10px;
padding-bottom: 0px;
font-size: 0.75em;
position: absolute;
top: 0;
left: 0;
}
a {color: rgb(255, 0, 255);text-decoration: none;}
a:hover {color: rgb(255, 121, 255);}
a:active, a:hover:active {color: rgb(255, 179, 255);}
#gameDiv { /*game canvas*/
border: 1px solid #ffffff;
position: absolute;
left: 50%;
transform: translate(-50%, -0%);
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
margin-top: 15px;
}
#infoParent, #modParent, #settingsParent {
display: none;
}
#infoScreen, #modManager, #settingsMenu {
border: 1px solid #ffffff;
position: absolute;
left: 50%;
transform: translate(-50%, 28%);
width: 95%;
height: 50%;
max-width: 700px;
padding: 10px;
background-color: rgb(31, 31, 31);
overflow-x: hidden;
}
.menuTitle {
font-size: 1.5em;
text-decoration: underline;
}
.menuText {
margin-top: 5px;
line-height: 1.5em;
}
#infoText {
white-space: pre-wrap;
}
.XButton {
position: absolute;
right: 0px;
top: 0px;
font-size: 2em;
background-color: rgb(100, 33, 33);
padding:5px;
text-align:center;
border: 1px solid #ffffff;
}
.XButton:hover {
background-color: rgb(200, 33, 33);
}
#infoSearch, #modManagerUrl {
position: absolute;
bottom: 50%;
width: 95%;
max-width: 700px;
height: 50px;
left: 50%;
transform: translate(-50%, 198.5%);
background-color: rgb(66, 66, 66);
color: white;
font-size: 1.5em;
padding: 8px;
font-family: 'Press Start 2P';
}
#infoSearch:focus, #modManagerUrl:focus {
outline: none;
}
/*#modManagerAdd {
position: absolute;
bottom: 25%;
right: 25%;
height: 50px;
width: 50px;
transform: translate(-25%, -25%);
background-color: rgb(0, 190, 32);
color: white;
font-size: 2em;
padding: 10px;
font-family: 'Press Start 2P';
}*/
#modManagerList {
margin-top: 20px;
}
#modManagerList li {
list-style-type: none;
position: relative;
}
#modManagerList li::before {
content: '•';
position: absolute;
left: -1.5em;
font-size: 1em;
font-family: 'Press Start 2P';
}
.removeModX {
color: red;
cursor: pointer;
}
.removeModX:hover {
color: rgb(255, 107, 107);
}
.infoLink {
color: rgb(116, 140, 221);
cursor: pointer;
text-decoration: underline;
}
button, input[type="submit"], input[type="reset"] {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
}
.usingTab button:focus {
filter: brightness(75%);
outline: none;
}
#underBox {
position: absolute;
left: 50%;
transform: translate(-50%, -0%);
margin-top: 10px;
width: 100%;
}
#controls button {
padding: 5px 10px;
border-radius: 5px;
font-size: 1em;
text-shadow: 0.5px 1px 4px #000000;
color: rgba(255, 255, 255, 0.75);
border: 1px solid #797979;
margin: 0px 5px 5px 5px;
font-variant: small-caps;
}
#controls button.bright {
text-shadow: 0.5px 1px 4px #ffffff;
color: rgba(0, 0, 0, 0.75);
}
/*Darken when active*/
#controls button:active, #controls button:active:hover {
filter: brightness(60%);
}
#controls button:hover {
filter: brightness(90%);
}
#controls button:disabled {
cursor: not-allowed;
}
#controls button[current="true"], #controls button[on="true"] {
border: 1px solid #ffffff;
filter: brightness(110%);
box-shadow: 0 5px 15px rgba(255, 255, 255, .4);
color: rgba(255, 255, 255, 1);
}
#controls button.bright[current="true"] {
color: rgba(0, 0, 0, 1);
}
#controls button[on="true"] {
border-color:lime;
color:lime;
}
#controls div {
display:block;
}
.stat {
margin-right: 25px;
margin-bottom: 5px;
float:right;
}
#stats {
margin: 0px 5px 5px 5px;
font-size: 0.75em;
height: 2em;
width:100%;
}
/* screen size < 700px */
@media screen and (max-width: 700px) {
#stats {padding-bottom:2em;}
.pagetitle {
font-size: 1em;
padding-left: 0.25em;
}
}
/* screen size > 1325px, h1::after {content:" Sandboxels"} */
@media screen and (min-width: 1325px) {
.pagetitle::after {content:" Sandboxels"}
}
#stat-pos, #stat-pixels, #stat-shift, #stat-tps, #stat-ticks, #stat-view {
float:left;
}
.categoryName {
font-size: 0.75em;
text-transform: uppercase;
margin-left: 5px;
vertical-align: middle;
}
#extraInfo {
margin:5px
}
#toolControls, #category-tools {
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
width: 100%;
position: absolute;
}
#toolControls {
margin-top: -3.5em;
z-index: 3;
}
#category-tools {
margin-top: -1.5em;
z-index: 2;
}
.category {
padding-top: 3em;
}
#categoryControls {
margin-top: 0.5em;
margin-bottom: 5px;
background-color: rgba(255, 255, 255, 0.125);
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
width: 100%;
position: absolute;
z-index: 1;
padding-bottom:1px;
scrollbar-color: rgba(255, 255, 255, 0.25) rgba(255, 255, 255, 0.15);
scrollbar-width: thin;
}
#categoryControls button {
/* Borderless buttons */
border: none;
border-radius: 0;
padding-right: 8px;
margin: 0;
padding-top: 5px;
padding-bottom: 5px;
display: inline-block;
position: relative;
z-index:0;
}
#categoryControls button:not(:last-child) {
border-right: 1px solid rgba(255, 255, 255, 0.4);
}
#categoryControls button[current="true"] {
border: none;
background-color: rgba(255, 255, 255, 0.4);
}
/* Dark Gray X Scrollbar for categoryControls */
#categoryControls::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: rgba(255, 255, 255, 0.15);
}
#categoryControls::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.25);
border-radius: 5px;
}
#categoryControls::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.15);
border-radius: 10px;
}
#categoryControls::-webkit-scrollbar-thumb:hover {
background-color: rgba(255, 255, 255, 0.3);
}
.category {
margin-top:3.1em;
position:relative;
display:flex;
flex-direction: column;
flex-wrap:wrap;
text-align:center;
}
button, input { /*Disable double tap zoom on mobile devices*/
touch-action: manipulation;
}
select {
background-color: black;
vertical-align: middle;
margin-left: 5px;
margin-right: 5px;
border: white 0.5px solid;
border-radius: 20px;
padding: 0.5em;
color: white;
}
#canvasDiv {
position:relative;
}
#colorSelector {
position:absolute;
bottom:1em;
right:1em;
display: none;
}
</style>
<script>
// replaceAll polyfill
if (!String.prototype.replaceAll) {String.prototype.replaceAll = function(str, newStr){if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {return this.replace(str, newStr);}return this.replace(new RegExp(str, 'g'), newStr);};}
// requestFullScreen
function requestFullScreen(element) { /* Supports most browsers and their versions.*/ var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen; if (requestMethod) { /*Native full screen.*/ requestMethod.call(element); } else if (typeof window.ActiveXObject !== "undefined") { /*Older IE.*/ var wscript = new ActiveXObject("WScript.Shell"); if (wscript !== null) { wscript.SendKeys("{F11}"); } } }
</script>
<script> // Mod Loader
runAfterLoadList = [];
// runAfterLoad() takes a function and adds it to the runAfterLoadList.
function runAfterLoad(func) {
runAfterLoadList.push(func);
}
// If the localStorage key "enabledMods" exists, load it as an array.
// If it doesn't exist, create an empty array.
enabledMods = localStorage.getItem("enabledMods") ? JSON.parse(localStorage.getItem("enabledMods")) : [];
// Run all scripts in the enabledMods array, if it fails print to console
for (var i = 0; i < enabledMods.length; i++) {
try {
var script = document.createElement('script');
var src = enabledMods[i];
script.src = src;
document.head.appendChild(script);
} catch (e) {
console.log("Error in mod: " + enabledMods[i]);
console.log(e);
}
}
</script>
<script>
// If settings is in localStorage, load it. If not, create an empty object.
settings = localStorage.getItem("settings") ? JSON.parse(localStorage.getItem("settings")) : {};
function saveSettings() {
localStorage.setItem("settings", JSON.stringify(settings));
}
behaviors = {
POWDER: [
"XX|XX|XX",
"XX|XX|XX",
"M2|M1|M2",
],
AGPOWDER: [
"M2|M1|M2",
"XX|XX|XX",
"XX|XX|XX",
],
LIQUID: [
"XX|XX|XX",
"M2|XX|M2",
"M1|M1|M1",
],
SLIDE: [
"XX|XX|XX",
"XX|XX|M2 AND BO",
"XX|M1|M1",
],
AGLIQUID: [
"M1|M1|M1",
"M2|XX|M2",
"XX|XX|XX",
],
WALL: [
"XX|XX|XX",
"XX|XX|XX",
"XX|XX|XX",
],
UL_UR: [
"M1|M1|M1",
"M2|XX|M2",
"XX|M2|XX",
],
GAS: [
"M2|M1|M2",
"M1|XX|M1",
"M2|M1|M2",
],
DGAS: [
"M2|M1|M2",
"M1|DL%5|M1",
"M2|M1|M2",
],
SUPPORT: [
"XX|XX|XX",
"SP|XX|SP",
"XX|M1|XX",
],
SUPPORTPOWDER: [
"XX|XX|XX",
"SP|XX|SP",
"M2|M1|M2",
],
DELETE: [
"XX|DL|XX",
"DL|XX|DL",
"XX|DL|XX",
],
FILL: [
"XX|CL|XX",
"CL|XX|CL",
"XX|CL|XX",
],
CLONER: [
"XX|CF|XX",
"CF|XX|CF",
"XX|CF|XX",
],
STURDYPOWDER: [
"XX|XX|XX",
"XX|XX|XX",
"XX|M1|XX",
],
SELFDELETE: [
"XX|XX|XX",
"XX|DL|XX",
"XX|XX|XX",
],
FOAM: [
"XX|XX|XX",
"XX|DL%5|XX",
"M2%25|M1%25|M2%25",
],
BUBBLE: [
"XX|XX|XX",
"XX|DL%0.25 AND FX%1|M1%5",
"XX|M1%1|M1%2",
],
STICKY: [
"XX|ST|XX",
"ST|XX|ST",
"XX|ST AND M1|XX",
],
MOLTEN: [
"XX|CR:fire%2.5|XX",
"M2|XX|M2",
"M1|M1|M1",
],
RADPOWDER: [
"XX|CR:radiation%2|XX",
"CR:radiation%2|XX|CR:radiation%2",
"M2|M1|M2",
],
RADMOLTEN: [
"XX|CR:fire,radiation%4.5|XX",
"M2 AND CR:radiation%2|XX|M2 AND CR:radiation%2",
"M1|M1|M1",
],
RADLIQUID: [
"XX|CR:radiation%2|XX",
"M2 AND CR:radiation%2|XX|M2 AND CR:radiation%2",
"M1|M1|M1",
],
}
eLists = {
"ANIMAL": ["flea","ant","fly","firefly","bee","frog","fish","worm","termite","rat","slug","snail"],
"CLEANANIMAL": ["ant","firefly","bee","frog","fish"],
}
//airDensity = 1.225; // kg/m^3
airTemp = 20; // Celsius
// Element Properties
// name - display name of the element [optional]
// color - color of the element's pixel
// behavior - behavior of the element
// ignore - elements to ignore in behavior [must be an array]
// category - category in which the element will show up in
// density - density of the element [only used for movable elements] (kg/m^3)
// state - solid, liquid, or gas [only used for movable elements]
// reactions - instructions for when elements attempt to move onto each other (object)
// conduct - conductivity of the element (0-1)
// behaviorOn - behavior to override when powered
// colorOn - color to change to when powered
// temp - default temperature of the element (Celsius)
// tempHigh - highest temperature before state change (Celsius)
// tempLow - lowest temperature before state change (Celsius)
// stateHigh - element transformed into when tempHigh is reached
// stateLow - element transformed into when tempLow is reached
// viscosity - how slow a liquid will move (higher = slower) (cps)
// burn - chance of burning per tick (0-100) (%)
// burnTime - time to burn (ticks)
// burnInto - element to turn into after burning
// fireColor - color of the flame given off when burning
// burning - whether the element is burning on creation
// charge - charge of the element on creation
// hardness - chance of resisting damage (0-1)
elements = {
"heat": { //hard-coded
color: "#ff0000",
behavior: [
"HT:2|HT:2|HT:2",
"HT:2|HT:2|HT:2",
"HT:2|HT:2|HT:2",
],
temp: 2,
category: "tools",
insulate:true,
},
"cool": { //hard-coded
color: "#0000ff",
behavior: [
"CO:2|CO:2|CO:2",
"CO:2|CO:2|CO:2",
"CO:2|CO:2|CO:2",
],
temp: -2,
category: "tools",
insulate:true,
},
"erase": { //hard-coded
color: "#fdb5ff",
behavior: [
"DL|DL|DL",
"DL|DL|DL",
"DL|DL|DL",
],
category: "tools",
},
"pick": { //hard-coded
color: ["#fa9b9b","#fae99b","#9bfab7","#9b9dfa"],
behavior: [
"CF|CF|CF",
"CF|DL%5|CF",
"CF|CF|CF",
],
category: "tools",
},
"mix": { //hard-coded
color: ["#fff4b5","#a6a6a6"],
behavior: [
"SW|SW|SW",
"SW|DL%5|SW",
"SW|SW|SW",
],
category: "tools",
},
"lookup": { //hard-coded
color: ["#919c9c","#72abab","#919c9c"],
behavior: behaviors.WALL,
category: "tools",
},
"shock": { //hard-coded
color: "#ffff00",
behavior: [
"SH|SH|SH",
"SH|DL%5|SH",
"SH|SH|SH",
],
category: "tools",
},
"paint": {
color: ["#c27070","#c29c70","#c2c270","#70c270","#70c2c2","#7070c2","#c270c2"],
tool: function(pixel) {
if (!shiftDown) {
pixel.color = pixelColorPick(pixel,currentColor)
}
else {
// convert the hex of currentColor to rgb and set it as a string
var rgb = currentColor.replace("#","").match(/.{1,2}/g);
for (var i = 0; i < rgb.length; i++) {
rgb[i] = parseInt(rgb[i],16);
}
pixel.color = "rgb(" + rgb.join(",") + ")"
}
},
customColor: true,
category: "tools",
},
"unpaint": {
color: ["#ffffff","#000000"],
tool: function(pixel) {
pixel.color = pixelColorPick(pixel)
},
category: "tools",
},
"sand": {
color: "#e6d577",
behavior: behaviors.POWDER,
tempHigh: 1700,
stateHigh: "molten_glass",
category: "land",
state: "solid",
density: 1602,
},
/* Tick Examples
"tick_sand": {
color: "#e6d577",
tick: function(pixel) {
tryMove(pixel, pixel.x, pixel.y+1);
doHeat(pixel);
},
tempHigh: 1700,
stateHigh: "molten_glass",
category: "land",
state: "solid",
density: 1602,
hidden: true,
category: "land",
},
"tick_wood": {
color: "#a0522d",
tick: function(pixel) {
doBurning(pixel);
doHeat(pixel);
},
tempHigh: 400,
stateHigh: "fire",
category: "solids",
burn: 5,
burnTime: 300,
burnInto: ["ash","charcoal","fire"],
state: "solid",
hardness: 0.15,
breakInto: "sawdust",
hidden: true,
category: "solids",
},
"tick_wall": {
color: "#808080",
category: "solids",
hidden: true,
},
"tick_props": {
color: "#ffffff",
tick: function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) {
pixel.moves += 1;
}
pixel.age += 1;
if (pixel.moves > 20) { // This pixel will delete itself if it moves 20 times
deletePixel(pixel.x, pixel.y);
}
},
properties: { // Default properties to set when the pixel is created:
"moves": 0,
"age": 0,
},
category: "powders",
hidden: true,
},
*/
"water": {
color: "#2167ff",
behavior: behaviors.LIQUID,
tempHigh: 100,
stateHigh: "steam",
tempLow: 0,
stateLow: "ice",
viscosity: 1,
category: "liquids",
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, },
"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 },
"quicklime": { "elem1": null, "elem2": "slaked_lime", },
"rock": { "elem2": "wet_sand", "chance": 0.00035 },
"ruins": { "elem2": "rock", "chance": 0.00035 },
},
state: "liquid",
density: 997,
conduct: 0.02,
stain: -0.5,
},
"salt_water": {
color: "#4d85ff",
behavior: behaviors.LIQUID,
tempHigh: 102,
stateHigh: ["steam","salt"],
tempLow: -2,
stateLow: "ice",
viscosity: 2,
category: "liquids",
reactions: {
"dirt": { "elem1": null, "elem2": "mud" },
"sand": { "elem1": null, "elem2": "wet_sand", },
"dust": { "elem1": "dirty_water", "elem2": null, },
"ash": { "elem1": "dirty_water", "elem2": null, },
"carbon_dioxide": { "elem1": "dirty_water", "elem2": null, },
"sulfur": { "elem1": "dirty_water", "elem2": null, },
"charcoal": { "elem1": "dirty_water", chance:0.005 },
"rat": { "elem1": "dirty_water", chance:0.005 },
"plague": { "elem1": "dirty_water", "elem2": null, },
"fallout": { "elem1": "dirty_water", chance:0.25 },
"radiation": { "elem1": "dirty_water", chance:0.25 },
"rust": { "elem1": "dirty_water", chance:0.005 },
"quicklime": { "elem1": null, "elem2": "slaked_lime", },
"rock": { "elem2": "wet_sand", "chance": 0.0005 },
},
state: "liquid",
density: 1026,
conduct: 0.1,
stain: -0.66,
},
"sugar_water": {
color: "#8eaae6",
behavior: behaviors.LIQUID,
tempHigh: 105,
stateHigh: ["steam","sugar"],
tempLow: -5,
stateLow: "ice",
viscosity: 5,
category: "liquids",
reactions: {
"dirt": { "elem1": null, "elem2": "mud" },
"sand": { "elem1": null, "elem2": "wet_sand", },
"dust": { "elem1": "dirty_water", "elem2": null, },
"ash": { "elem1": "dirty_water", "elem2": null, },
"carbon_dioxide": { "elem1": "soda", "elem2": null, },
"sulfur": { "elem1": "dirty_water", "elem2": null, },
"charcoal": { "elem1": "dirty_water", chance:0.005 },
"rat": { "elem1": "dirty_water", chance:0.005 },
"plague": { "elem1": "dirty_water", "elem2": null, },
"fallout": { "elem1": "dirty_water", chance:0.25 },
"radiation": { "elem1": "dirty_water", chance:0.25 },
"rust": { "elem1": "dirty_water", chance:0.005 },
"rock": { "elem2": "wet_sand", "chance": 0.0004 },
},
hidden: true,
state: "liquid",
density: 1026,
conduct: 0.05,
stain: -0.45,
},
"seltzer": {
color: ["#8eaae6","#82a4ed","#b5c5e8","#8eaae6","#82a4ed"],
behavior: [
"XX|CR:foam%3|XX",
"M2|XX|M2",
"M2|M1|M2",
],
tempHigh: 98,
stateHigh: ["steam","carbon_dioxide"],
tempLow: 0,
stateLow: "ice",
viscosity: 1,
category: "liquids",
reactions: {
"dirt": { "elem1": null, "elem2": "mud" },
"sand": { "elem1": null, "elem2": "wet_sand", },
"rock": { "elem2": "wet_sand", "chance": 0.0004 },
"sugar": { "elem1": "soda", "elem2": "foam" },
"sugar_water": { "elem1": "soda", "elem2": "foam" },
},
hidden: true,
state: "liquid",
density: 1026.91,
conduct: 0.05,
stain: -0.45,
},
"dirty_water": {
color: ["#0e824e","#07755a","#0c6934"],
behavior: behaviors.LIQUID,
tempHigh: 105,
stateHigh: ["steam","carbon_dioxide"],
tempLow: -5,
stateLow: "ice",
viscosity: 10,
category: "liquids",
reactions: {
"dirt": { "elem1": null, "elem2": "mud" },
"sand": { "elem1": null, "elem2": "wet_sand", },
"rock": { "elem2": "wet_sand", "chance": 0.0004 },
"plant": { "elem1":"water", "chance":0.05 },
"algae": { "elem1":"water", "chance":0.05 },
"charcoal": { "elem1":"water", "chance":0.02 },
"gravel": { "elem1":"water", "chance":0.01 },
},
hidden: true,
state: "liquid",
density: 1050,
conduct: 0.1,
stain: 0.075,
},
"dirt": {
color: ["#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#a88c7b"],
behavior: behaviors.POWDER,
tempHigh:1200,
tempLow: -50,
stateLow: "permafrost",
category:"land",
state: "solid",
density: 1220,
},
"mud": {
color: "#382417",
behavior: behaviors.STURDYPOWDER,
reactions: {
"dirt": { "elem1":"dirt", "elem2":"mud", "chance":0.0005, "oneway":true },
"sand": { "elem1":"dirt", "elem2":"wet_sand", "chance":0.0005, "oneway":true },
},
tempHigh: 100,
stateHigh: "mudstone",
tempLow: -50,
stateLow: "permafrost",
category: "land",
state: "solid",
density: 1730,
stain: 0.02,
},
"wet_sand": {
color: ["#a19348","#b5a85e"],
behavior: behaviors.STURDYPOWDER,
reactions: {
"sand": { "elem1":"sand", "elem2":"wet_sand", "chance":0.0005, "oneway":true },
"dirt": { "elem1":"sand", "elem2":"mud", "chance":0.0005, "oneway":true },
"gravel": { "elem1":"cement", "elem2":null, "chance":0.2 }
},
tempHigh: 100,
stateHigh: "packed_sand",
category: "land",
state: "solid",
density: 1905,
},
"rock": {
color: ["#808080","#4f4f4f","#949494"],
behavior: behaviors.POWDER,
tempHigh: 950,
stateHigh: "magma",
category: "land",
state: "solid",
density: 2550,
hardness: 0.5,
breakInto: ["sand","gravel"],
},
"mudstone": {
color: "#4a341e",
behavior: behaviors.SUPPORT,
tempHigh:1200,
stateHigh: "molten_dirt",
category: "land",
state: "solid",
density: 1250,
breakInto: "dirt",
},
"packed_sand": {
color: "#948b5a",
behavior: behaviors.SUPPORT,
tempHigh:1700,
stateHigh: "molten_glass",
category: "land",
state: "solid",
density: 1682,
breakInto: "sand",
},
"plant": {
color: "#00bf00",
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: 1050,
},
"dead_plant": {
color: ["#826521","#826021","#825321","#70360c"],
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"M2|M1|M2",
],
category:"life",
tempHigh: 300,
stateHigh: "fire",
tempLow: -2,
stateLow: "frozen_plant",
burn:85,
burnTime:45,
state: "solid",
density: 1050,
hidden: true,
},
"frozen_plant": {
color: "#00bf8c",
behavior: behaviors.WALL,
category:"life",
tempHigh: 7,
stateHigh: "dead_plant",
state: "solid",
density: 1050,
hidden: true,
},
"grass": {
color: ["#439809","#258B08","#118511","#127B12","#136D14"],
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"XX|M1|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn:50,
burnTime:20,
category:"life",
state: "solid",
density: 1400,
},
"algae": {
color: ["#395706","#6F9315","#9DCA19"],
behavior: [
"XX|XX|XX",
"SW:water,salt_water,sugar_water,dirty_water%1|XX|SW:water,salt_water,sugar_water,dirty_water%1",
"SW:water,salt_water,sugar_water,dirty_water%10|M1|SW:water,salt_water,sugar_water,dirty_water%10",
],
reactions: {
"wood": { "elem1":"lichen" }
},
category:"life",
tempHigh: 225,
stateHigh: "fire",
burn:95,
burnTime:20,
state: "solid",
density: 920,
},
"concrete": {
color: "#ababab",
behavior: behaviors.SUPPORT,
tempHigh: 1500,
stateHigh: "magma",
category: "powders",
state: "solid",
density: 2400,
hardness: 0.5,
breakInto: "dust",
},
"wall": {
color: "#808080",
behavior: behaviors.WALL,
category: "solids",
insulate: true,
hardness: 1,
},
"fire": {
color: ["#ff6b21","#ffa600","#ff4000"],
behavior: behaviors.UL_UR,
reactions: {
"water": { "elem1": "smoke" },
},
temp:600,
tempLow:100,
stateLow: "smoke",
tempHigh: 7000,
stateHigh: "plasma",
category: "energy",
burning: true,
burnTime: 25,
burnInto: "smoke",
state: "gas",
density: 0.1,
},
"bomb": {
color: "#524c41",
behavior: [
"XX|EX:10|XX",
"XX|XX|XX",
"M2|M1 AND EX:10|M2",
],
category: "weapons",
state: "solid",
density: 1300,
excludeRandom: true,
},
"steam": {
color: "#abd6ff",
behavior: behaviors.GAS,
reactions: {
"steam": { "elem1": null, "elem2": "rain_cloud", "chance":0.3, "y":[0,15] },
"rain_cloud": { "elem1": "rain_cloud", "chance":0.4, "y":[0,15] },
"snow_cloud": { "elem1": "rain_cloud", "chance":0.4, "y":[0,15] },
"hail_cloud": { "elem1": "rain_cloud", "chance":0.4, "y":[0,15] },
"pyrocumulus": { "elem1": "rain_cloud", "chance":0.4, "y":[0,15] },
"fire_cloud": { "elem1": "rain_cloud", "elem2": "pyrocumulus", "chance":0.4, "y":[0,15] },
"smoke": { "elem1": "smog", "elem2": null },
},
temp: 100,
tempLow: 95,
stateLow: "water",
category: "gases",
state: "gas",
density: 0.6,
},
"ice": {
color: "#c5e9f0",
behavior: behaviors.WALL,
temp: 0,
tempHigh: 5,
stateHigh: "water",
category: "solids",
state: "solid",
density: 917,
breakInto: "snow",
},
"snow": {
color: "#e1f8fc",
behavior: behaviors.POWDER,
temp: 0,
tempHigh: 5,
stateHigh: "water",
category: "land",
state: "solid",
density: 100,
},
"packed_snow": {
color: "#bcdde3",
behavior: behaviors.SUPPORTPOWDER,
temp: 0,
tempHigh: 20,
stateHigh: "water",
category: "land",
state: "solid",
density: 400,
},
"wood": {
color: "#a0522d",
behavior: behaviors.WALL,
tempHigh: 400,
stateHigh: "fire",
category: "solids",
burn: 5,
burnTime: 300,
burnInto: ["ember","charcoal","fire"],
state: "solid",
hardness: 0.15,
breakInto: "sawdust",
},
"smoke": {
color: "#383838",
behavior: behaviors.DGAS,
reactions: {
"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] },
"hail_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: "fire",
category: "gases",
state: "gas",
density: 1180,
stain: 0.075,
},
"magma": {
color: ["#ff6f00","#ff8c00","#ff4d00"],
behavior: behaviors.MOLTEN,
reactions: {
"ice": { "elem1": "basalt" },
},
temp: 950,
tempLow: 800,
stateLow: ["basalt","basalt","basalt","rock"],
viscosity: 10000,
category: "liquids",
state: "liquid",
density: 2725,
},
"plasma": {
color: ["#8800ff","#b184d9","#8800ff"],
behavior: behaviors.DGAS,
behaviorOn: [
"M2|M1|M2",
"CL%5 AND M1|XX|CL%5 AND M1",
"M2|M1|M2",
],
temp:7065,
tempLow:5000,
stateLow: "fire",
category: "energy",
state: "gas",
density: 1,
charge: 0.5,
conduct: 1,
},
"cold_fire": {
color: ["#21cbff","#006aff","#00ffff"],
behavior: [
"M1|M1|M1",
"M2|CH:smoke%8|M2",
"XX|M2|XX",
],
reactions: {
"fire": { "elem1": "smoke", "elem2": "smoke" },
"plasma": { "elem1": "light", "elem2": "light" },
},
temp:-200,
tempHigh:0,
stateHigh: "smoke",
category: "energy",
state: "gas",
density: 0.2,
},
"glass": {
color: ["#5e807d","#679e99"],
behavior: behaviors.WALL,
tempHigh: 1500,
category: "solids",
state: "solid",
density: 2500,
breakInto: "glass_shard",
},
"meat": {
color: ["#9E4839","#BA6449","#D2856C","#A14940"],
behavior: [
"XX|XX|XX",
"SP|CH:rotten_meat%0.00025|SP",
"XX|M1|XX",
],
tempHigh: 80,
stateHigh: "cooked_meat",
tempLow: -18,
stateLow: "frozen_meat",
category:"food",
burn:25,
burnTime:200,
burnInto:"cooked_meat",
state: "solid",
density: 1019.5,
conduct: 0.2,
},
"rotten_meat": {
color: ["#9ab865","#b8b165","#b89765"],
behavior: [
"XX|CR:plague%0.25|XX",
"SP|XX|SP",
"XX|M1|XX",
],
tempHigh: 120,
stateHigh: "plague",
category:"food",
hidden: true,
burn:25,
burnTime:200,
burnInto:"plague",
state: "solid",
density: 1005,
conduct: 0.1,
},
"cooked_meat": {
color: ["#AE7D5B","#9B6D54","#7E4D31"],
behavior: behaviors.STURDYPOWDER,
tempHigh: 150,
stateHigh: "ash",
category:"food",
hidden:true,
burn:25,
burnTime:200,
burnInto: "ash",
state: "solid",
density: 1005,
},
"frozen_meat": {
color: "#65b8aa",
behavior: behaviors.STURDYPOWDER,
temp: -18,
tempHigh: 0,
stateHigh: "meat",
category:"food",
hidden:true,
state: "solid",
density: 1067.5,
},
"chocolate": {
color: "#4d2818",
behavior: behaviors.STURDYPOWDER,
tempHigh: 31,
stateHigh: "chocolate_syrup",
category: "food",
state: "solid",
density: 1325,
},
"cloner": {
color: "#dddd00",
behavior: behaviors.CLONER,
ignore: ["ecloner","slow_cloner","clone_powder","floating_cloner"],
category:"machines",
insulate:true,
hardness: 1,
},
"ecloner": {
name: "e-cloner",
color: "#dddd00",
behavior: behaviors.WALL,
behaviorOn: behaviors.CLONER,
ignore: ["cloner","slow_cloner","clone_powder","floating_cloner"],
category:"machines",
insulate:true,
conduct: 1,
hardness: 1,
},
"slow_cloner": {
color: "#888800",
behavior: [
"XX|CF%10|XX",
"CF%10|XX|CF%10",
"XX|CF%10|XX",
],
ignore: ["cloner","ecloner","clone_powder","floating_cloner"],
category:"machines",
insulate:true,
hardness: 1,
},
"wire": {
color: "#4d0a03",
behavior: behaviors.WALL,
category: "machines",
insulate: true,
conduct: 1,
},
"random": { //hard-coded
color: ["#3e5f8a","#a334ec","#ea96f9","#a6ecf6","#70ebc8","#d9286b","#7eed91","#a18b30"],
behavior: behaviors.WALL,
category: "special",
excludeRandom: true,
},
"uncharge": {
color: "#0000ff",
tool: function(pixel) {
if (pixel.charge) {
delete pixel.charge;
pixel.chargeCD = 16;
}
},
category: "special",
excludeRandom: true,
},
"smash": {
color: ["#666666","#888888","#666666"],
tool: function(pixel) {
if (elements[pixel.element].breakInto) {
if (Math.random() < (elements[pixel.element].hardness || 1)) {
var breakInto = elements[pixel.element].breakInto;
// if breakInto is an array, pick one
if (Array.isArray(breakInto)) {
breakInto = breakInto[Math.floor(Math.random() * breakInto.length)];
}
changePixel(pixel,breakInto);
}
}
else if (Math.random() < (elements[pixel.element].hardness || 0.1)) {
deletePixel(pixel.x, pixel.y);
}
},
category: "special",
excludeRandom: true,
},
"filler": {
color: "#ae4cd9",
behavior: behaviors.FILL,
category:"special",
excludeRandom: true,
},
"lattice": {
color: "#cb4cd9",
behavior: [
"CL|XX|CL",
"XX|XX|XX",
"CL|XX|CL",
],
hidden: true,
category:"special",
excludeRandom: true,
},
"gravel": {
color: ["#E3E0DF","#B1ABA3","#74736D","#524B47"],
behavior: behaviors.POWDER,
category:"land",
tempHigh: 950,
stateHigh: "magma",
state: "solid",
density: 1680,
hardness: 0.2,
},
"slime": {
color: "#81cf63",
behavior: behaviors.LIQUID,
reactions: {
"bomb": { "elem2":"sticky_bomb", "elem2":null },
},
viscosity: 5000,
tempHigh: 120,
stateHigh: "steam",
category:"liquids",
state: "liquid",
density: 1450,
stain: 0.05,
},
"cement": {
color: "#b5b5b5",
behavior: behaviors.LIQUID,
tick: function(pixel) {
if (pixelTicks - pixel.start > 100) {
changePixel(pixel,"concrete")
}
},
category:"liquids",
tempHigh: 1550,
stateHigh: "magma",
state: "solid",
density: 1440,
hardness: 0.1,
viscosity: 1000,
},
"dust": {
color: "#666666",
behavior: behaviors.POWDER,
category: "powders",
burn: 10,
burnTime: 1,
state: "solid",
density: 1490,
},
"void": {
color: "#262626",
behavior: behaviors.DELETE,
category:"special",
hardness: 1,
},
"cell": {
color: ["#00ee00","#83ee00","#d6ee00"],
behavior: [
"XX|CL%0.5|XX",
"CL%0.5|XX|CL%0.5",
"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":"cancer", "chance":0.04 },
"alcohol": { "elem1":null, "chance":0.02 },
"poison": { "elem1":null, "chance":0.02 },
},
tempHigh: 102,
stateHigh: "steam",
tempLow: -2,
stateLow: "ice",
state: "solid",
density: 1000.1,
category: "life",
},
"cancer": {
color: ["#300b29","#5c114e","#870c71"],
behavior: [
"XX|CL%1|XX",
"CL%1|XX|CL%1",
"M2%2|M1|M2%2",
],
reactions: {
"cell": { "elem2":"cancer", "chance":0.005 },
"frog": { "elem2":"cancer", "chance":0.005 },
"fish": { "elem2":"cancer", "chance":0.005 },
"rat": { "elem2":"cancer", "chance":0.005 },
"sugar": { "elem2":"cancer", "chance":0.04 },
"sugar_water": { "elem2":"cancer", "chance":0.05 },
"alcohol": { "elem1":null, "chance":0.01 },
"poison": { "elem1":null, "chance":0.01 },
},
tempHigh: 202,
stateHigh: "plague",
state: "solid",
density: 1000.2,
category: "life",
},
"plague": {
color: "#36005c",
behavior: behaviors.GAS,
reactions: {
"frog": { "elem2":"plague", "chance":0.05 },
"ant": { "elem2":"plague", "chance":0.05 },
"bee": { "elem2":"plague", "chance":0.05 },
"fish": { "elem2":"plague", "chance":0.05 },
"firefly": { "elem2":"plague", "chance":0.05 },
},
category: "life",
state: "gas",
density: 600,
},
"flea": {
color: "#9e4732",
behavior: [
"M2|XX|M2",
"XX|XX|XX",
"M2|M1|M2",
],
reactions: {
"blood": { "elem2":null, "chance":0.1875 },
"infection": { "elem2":null, "chance":0.1875 },
"antibody": { "elem2":null, "chance":0.1875 },
},
tempHigh: 35,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
density: 400,
conduct: 0.15,
},
"termite": {
color: "#f5a056",
behavior: [
"XX|XX|SW:wood,tree_branch%5",
"XX|FX%3|M2%15 AND BO",
"XX|M1|SW:wood,tree_branch%5",
],
reactions: {
"wood": { "elem2":null, chance:0.04 },
"tree_branch": { "elem2":null, chance:0.02 },
"cellulose": { "elem2":null, chance:0.04 },
"paper": { "elem2":null, chance:0.04 },
"bamboo": { "elem2":null, chance:0.03 },
"bamboo_plant": { "elem2":null, chance:0.04 },
"sapling": { "elem2":null, chance:0.025 },
},
tempHigh: 37.78,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
conduct: 0.15,
},
"ant": {
color: "#4a0903",
behavior: [
"SW:dirt,sand,gravel%5|XX|SW:dirt,sand,gravel%5",
"M2|XX|M2",
"SW:dirt,sand,gravel%5|M1|SW:dirt,sand,gravel%5",
],
tempHigh: 53.7,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
density: 500,
conduct: 0.15,
},
"worm": {
color: "#402208",
behavior: [
"SW:dirt,sand,gravel,ash,mycelium,mud,wet_sand,clay_soil%3|XX|SW:dirt,sand,gravel,ash,mycelium,mud,wet_sand,clay_soil%3",
"M2%10|XX|M2%10",
"SW:dirt,sand,gravel,ash,mycelium,mud,wet_sand,clay_soil%3|M1|SW:dirt,sand,gravel,ash,mycelium,mud,wet_sand,clay_soil%3",
],
reactions: {
"ash": { "elem2":null, "chance":0.1 },
"root": { "elem2":"dirt", "chance":0.1 },
"hyphae": { "elem2":"mycelium", "chance":0.1 },
"plant": { "elem2":"root", "chance":0.1 },
"grass": { "elem2":"dirt", "chance":0.1 },
"limestone": { "elem2":"calcium", "chance":0.1 },
"quicklime": { "elem2":"calcium", "chance":0.1 },
"slaked_lime": { "elem2":"calcium", "chance":0.1 },
"salt": { "elem1": "slime", "elem2": null },
"potassium_salt": { "elem1": "slime", "elem2": null },
"epsom_salt": { "elem1": "slime", "elem2": null },
},
tempHigh: 40,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
conduct: 0.17,
},
"fly": {
color: "#303012",
behavior: [
"XX|M2|M1",
"XX|FX%2|BO",
"XX|M2|M1",
],
reactions: {
"plant": { "elem2":null, chance:0.5 },
"meat": { "elem2":null, chance:0.5 },
"cooked_meat": { "elem2":null, chance:0.5 },
"rotten_meat": { "elem2":null, chance:0.5 },
"vine": { "elem2":null, chance:0.5 },
"corn": { "elem2":null, chance:0.5 },
"potato": { "elem2":null, chance:0.5 },
"wheat": { "elem2":null, chance:0.5 },
"yeast": { "elem2":null, chance:0.5 },
"caramel": { "elem2":null, chance:0.5 },
"bread": { "elem2":null, chance:0.5 },
},
tempHigh: 47,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
density: 600,
conduct: 0.15,
},
"firefly": {
color: ["#310D09","#310D09","#d9d950","#310D09","#310D09"],
behavior: [
"XX|M2|M1",
"XX|CC:310D09,310D09,310D09,310D09,d9d950%10 AND FX%2|BO",
"XX|M2|M1",
],
reactions: {
"pollen": { "elem2":null, chance:0.5 },
"honey": { "elem2":null, chance:0.5 },
"firefly": { "elem2":null, chance:0.01 },
"sugar_water": { "elem2":null, chance:0.5 },
"soda": { "elem2":null, chance:0.5 },
"sugar": { "elem2":null, chance:0.25 },
},
tempHigh: 47,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
density: 600,
conduct: 0.15,
},
"bee": {
color: "#c4b100",
behavior: [
"XX|M2|M1",
"XX|FX%2|M1 AND BO",
"XX|CR:pollen%0.025 AND M2|M1",
],
reactions: {
"sugar_water": { "elem2":null, chance:0.5 },
"soda": { "elem2":null, chance:0.5 },
"sugar": { "elem2":null, chance:0.25 },
"caramel": { "elem2":null, chance:0.5 },
"candy": { "elem2":null, chance:0.05 },
},
tempHigh: 47,
stateHigh: "ash",
category:"life",
burn:95,
burnTime:25,
state: "solid",
density: 600,
conduct: 0.15,
},
"human": {
color: ["#f5eac6","#d4c594","#a89160","#7a5733","#523018","#361e0e"],
category: "life",
properties: {
dead: false,
dir: 1,
panic: 0,
},
tick: function(pixel) {
if (isEmpty(pixel.x, pixel.y+1)) {
createPixel("body", pixel.x, pixel.y+1);
pixel.element = "head";
}
else if (isEmpty(pixel.x, pixel.y-1)) {
createPixel("head", pixel.x, pixel.y-1);
pixelMap[pixel.x][pixel.y-1].color = pixel.color;
pixel.element = "body";
pixel.color = pixelColorPick(pixel)
}
else {
deletePixel(pixel.x, pixel.y);
}
},
},
"body": {
color: ["#049699","#638A61"],
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",
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 },
},
properties: {
dead: false,
dir: 1,
panic: 0,
},
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 == "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) {
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;
}
}
}
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
if (Math.random() < 0.15) {
pixel.dir *= -1;
}
}
},
},
"head": {
color: ["#f5eac6","#d4c594","#a89160","#7a6433","#524018"],
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",
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 },
},
properties: {
dead: false
},
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) {
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;
}
}
}
}
},
"rat": {
color: ["#A698A9","#8C7D82","#CCC3CF"],
behavior: [
"XX|CR:plague%0.05 AND M2%1.5|M2%5",
"XX|FX%2|M2 AND BO",
"XX|M1|M2",
],
reactions: {
"meat": { "elem2":null, "chance":0.5 },
"cooked_meat": { "elem2":null, "chance":0.5 },
"rotten_meat": { "elem2":null, "chance":0.5 },
"cheese": { "elem2":null, "chance":0.5 },
"melted_cheese": { "elem2":null, "chance":0.5 },
"plant": { "elem2":null, "chance":0.5 },
"algae": { "elem2":null, "chance":0.5 },
"grass_seed": { "elem2":null, "chance":0.5 },
"wheat_seed": { "elem2":null, "chance":0.5 },
"wheat": { "elem2":null, "chance":0.5 },
"potato_seed": { "elem2":null, "chance":0.5 },
"potato": { "elem2":null, "chance":0.5 },
"corn_seed": { "elem2":null, "chance":0.5 },
"corn": { "elem2":null, "chance":0.5 },
"flower_seed": { "elem2":null, "chance":0.5 },
"flour": { "elem2":null, "chance":0.5 },
"dough": { "elem2":null, "chance":0.5 },
"bread": { "elem2":null, "chance":0.5 },
"toast": { "elem2":null, "chance":0.5 },
"salt": { "elem2":null, "chance":0.5 },
"sugar": { "elem2":null, "chance":0.5 },
"salt_water": { "elem2":"dirty_water", "chance":0.5 },
"sugar_water": { "elem2":"dirty_water", "chance":0.5 },
"water": { "elem2":"dirty_water", "chance":0.5 },
"popcorn": { "elem2":null, "chance":0.5 },
"candy": { "elem2":null, "chance":0.5 },
"caramel": { "elem2":null, "chance":0.5 },
},
category: "life",
tempHigh: 50,
stateHigh: "rotten_meat",
tempLow: 15,
stateLow: "frozen_meat",
burn:80,
burnTime:150,
state: "solid",
conduct: 0.25,
},
"frog": {
color: "#607300",
behavior: [
"XX|XX|M2%3",
"XX|FX%0.5|CR:slime%0.01 AND BO",
"XX|M1|XX",
],
reactions: {
"fly": { "elem2":null, chance:0.5 },
"firefly": { "elem2":null, chance:0.5 },
"snail": { "elem2":"calcium", chance:0.1 },
"slug": { "elem2":null, chance:0.2 },
"worm": { "elem2":null, chance:0.2 },
"algae": { "elem2":null, chance:0.5 },
"oxygen": { "elem2":"carbon_dioxide", chance:0.5 },
},
temp: 19.1,
tempHigh: 41,
stateHigh: "meat",
tempLow: -18,
stateLow: "frozen_frog",
category:"life",
burn:75,
burnTime:30,
state: "solid",
density: 1450,
conduct: 0.2,
},
"frozen_frog": {
color: "#007349",
behavior: behaviors.STURDYPOWDER,
temp: -18,
tempHigh: 0,
stateHigh: "frog",
tempLow: -18,
stateLow: "frozen_frog",
category:"life",
hidden: true,
state: "solid",
density: 1500,
},
"fish": {
color: "#ac8650",
behavior: [
"XX|M2%5|SW:water,salt_water,sugar_water,dirty_water%7",
"XX|FX%1|BO",
"XX|M1|SW:water,salt_water,sugar_water,dirty_water%8",
],
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 },
"oxygen": { "elem2":"carbon_dioxide", chance:0.5 },
},
temp: 20,
tempHigh: 32,
stateHigh: "meat",
tempLow: -20,
stateLow: "frozen_meat",
category:"life",
burn:40,
burnTime:100,
state: "solid",
density: 1080,
conduct: 0.2,
},
"slug": {
color: ["#997e12","#403314","#997e12","#403314","#997e12","#403314","#997e12","#403314","#997e12","#403314","#997e12","#403314","#124a44"],
behavior: [
"XX|XX|XX",
"XX|FX%0.25|M2%0.5 AND BO",
"XX|M1|XX",
],
reactions: {
"salt": { "elem1": "slime", "elem2": null },
"potassium_salt": { "elem1": "slime", "elem2": null },
"epsom_salt": { "elem1": "slime", "elem2": null },
"plant": { "elem2":null, "chance":0.05 },
"worm": { "elem2":null, "chance":0.01 },
"mushroom_spore": { "elem2":null, "chance":0.05 },
"grass": { "elem2":null, "chance":0.05 },
"grass_seed": { "elem2":null, "chance":0.05 },
"algae": { "elem2":null, "chance":0.05 },
"mushroom_cap": { "elem2":null, "chance":0.05 },
"mushroom_stalk": { "elem2":null, "chance":0.05 },
"mushroom_gill": { "elem2":null, "chance":0.05 },
"hyphae": { "elem2":"dirt", "chance":0.05 },
"mycelium": { "elem2":"dirt", "chance":0.05 },
},
tempLow: 5,
stateLow: "slime",
tempHigh: 40,
stateHigh: "slime",
category: "life",
state: "solid",
density: 1450,
conduct: 0.17,
},
"snail": {
color: "#5c3104",
behavior: [
"XX|XX|XX",
"XX|FX%0.25|M2%0.5 AND BO",
"XX|M1|XX",
],
reactions: {
"salt": { "elem1": "calcium", "elem2": null },
"potassium_salt": { "elem1": "calcium", "elem2": null },
"epsom_salt": { "elem1": "calcium", "elem2": null },
"plant": { "elem2":null, "chance":0.05 },
"worm": { "elem2":null, "chance":0.01 },
"mushroom_spore": { "elem2":null, "chance":0.05 },
"grass": { "elem2":null, "chance":0.05 },
"grass_seed": { "elem2":null, "chance":0.05 },
"algae": { "elem2":null, "chance":0.05 },
"mushroom_cap": { "elem2":null, "chance":0.05 },
"mushroom_stalk": { "elem2":null, "chance":0.05 },
"mushroom_gill": { "elem2":null, "chance":0.05 },
"hyphae": { "elem2":"dirt", "chance":0.05 },
"mycelium": { "elem2":"dirt", "chance":0.05 },
},
tempLow: -6.4,
stateLow: "calcium",
tempHigh: 100,
stateHigh: "calcium",
category: "life",
state: "solid",
density: 1500,
conduct: 0.16,
},
"heater": {
color: "#881111",
behavior: [
"XX|HT:2|XX",
"HT:2|XX|HT:2",
"XX|HT:2|XX",
],
category:"machines",
insulate:true,
},
"cooler": {
color: "#111188",
behavior: [
"XX|CO:2|XX",
"CO:2|XX|CO:2",
"XX|CO:2|XX",
],
category:"machines",
insulate:true,
},
"superheater": {
color: "#dd1111",
behavior: [
"XX|HT:10|XX",
"HT:10|XX|HT:10",
"XX|HT:10|XX",
],
category:"machines",
insulate:true,
},
"freezer": {
color: "#1111dd",
behavior: [
"XX|CO:10|XX",
"CO:10|XX|CO:10",
"XX|CO:10|XX",
],
category:"machines",
insulate:true,
},
"torch": {
color: "#d68542",
behavior: [
"XX|CR: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" },
"steam": { "elem1":"wood" },
"smog": { "elem1":"wood" },
"rain_cloud": { "elem1":"wood" },
},
temp:600,
category:"special",
},
"spout": {
color: "#606378",
behavior: [
"XX|CR:water|XX",
"CR:water|XX|CR:water",
"XX|CR:water|XX",
],
category:"special",
tempHigh: 1455.5,
stateHigh: "molten_steel",
conduct: 0.42,
},
"udder": {
color: "#ecb3f5",
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"XX|CR:milk%2.5|XX",
],
tempHigh: 80,
stateHigh: "cooked_meat",
tempLow: -18,
stateLow: "frozen_meat",
category:"special",
},
"bone_marrow": {
color: "#c97265",
behavior: [
"XX|CR:blood,bone,bone%5|XX",
"CR:blood,bone,bone%5|XX|CR:blood,bone,bone%5",
"XX|CR:blood,bone,bone%5|XX",
],
category:"life",
tempHigh: 750,
stateHigh: "calcium",
hidden: true,
},
"bone": {
color: "#d9d9d9",
behavior: behaviors.SUPPORT,
category:"life",
tempHigh: 760,
stateHigh: "calcium",
state: "solid",
density: 1900,
hardness: 0.5,
breakInto: "calcium",
},
"antipowder": {
color: "#ebd1d8",
behavior: behaviors.AGPOWDER,
category:"special",
tempHigh: 1850,
stateHigh: "antimolten",
state: "solid",
density: 1850,
},
"antimolten": {
color: ["#ffb5b5","#ffd0b5","#ffd0b5"],
behavior: [
"M1|M1|M1",
"M2|XX|M2",
"XX|CR:antifire%2.5|XX",
],
temp: 1850,
tempLow: 1750,
stateLow: "antipowder",
viscosity: 10000,
hidden: true,
state: "liquid",
density: 1000,
category: "special",
},
"antifire": {
color: ["#ffc3a6","#ffdfa3","#ffb69e"],
behavior: [
"XX|M2|XX",
"M2|XX|M2",
"M1|M1|M1",
],
reactions: {
"antiliquid": { "elem1": "antigas" },
},
temp:600,
tempLow:100,
stateLow: "antigas",
tempHigh: 7000,
stateHigh: "plasma",
category: "special",
burning: true,
burnTime: 25,
burnInto: "antigas",
hidden: true,
state: "gas",
density: 0.2,
},
"antifluid": {
color: "#d1dbeb",
behavior: behaviors.AGLIQUID,
category:"special",
tempHigh: 100,
stateHigh: "antigas",
state: "liquid",
density: 1000,
},
"antigas": {
color: "#e6fffc",
behavior: behaviors.GAS,
category:"special",
tempLow: 100,
stateLow: "antifluid",
hidden: true,
state: "gas",
density: 0.1,
},
"vertical": {
color: "#d9d9d9",
behavior: [
"XX|M1|XX",
"CR:wall|XX|CR:wall",
"XX|XX|XX",
],
category:"special",
hidden:true,
excludeRandom: true,
},
"horizontal": {
color: "#d9d9d9",
behavior: [
"XX|CR:wall|XX",
"XX|XX|M1",
"XX|CR:wall|XX",
],
category:"special",
hidden:true,
excludeRandom: true,
},
"rocket": {
color: "#ff0000",
behavior: [
"XX|M1|XX",
"XX|DL%1|XX",
"CR:smoke|CR:fire|CR:smoke",
],
category: "special",
hidden:true,
state: "solid",
temp:700,
density: 7300,
conduct: 0.73,
tempHigh: 1455.5,
stateHigh: "molten_steel",
},
"ash": {
color: ["#8c8c8c","#9c9c9c"],
behavior: behaviors.POWDER,
reactions: {
"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] },
"hail_cloud": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,15] },
"acid_cloud": { "elem1": "pyrocumulus", "chance":0.05, "y":[0,15] },
"pyrocumulus": { "elem1": "pyrocumulus", "chance":0.08, "y":[0,15] },
},
category:"powders",
state: "solid",
density: 700,
},
"light": {
color: "#ffffa8",
behavior: [
"XX|XX|XX",
"XX|DL%5|M1 AND BO",
"XX|XX|XX",
],
rotatable: true,
temp: 40,
category: "energy",
},
"laser": {
color: "#ff0000",
behavior: [
"XX|XX|XX",
"XX|DL%0.25|M1 AND BO:1,2,3",
"XX|XX|XX",
],
rotatable: true,
temp: 40,
category: "energy",
},
"ball": {
color: "#e35693",
behavior: [
"XX|XX|XX",
"XX|FY:0%5|XX",
"XX|M1 AND BO|XX",
],
category: "energy",
flipY: false,
flippableY: true,
hidden: true,
},
"pointer": {
color: "#ff0000",
behavior: behaviors.SELFDELETE,
category:"special",
hidden:true,
},
"charcoal": {
color: "#2b2b2b",
behavior: behaviors.POWDER,
burn: 25,
burnTime: 1000,
burnInto: "carbon_dioxide",
category: "powders",
state: "solid",
density: 208,
breakInto: ["ash","ash","carbon_dioxide"],
},
"tinder": {
color: ["#917256","#87684F","#735F4A","#5D4C3E","#4B3A2E"],
behavior: behaviors.STURDYPOWDER,
category: "powders",
tempHigh: 400,
stateHigh: "fire",
burn: 50,
burnTime: 100,
state: "solid",
density: 23,
},
"sawdust": {
color: ["#dec150","#c7b15a"],
behavior: behaviors.POWDER,
tempHigh: 400,
stateHigh: "fire",
category: "powders",
burn: 25,
burnTime: 150,
burnInto: ["ash","fire","fire","fire"],
state: "solid",
density: 393,
},
"hail": {
color: "#c5e9f0",
tick: function(pixel) {
for (var i=0; i<3; i++) {
if (!tryMove(pixel, pixel.x, pixel.y+1)) {
if (!isEmpty(pixel.x, pixel.y+1,true)) {
var newPixel = pixelMap[pixel.x][pixel.y+1];
if (newPixel.element === "hail") { break; }
if (elements[newPixel.element].state == "solid") {
if (Math.random() > (elements[newPixel.element].hardness || 0)) {
if (elements[newPixel.element].breakInto) {
var breakInto = elements[newPixel.element].breakInto;
// if it is an array, pick a random element
if (Array.isArray(breakInto)) {
breakInto = breakInto[Math.floor(Math.random()*breakInto.length)];
}
changePixel(newPixel,breakInto);
}
else {
deletePixel(newPixel.x, newPixel.y);
}
}
}
}
deletePixel(pixel.x,pixel.y);
break;
}}},
temp: -10,
tempHigh: 10,
stateHigh: "water",
category: "powders",
state: "solid",
density: 850,
},
"hydrogen": {
color: "#558bcf",
behavior: behaviors.GAS,
reactions: {
"oxygen": { "elem1":null, "elem2":"steam" },
},
category: "gases",
burn: 100,
burnTime: 2,
tempLow: -252.8,
stateLow: "liquid_hydrogen",
state: "gas",
density: 0.08375,
},
"oxygen": {
color: "#99c7ff",
behavior: behaviors.GAS,
reactions: {
"copper": { "elem2":"oxidized_copper", chance:0.05 },
"iron": { "elem2":"rust", chance:0.025 },
"water": { "elem1":"foam" },
"salt_water": { "elem1":"foam" },
"sugar_water": { "elem1":"foam" },
"seltzer": { "elem1":"foam" },
"soda": { "elem1":"foam" },
"dirty_water": { "elem1":"foam" },
},
category: "gases",
burn: 100,
burnTime: 2,
tempLow: -183.94,
stateLow: "liquid_oxygen",
state: "gas",
density: 1.292,
},
"nitrogen": {
color: "#b8d1d4",
behavior: behaviors.GAS,
reactions: {
"oxygen": { "elem1":null, "elem2":"anesthesia" },
"hydrogen": { "elem1":null, "elem2":"ammonia" },
},
category: "gases",
tempLow: -195.8,
stateLow: "liquid_nitrogen",
state: "gas",
density: 1.165,
},
"helium": {
color: "#a69494",
behavior: behaviors.GAS,
category: "gases",
tempLow: -272.20,
stateLow: "liquid_helium",
state: "gas",
density: 0.1786,
},
"anesthesia": {
color: "#d3e1e3",
behavior: behaviors.GAS,
category: "gases",
tempLow: -88.48,
stateLow: ["nitrogen","oxygen"],
hidden: true,
state: "liquid",
density: 1.9781,
},
"ammonia": {
color: "#bab6a9",
behavior: behaviors.GAS,
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" },
},
tempLow: -150,
stateLow: ["nitrogen","hydrogen"],
category: "gases",
state: "gas",
density: 0.73,
},
"carbon_dioxide": {
color: "#2f2f2f",
behavior: behaviors.GAS,
reactions: {
"plant": { "elem1":"oxygen" },
"algae": { "elem1":"oxygen" },
},
category: "gases",
tempLow: -78.5,
stateLow: "dry_ice",
state: "gas",
density: 1.977,
},
"oil": {
color: "#470e00",
behavior: behaviors.LIQUID,
reactions: {
"dirt": { "elem2":"mud" },
"sand": { "elem2":"wet_sand" },
},
category: "liquids",
tempHigh: 400,
stateHigh: "fire",
burn: 100,
burnTime: 30,
burnInto: ["carbon_dioxide","fire"],
viscosity: 250,
state: "liquid",
density: 825,
stain: 0.05,
},
"lamp_oil": {
color: "#b3b38b",
behavior: behaviors.LIQUID,
category: "liquids",
tempHigh: 2100,
stateHigh: "fire",
burn: 95,
burnTime: 2000,
burnInto: ["carbon_dioxide","fire"],
viscosity: 3,
state: "liquid",
density: 850,
},
"propane": {
color: "#cfcfcf",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 400,
stateHigh: "fire",
burn: 100,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 2.0098,
},
"methane": {
color: "#9f9f9f",
behavior: behaviors.GAS,
category: "gases",
tempHigh: 400,
stateHigh: "fire",
burn: 85,
burnTime: 5,
fireColor: ["#00ffff","#00ffdd"],
state: "gas",
density: 0.554,
},
"color_sand": {
color: ["#ff4d4d","#ffac4d","#ffff4d","#4dff4d","#4dffff","#4d4dff","#ff4dff"],
behavior: behaviors.POWDER,
tick: function(pixel) {
if (pixel.start === pixelTicks) {
pixel.color = "hsl(" + pixel.start + ",100%,65%)";
pixel.colorstart = pixel.start;
}
},
tempHigh: 1700,
stateHigh: "molten_stained_glass",
category: "powders",
state: "solid",
density: 1602,
},
"stained_glass": {
color: ["#6b2e2e","#6b4f2e","#6b6b2e","#2e6b2e","#2e6b6b","#2e2e6b","#6b2e6b"],
behavior: behaviors.WALL,
tick: function(pixel) {
if (pixel.start-1 < pixelTicks) {
pixel.color = "hsl(" + (pixel.colorstart || pixel.start) + ",40%,30%)";
if (!pixel.colorstart) {
pixel.colorstart = pixel.start;
}
}
},
tempHigh: 1500,
category: "solids",
state: "solid",
density: 2500,
breakInto: "color_sand",
},
"molten_stained_glass": {
color: ["#c27070","#c29c70","#c2c270","#70c270","#70c2c2","#7070c2","#c270c2"],
tick: function(pixel) {
if (pixel.start-1 < pixelTicks) {
pixel.color = "hsl(" + (pixel.colorstart || pixel.start) + ",40%,60%)";
if (!pixel.colorstart) {
pixel.colorstart = pixel.start;
}
}
}
},
"art": {
color: "#ffffff",
behavior: behaviors.WALL,
customColor: true,
category: "special"
},
"rainbow": {
color: ["#ff0000","#ff8800","#ffff00","#00ff00","#00ffff","#0000ff","#ff00ff"],
tick: function(pixel) {
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)));
pixel.color = "rgb("+r+","+g+","+b+")";
},
category: "special",
},
"static": {
color: ["#ffffff","#888888","#000000"],
behavior: [
"XX|XX|XX",
"XX|CC:ffffff,9c9c9c,454545|XX",
"XX|XX|XX",
],
category: "special",
},
"border": {
color: "#00ffff",
tick: function(pixel) {
var t = pixelTicks/2+pixel.x+pixel.y;
var r = Math.floor(127*Math.sin(t/1.5));
pixel.color = "rgba("+r+","+r*2+","+r*2+","+r/127+")";
},
category: "special",
hardness: 1,
insulate: true,
},
"clay": {
color: "#d4c59c",
behavior: behaviors.SUPPORT,
tempHigh: 135,
stateHigh: "baked_clay",
category: "land",
state: "solid",
density: 1760,
},
"clay_soil": {
color: ["#F49A6F","#AB7160","#B56C52"],
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"M2%25|M1|M2%25",
],
reactions: {
"water": { "elem1":"clay", "elem2":null },
},
tempHigh: 140,
stateHigh: "baked_clay",
category: "land",
state: "solid",
density: 1600,
},
"baked_clay": {
color: "#b85746",
behavior: behaviors.SUPPORT,
category: "powders",
state: "solid",
density: 2000,
},
"brick": {
color: "#cb4141",
behavior: behaviors.WALL,
category: "solids",
tempHigh: 1540,
state: "solid",
density: 1650,
hardness: 0.33,
breakInto: "brick_rubble",
},
"brick_rubble": {
color: ["#cb4141","#ab4d4d","#872626"],
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 1540,
stateHigh: "molten_brick",
state: "solid",
density: 1650,
hardness: 0.25,
breakInto: "dust",
hidden: true,
},
"ruins": {
color: "#5c5c5c",
behavior: [
"XX|SP|XX",
"XX|XX|XX",
"M2%1|M1|M2%1"
],
tempHigh: 1500,
stateHigh: "magma",
category:"solids",
state: "solid",
density: 2400,
hardness: 0.33,
breakInto: "dust",
},
"sapling": {
color: "#3e9c3e",
behavior: [
"XX|M2%2|XX",
"XX|L2:wood,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,
},
"seeds": {
color: ["#359100","#74b332","#b9d461","#dede7a"],
tick: function(pixel) {
// Choose randomly grass_seed, wheat_seed, flower_seed, bamboo_plant, mushroom_spore, corn_seed, potato_seed
pixel.element = ["grass_seed","wheat_seed","flower_seed","bamboo_plant","mushroom_spore","corn_seed","potato_seed"][Math.floor(Math.random()*7)];
pixel.color = pixelColorPick(pixel);
},
category: "life",
},
"grass_seed": {
color: ["#439809","#258B08","#118511","#127B12","#136D14"],
behavior: [
"XX|M2%0.05|XX",
"XX|L2:grass|XX",
"XX|M1|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 50,
burnTime: 20,
category: "life",
state: "solid",
density: 1400,
},
"wheat_seed": {
color: "#b6c981",
behavior: [
"XX|M2%0.25|XX",
"XX|L2:wheat AND C2:wheat%30|XX",
"XX|M1|XX",
],
tempHigh: 400,
stateHigh: "fire",
burn: 50,
burnTime: 20,
category: "life",
state: "solid",
density: 769,
},
"wheat": {
color: "#c9bc81",
behavior: behaviors.WALL,
reactions: {
"rock": { "elem1":"flour", "elem2":"rock" }
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn:40,
burnTime:25,
category:"life",
hidden:true,
state: "solid",
density: 769,
},
"straw": {
color: ["#E9D391","#A3835E","#B79A73"],
behavior: behaviors.WALL,
tempHigh: 400,
stateHigh: "fire",
burn: 60,
burnTime: 40,
category: "solids",
state: "solid",
density: 67.5,
},
"pollen": {
color: "#ffffc0",
behavior: [
"XX|XX|XX",
"XX|CH:flower_seed%0.01|XX",
"M2|M1|M2",
],
reactions: {
"sugar_water": { "elem1": null, "elem2": "honey" },
},
category:"life",
tempHigh: 400,
stateHigh: "ash",
burn:50,
burnTime:20,
state: "solid",
density: 1435,
},
"flower_seed": {
color: "#0e990e",
behavior: [
"XX|M2%1.5|XX",
"XX|L2:grass AND C2:pistil%30|XX",
"XX|M1|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn:50,
burnTime:20,
category:"life",
state: "solid",
density: 1400,
},
"pistil": {
color: "#734e39",
behavior: [
"XX|CR:petal%10|XX",
"CR:petal%10|XX|CR:petal%10",
"XX|XX|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn:50,
burnTime:20,
category:"life",
hidden: true,
state: "solid",
density: 1400,
},
"petal": {
color: "#ff0000",
behavior: behaviors.WALL,
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn:50,
burnTime:20,
category:"life",
hidden: true,
state: "solid",
density: 1400,
},
"tree_branch": {
color: "#a0522d",
behavior: [
"CR:plant,tree_branch%2|CR:plant,plant,plant,tree_branch%2|CR:plant,tree_branch%2",
"XX|XX|XX",
"XX|XX|XX",
],
tempHigh: 400,
stateHigh: "fire",
tempLow: -30,
stateLow: "wood",
category: "solids",
burn: 40,
burnTime: 50,
burnInto: ["ember","charcoal","fire"],
hidden: true,
state: "solid",
density: 1500,
hardness: 0.15,
breakInto: "sawdust",
},
"vine": {
color: "#005900",
behavior: [
"XX|SP|XX",
"XX|XX|XX",
"XX|CL%1 AND M1|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 35,
burnTime: 100,
category: "life",
state: "solid",
density: 1050,
},
"bamboo": {
color: ["#7CC00C","#77A012"],
behavior: behaviors.WALL,
tempHigh: 380,
stateHigh: "fire",
burn: 10,
burnTime: 200,
category: "life",
state: "solid",
density: 686,
breakInto: "sawdust",
},
"bamboo_plant": {
color: ["#FBC882","#DFAD64"],
behavior: [
"XX|M2%0.25|XX",
"XX|L2:bamboo AND C2:bamboo%10|XX",
"XX|M1|XX",
],
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "bamboo",
burn: 30,
burnTime: 100,
category: "life",
state: "solid",
density: 686,
breakInto: "sawdust",
},
"burner": {
color: "#d6baa9",
behavior: [
"CR:propane|CR:propane|CR:propane",
"XX|XX|XX",
"XX|XX|XX",
],
category: "machines",
conduct: 0.73,
},
"foam": {
color: "#cad2e3",
behavior: behaviors.FOAM,
category: "liquids",
state: "gas",
density: 40,
},
"bubble": {
color: "#afc7fa",
behavior: behaviors.BUBBLE,
category: "liquids",
state: "gas",
density: 1.294,
},
"acid": {
color: ["#b5cf91","#a1ff5e","#288f2a"],
behavior: [
"XX|DB%5|XX",
"DB%5 AND M2|XX|DB%5 AND M2",
"DB%5 AND M2|DB%10 AND M1|DB%5 AND M2",
],
ignore: ["glass","glass_shard","stained_glass","baked_clay","acid_gas","neutral_acid","acid_cloud"],
reactions: {
"ash": { "elem1":"neutral_acid", "elem2":null },
"limestone": { "elem1":"neutral_acid", "elem2":null },
"quicklime": { "elem1":"neutral_acid", "elem2":null },
"slaked_lime": { "elem1":"neutral_acid", "elem2":null },
"borax": { "elem1":"neutral_acid", "elem2":null },
"ammonia": { "elem1":"neutral_acid", "elem2":null },
},
category: "liquids",
tempHigh: 400,
stateHigh: "fire",
burn: 30,
burnTime: 1,
state: "liquid",
density: 1049,
},
"neutral_acid": {
color: ["#c8d9b0","#c1d9b0","#b8dbb9"],
behavior: behaviors.LIQUID,
category: "liquids",
state: "liquid",
density: 1020,
hidden: true,
},
"acid_gas": {
color: ["#85a758","#3b7810","#256626"],
behavior: [
"M1|DB%5 AND M1|M1",
"DB%5 AND M1|XX|DB%5 AND M1",
"DB%5 AND M1|DB%10 AND M1|DB%5 AND M1",
],
ignore: ["glass","glass_shard","stained_glass","baked_clay","acid","neutral_acid","acid_cloud"],
reactions: {
"acid_gas": { "elem1": null, "elem2": "acid_cloud", "chance":0.3, "y":[0,15] },
"rain_cloud": { "elem1": null, "elem2": "acid_cloud", "chance":0.4, "y":[0,15] },
"snow_cloud": { "elem1": null, "elem2": "acid_cloud", "chance":0.4, "y":[0,15] },
"hail_cloud": { "elem1": null, "elem2": "acid_cloud", "chance":0.4, "y":[0,15] },
"pyrocumulus": { "elem1": null, "elem2": "acid_cloud", "chance":0.4, "y":[0,15] },
"fire_cloud": { "elem1": null, "elem2": "acid_cloud", "chance":0.4, "y":[0,15] },
"ash": { "elem1":"hydrogen", "elem2":null, "chance":0.05 },
"limestone": { "elem1":"hydrogen", "elem2":null, "chance":0.05 },
"quicklime": { "elem1":"hydrogen", "elem2":null, "chance":0.05 },
"slaked_lime": { "elem1":"hydrogen", "elem2":null, "chance":0.05 },
"borax": { "elem1":"hydrogen", "elem2":null, "chance":0.05 },
"ammonia": { "elem1":"hydrogen", "elem2":null, "chance":0.05 },
},
category: "gases",
tempHigh: 400,
stateHigh: "fire",
tempLow: -10,
stateLow: "acid",
burn: 30,
burnTime: 1,
state: "gas",
density: 1.63,
},
"glue": {
color: "#f0f0f0",
behavior: behaviors.STICKY,
tempHigh: 475,
stateHigh: ["cyanide","dioxin"],
category: "liquids",
state: "liquid",
density: 1300,
},
"soda": {
color: "#422016",
behavior: [
"XX|CR:foam%2|XX",
"M2|XX|M2",
"M2|M1|M2",
],
tempHigh: 100,
stateHigh: ["steam","carbon_dioxide","sugar"],
tempLow: -1.11,
stateLow: "ice",
viscosity: 1,
category: "liquids",
reactions: {
"dirt": { "elem1": null, "elem2": "mud" },
"sand": { "elem1": null, "elem2": "wet_sand", },
"rock": { "elem2": "wet_sand", "chance": 0.0004 },
"water": { "elem1": "sugar_water", "elem2": "sugar_water" },
},
state: "liquid",
density: 1030,
},
"gray_goo": {
color: "#c0c0c0",
behavior: [
"XX|CH:gray_goo|XX",
"M2%5 AND CH:gray_goo|DL%5|M2%5 AND CH:gray_goo",
"XX|CH:gray_goo AND M1|XX",
],
behaviorOn: [
"XX|XX|XX",
"XX|DL%5|XX",
"M1|M2|M1",
],
ignore: ["fire","smoke"],
category: "special",
state: "solid",
density: 21450,
excludeRandom: true,
conduct: 0.25,
},
"clone_powder": {
color: "#f0f000",
behavior: [
"XX|CF|XX",
"CF|XX|CF",
"M2|CF AND M1|M2",
],
ignore: ["cloner","ecloner","slow_cloner","floating_cloner"],
category:"machines",
insulate:true,
state:"solid",
density:2710,
hardness: 1,
},
"floating_cloner": {
color: "#c7c787",
behavior: [
"XX|CF%3 AND M1%10|XX",
"CF%3 AND M1%10|XX|CF%3 AND M1%10",
"XX|CF%3 AND M1%10|XX",
],
ignore: ["cloner","ecloner","slow_cloner","clone_powder"],
category:"machines",
insulate:true,
state:"solid",
density:1355,
hardness: 1,
},
"virus": {
color: "#cc00ff",
behavior: [
"XX|CH:virus%25|XX",
"CH:virus%25|XX|CH:virus%25",
"XX|CH:virus%25 AND M1|XX",
],
ignore: ["fire","smoke","soap","plague","cancer"],
category: "special",
state: "solid",
density: 600,
excludeRandom: true,
},
"permafrost": {
color: ["#557d65","#557d79"],
behavior: behaviors.SUPPORT,
temp: -50,
tempHigh: 0,
stateHigh: "mud",
category: "land",
state: "solid",
density: 700,
},
"cheese": {
color: "#fcba03",
behavior: behaviors.STURDYPOWDER,
tempHigh: 54,
stateHigh: "melted_cheese",
category: "food",
state: "solid",
density: 1153,
},
"melted_cheese": {
color: "#fcdb53",
behavior: behaviors.LIQUID,
tempLow: 0,
stateLow: "cheese",
category: "liquids",
viscosity: 112,
hidden: true,
state: "liquid",
density: 1153,
},
"mushroom_spore": {
color: ["#d1d1d1","#d4cfa9","#b4d4ae","#b98aba","#805236"],
behavior: [
"XX|M2%1.5|XX",
"XX|L2:mushroom_stalk AND C2:mushroom_gill%20|XX",
"XX|M1|XX",
],
reactions: {
"wood": { "elem2":"dirt", "chance":0.04 },
"tree_brake": { "elem2":"dirt", "chance":0.04 },
"plant": { "elem2":"dirt", "chance":0.07 },
"root": { "elem2":"dirt", "chance":0.07 },
"grass": { "elem2":"dirt", "chance":0.08 },
"grass_seed": { "elem2":"dirt", "chance":0.08 },
},
category: "life",
tempHigh: 225,
stateHigh: "fire",
burn: 10,
burnTime: 20,
state: "solid",
density: 123.6,
},
"mushroom_stalk": {
color: "#d1d1d1",
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"XX|CH:dirt>hyphae%1 AND M1|XX",
],
reactions: {
"wood": { "elem2":"dirt", "chance":0.04 },
"tree_brake": { "elem2":"dirt", "chance":0.04 },
"plant": { "elem2":"dirt", "chance":0.07 },
"root": { "elem2":"dirt", "chance":0.07 },
"grass": { "elem2":"dirt", "chance":0.08 },
"grass_seed": { "elem2":"dirt", "chance":0.08 },
"ash": { "elem2":"dirt", "chance":0.04 },
},
category: "life",
hidden: true,
tempHigh: 225,
stateHigh: "fire",
burn: 10,
burnTime: 65,
state: "solid",
density: 90.445,
},
"mushroom_gill": {
color: "#d4cfa9",
behavior: [
"XX|CR:mushroom_cap%10|XX",
"CR:mushroom_gill,mushroom_cap%2|XX|CR:mushroom_gill,mushroom_cap%2",
"XX|XX|XX",
],
category: "life",
hidden: true,
tempHigh: 225,
stateHigh: "fire",
burn: 10,
burnTime: 65,
burnInto: "mushroom_spore",
state: "solid",
density: 90.445,
},
"mushroom_cap": {
color: ["#c74442","#c74442","#c74442","#c74442","#c74442","#c74442","#cfb4b4"],
behavior: behaviors.WALL,
category: "life",
hidden: true,
tempHigh: 225,
stateHigh: "fire",
burn: 10,
burnTime: 65,
burnInto: "mushroom_spore",
state: "solid",
density: 90.445,
},
"hyphae": {
color: "#c79789",
behavior: [
"CH:dirt>hyphae,hyphae,mycelium%0.5|CR:mushroom_spore%0.5|CH:dirt>hyphae,hyphae,mycelium%0.5",
"CH:mycelium%0.5|XX|CH:mycelium%0.5",
"CH:dirt>hyphae,hyphae,mycelium%0.5|XX|CH:dirt>hyphae,hyphae,mycelium%0.5",
],
reactions: {
"wood": { "elem2":"dirt", "chance":0.04 },
"tree_brake": { "elem2":"dirt", "chance":0.04 },
"plant": { "elem2":"dirt", "chance":0.07 },
"root": { "elem2":"dirt", "chance":0.07 },
"grass": { "elem2":"dirt", "chance":0.08 },
"grass_seed": { "elem2":"dirt", "chance":0.08 },
"ash": { "elem2":"dirt", "chance":0.04 },
},
category: "life",
hidden: true,
tempHigh: 225,
stateHigh: "fire",
burn: 30,
burnTime: 20,
state: "solid",
density: 462,
},
"mycelium": {
color: ["#734d5e","#b5949f","#734d53"],
behavior: behaviors.POWDER,
tempHigh:225,
stateHigh: "dirt",
tempLow: -50,
stateLow: "permafrost",
burn: 20,
burnTime: 40,
burnInto: "dirt",
category:"land",
state: "solid",
density: 462,
},
"lichen": {
color: ["#b6d6c3","#769482"],
behavior: [
"XX|ST:wood AND M2%0.1|XX",
"ST:wood AND M2%0.1|L2:lichen|ST:wood AND M2%0.1",
"XX|M1 AND M2%0.1|XX",
],
tempHigh: 400,
stateHigh: "fire",
burn: 50,
burnTime: 20,
category: "life",
state: "solid",
density: 1.5,
},
"antimatter": {
color: "#a89ba8",
behavior: [
"M2|DB%50 AND M2 AND EX:5|M2",
"M1|XX|M1",
"M1|DB%50 AND M1 AND EX:5|M1",
],
ignore: ["antimatter_bomb"],
category: "special",
state: "gas",
density: 0.1,
},
"plastic": {
color: "#c5dede",
behavior: behaviors.WALL,
tempHigh: 250,
burn: 10,
burnTime: 200,
burnInto: "dioxin",
category: "solids",
state: "solid",
density: 1052,
},
"molten_plastic": {
color: "#a4b3b3",
behavior: behaviors.LIQUID,
viscosity: 20,
},
"paper": {
color: "#f0f0f0",
behavior: behaviors.STURDYPOWDER,
reactions: {
"water": { "elem1":"cellulose", "elem2":null },
"dirty_water": { "elem1":"cellulose", "elem2":null },
"salt_water": { "elem1":"cellulose", "elem2":null },
"sugar_water": { "elem1":"cellulose", "elem2":null },
"seltzer": { "elem1":"cellulose", "elem2":null },
"soda": { "elem1":"cellulose", "elem2":null },
"blood": { "elem1":"cellulose", "elem2":null },
"foam": { "elem1":"cellulose", "elem2":null },
"bubble": { "elem1":"cellulose", "elem2":null },
"oil": { "elem1":"cellulose", "elem2":null },
"alcohol": { "elem1":"cellulose", "elem2":null },
"vinegar": { "elem1":"cellulose", "elem2":null },
},
tempHigh: 248,
stateHigh: "fire",
burn: 70,
burnTime: 300,
category: "powders",
state: "solid",
density: 1201,
},
"cellulose": {
color: "#c7d4c9",
behavior: behaviors.LIQUID,
tempHigh: 124,
stateHigh: "steam",
burn: 35,
burnTime: 300,
category: "life",
state: "solid",
density: 65,
viscosity: 2500,
},
"wax": {
color: "#fff3d6",
behavior: behaviors.STURDYPOWDER,
tempHigh: 57,
stateHigh: "melted_wax",
category: "powders",
state: "solid",
density: 900,
},
"melted_wax": {
color: "#d4c196",
behavior: behaviors.LIQUID,
tempLow: 57,
stateLow: "wax",
category: "liquids",
viscosity: 112,
hidden: true,
state: "liquid",
density: 900,
viscosity: 1.355,
},
"fuse": {
color: "#825d38",
behavior: behaviors.WALL,
tempHigh: 500,
stateHigh: "fire",
burn: 100,
burnTime: 1,
category: "solids",
state: "solid",
density: 1000,
},
"dioxin": {
color: "#b8b8b8",
behavior: behaviors.GAS,
reactions: {
"cell": { "elem2":"cancer", "chance":0.0015 },
"blood": { "elem2":"infection", "chance":0.01 },
"antibody": { "elem2":"blood", "chance":0.025 },
"frog": { "elem2":"meat", "chance":0.05 },
"fish": { "elem2":"meat", "chance":0.05 },
"rat": { "elem2":"rotten_meat", "chance":0.05 },
},
category: "gases",
state: "gas",
density: 1830,
},
"insulation": {
color: "#b8aea5",
behavior: behaviors.WALL,
category: "solids",
insulate: true,
state: "solid",
},
"sponge": {
color: ["#bf9c00","#ad8e05","#876f05"],
properties: {
"damp":0
},
tick: function(pixel) {
var coordsToCheck = [
[pixel.x-1,pixel.y],
[pixel.x+1,pixel.y],
[pixel.x,pixel.y-1],
[pixel.x,pixel.y+1],
];
for (var i = 0; i < coordsToCheck.length; i++) {
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)) {
deletePixel(coord[0],coord[1]);
}
}
}
},
category: "solids",
state: "solid",
},
"iron": {
color: ["#cbcdcd","#bdbdbd"],
behavior: behaviors.WALL,
reactions: {
"water": { "elem1":"rust", chance:0.0025 },
"salt_water": { "elem1":"rust", chance:0.005 },
"dirty_water": { "elem1":"rust", chance:0.04 },
"sugar_water": { "elem1":"rust", chance:0.0035 },
"seltzer": { "elem1":"rust", chance:0.006 },
},
tempHigh: 1538,
category: "solids",
density: 7860,
conduct: 0.47,
},
"rust": {
color: ["#AE551C","#BC6E39","#925F49"],
behavior: behaviors.SUPPORT,
tempHigh: 1538,
stateHigh: "molten_iron",
category: "solids",
state: "solid",
density: 5250,
conduct: 0.37,
},
"copper": {
color: ["#A95232","#BE4322","#C76035"],
behavior: [
"XX|XX|XX",
"XX|CH:oxidized_copper%0.001|XX",
"XX|XX|XX",
],
reactions: {
"water": { "elem1":"oxidized_copper", chance:0.0025 },
"salt_water": { "elem1":"oxidized_copper", chance:0.005 },
"dirty_water": { "elem1":"oxidized_copper", chance:0.04 },
"sugar_water": { "elem1":"oxidized_copper", chance:0.0035 },
"seltzer": { "elem1":"oxidized_copper", chance:0.006 },
},
category: "solids",
tempHigh: 1085,
density: 8960,
conduct: 0.95,
},
"oxidized_copper": {
color: ["#406555","#42564A","#517364"],
behavior: [
"XX|XX|XX",
"XX|XX|XX",
"XX|XX|XX",
],
category: "solids",
hidden: true,
tempHigh: 1085,
stateHigh: "molten_copper",
density: 8960,
conduct: 0.85,
},
"zinc": {
color: ["#7C7A7B","#9D9D9F","#F8F8F3"],
behavior: behaviors.WALL,
tempHigh: 419.53,
category: "solids",
density: 7068,
conduct: 0.53,
},
"tin": {
color: ["#9E9D98","#AEADA4"],
behavior: behaviors.WALL,
tempHigh: 231.9,
category: "solids",
density: 7260,
conduct: 0.45,
},
"nickel": {
color: "#727472",
behavior: behaviors.WALL,
tempHigh: 1455,
category: "solids",
density: 8900,
conduct: 0.51,
},
"silver": {
color: "#CACACA",
behavior: behaviors.WALL,
tempHigh: 961.8,
category: "solids",
density: 10497,
conduct: 0.99,
},
"gold": {
color: ["#FFF0B5","#986A1A","#F0BB62"],
behavior: behaviors.WALL,
tempHigh: 1064,
category: "solids",
density: 19300,
conduct: 0.81,
},
"gold_coin": {
color: ["#FFF0B5","#986A1A","#F0BB62"],
behavior: behaviors.POWDER,
tempHigh: 1064,
stateHigh: "molten_gold",
category: "powders",
state: "solid",
density: 19300,
conduct: 0.78,
},
"aluminum": {
color: ["#D1C6BE","#B5C0AD","#B9B8BC"],
behavior: behaviors.WALL,
tempHigh: 660.3,
category: "solids",
density: 2710,
conduct: 0.73,
},
"lead": {
color: "#6c6c6a",
behavior: behaviors.WALL,
tempHigh: 327.5,
category: "solids",
density: 11343,
conduct: 0.41,
},
"tungsten": {
color: ["#D4D3CD","#C3C0B8","#BCBAAE","#625950"],
behavior: behaviors.WALL,
tempHigh: 3422,
category: "solids",
density: 19300,
conduct: 0.65,
},
"molten_tungsten": {
color: ['#ffff67', '#ffd367', '#ff9e00', '#d1ff5c', '#5cffb0', '#0073ff', '#ca57ff', '#ffba57', '#ff8c00', '#c46f28', '#c45928', '#c44300']
},
"brass": {
color: ["#cb9e5d","#865e39"],
behavior: behaviors.WALL,
tempHigh: 927,
category: "solids",
density: 8550,
conduct: 0.52,
},
"bronze": {
color: "#cd7f32",
behavior: behaviors.WALL,
tempHigh: 913,
category: "solids",
density: 8150,
conduct: 0.44,
},
"sterling": {
color: ["#858478","#eae8e2","#bfbcb7"],
behavior: behaviors.WALL,
tempHigh: 802,
category: "solids",
density: 10375.25,
conduct: 0.95,
},
"steel": {
color: "#71797E",
behavior: behaviors.WALL,
tempHigh: 1455.5,
category: "solids",
density: 7850,
conduct: 0.42,
hardness: 0.8,
},
"rose_gold": {
color: ["#B76E79","#a1334d","#f06283"],
behavior: behaviors.WALL,
tempHigh: 897,
category: "solids",
density: 12900,
conduct: 0.87,
},
"solder": {
color: "#a1a19d",
behavior: behaviors.WALL,
tempHigh: 200,
category: "solids",
density: 8885,
conduct: 0.43,
},
"molten_copper": {
reactions: {
"molten_zinc": { "elem1": null, "elem2": "molten_brass" },
"molten_tin": { "elem1": null, "elem2": "molten_bronze" },
"molten_silver": { "elem1": null, "elem2": "molten_sterling" },
"molten_gold": { "elem1": null, "elem2": "molten_rose_gold" },
}
},
"molten_iron": {
reactions: {
"charcoal": { "elem1": "molten_steel", "elem2": null },
"diamond": { "elem1": "molten_steel", "elem2": null },
"carbon_dioxide": { "elem1": "molten_steel", "elem2": null },
}
},
"molten_tin": {
reactions: {
"molten_lead": { "elem1": null, "elem2": "molten_solder" },
}
},
"milk": {
color: "#fafafa",
behavior: behaviors.LIQUID,
tempHigh: 93,
stateHigh: "yogurt",
viscosity: 1.5,
category: "liquids",
state: "liquid",
density: 1036.86,
},
"yogurt": {
color: "#f0efe6",
behavior: behaviors.STURDYPOWDER,
category: "food",
state: "liquid",
density: 820.33,
},
"vinegar": {
color: "#ffecb3",
behavior: behaviors.LIQUID,
reactions: {
"milk": { "elem1": null, "elem2": "cheese" },
"baking_soda": { "elem1": "carbon_dioxide", "elem2": "sodium_acetate" },
"rust": { "elem2":"iron", chance:0.05 },
"oxidized_copper": { "elem2":"copper", chance:0.05 },
},
viscosity: 12,
tempHigh: 100.6,
stateHigh: "steam",
category: "liquids",
state: "liquid",
density: 1006,
stain: -0.8,
},
"baking_soda": {
color: "#ededed",
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 1000,
},
"sodium_acetate": {
color: ["#ededed","#dbdbdb"],
behavior: behaviors.POWDER,
hidden: true,
state: "solid",
density: 900,
category: "powders",
},
"yeast": {
color: ["#AD9166","#9A7F4E","#D8BB8D"],
behavior: [
"XX|CL:50%20|XX",
"CL:50%20 AND SW:bread%30|XX|CL:50%20 AND SW:bread%30",
"XX|M1|XX",
],
reactions: {
"bread": { "elem1": "bread" },
"sugar": { "elem2": "alcohol" },
"potato": { "elem2": "alcohol" },
},
tempHigh: 100,
stateHigh: "bread",
burn: 50,
burnTime: 20,
burnInto: "ash",
category: "food",
state: "solid",
density: 1180,
},
"corn": {
color: ["#F8D223","#D6BA2A","#f7f5ba","#DBD281","#CDB12D"],
behavior: behaviors.WALL,
category: "food",
burn: 10,
burnTime: 200,
tempHigh: 180,
stateHigh: "popcorn",
state: "solid",
density: 721,
},
"popcorn": {
color: ["#a6a076","#ebe4ab","#ebe4ab","#ebe4ab","#ebe4ab","#ebe4ab","#ebe4ab","#c99947"],
behavior: behaviors.POWDER,
category: "food",
tempHigh: 500,
stateHigh: "ash",
burn: 20,
burnTime: 200,
burnInto: ["fire","ash"],
state: "solid",
density: 360.5,
},
"corn_seed": {
color: ["#F2B813","#F9E3BA"],
behavior: [
"XX|M2%0.25|XX",
"XX|L2:plant,corn AND C2:corn%30|XX",
"XX|M1|XX",
],
tempHigh: 400,
stateHigh: "fire",
burn: 50,
burnTime: 20,
category: "life",
state: "solid",
density: 721,
},
"potato_seed": {
color: ["#CDA57F","#AA7437","#BC9563"],
behavior: [
"XX|CH:dirt>root|XX",
"CH:dirt>potato%5|CH:potato%1|CH:dirt>potato%5",
"XX|SW:dirt%3 AND M1|XX",
],
tempHigh: 400,
stateHigh: "fire",
burn: 50,
burnTime: 20,
category: "life",
state: "solid",
density: 675,
},
"potato": {
color: ["#d99857","#d98757","#a66933"],
behavior: behaviors.STURDYPOWDER,
tempHigh: 400,
stateHigh: "ash",
burn: 50,
burnTime: 20,
burnInto: "ash",
category: "food",
state: "solid",
density: 675,
},
"root": {
color: "#7B6F6B",
behavior: behaviors.WALL,
reactions: {
"rock": { "elem2":"sand", "chance":0.0004 },
},
tempHigh: 100,
stateHigh: "dead_plant",
tempLow: -2,
stateLow: "frozen_plant",
burn: 50,
burnTime: 20,
burnInto: "dirt",
category: "life",
state: "solid",
density: 1250,
},
"bread": {
color: "#F2CF99",
behavior: behaviors.STURDYPOWDER,
tempHigh: 176,
stateHigh: "toast",
category: "food",
burn: 30,
burnTime: 200,
burnInto: "ash",
state: "solid",
density: 233.96,
},
"toast": {
color: "#C08655",
behavior: behaviors.STURDYPOWDER,
tempHigh: 500,
stateHigh: "ash",
category: "food",
burn: 50,
burnTime: 170,
burnInto: "ash",
state: "solid",
density: 233.96,
},
"flour": {
color: "#F0E2B7",
behavior: behaviors.POWDER,
reactions: {
"water": { "elem1": "dough", "elem2": null },
},
category: "powders",
tempHigh: 400,
stateHigh: "fire",
burn:40,
burnTime:25,
state: "solid",
density: 600,
},
"dough": {
color: "#EDD8BA",
behavior: behaviors.SUPPORT,
category: "food",
tempHigh: 94,
stateHigh: "bread",
burn:40,
burnTime:25,
burnInto:"ash",
state: "solid",
density: 526.9,
},
"salt": {
color: ["#f2f2f2","#e0e0e0"],
behavior: behaviors.POWDER,
reactions: {
"ice": { "elem1":null, "elem2":"salt_water", "chance":0.1 },
"snow": { "elem1":null, "elem2":"salt_water", "chance":0.25 },
"packed_snow": { "elem1":null, "elem2":"salt_water", "chance":0.05 },
"packed_ice": { "elem1":null, "elem2":"salt_water", "chance":0.01 },
},
category: "powders",
tempHigh: 801,
state: "solid",
density: 2160,
},
"sugar": {
color: "#f2f2f2",
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 186,
stateHigh: "caramel",
state: "solid",
density: 1590,
},
"candy": {
color: "#e6cab1",
behavior: behaviors.WALL,
tempHigh: 186,
stateHigh: "caramel",
category: "food",
state: "solid",
density: 900,
},
"dry_ice": {
color: "#e6e6e6",
behavior: behaviors.WALL,
category: "solids",
temp: -98.5,
tempHigh: -78.5,
stateHigh: "carbon_dioxide",
state: "solid",
density: 1562,
},
"nitrogen_ice": {
color: "#e6e6e6",
behavior: behaviors.WALL,
category: "solids",
temp: -259.86,
tempHigh: -209.86,
stateHigh: "liquid_nitrogen",
state: "solid",
density: 1562,
hidden: true,
},
"alcohol": {
color: "#c9c5b1",
behavior: behaviors.LIQUID,
reactions: {
"virus": { "elem2":null },
"plague": { "elem2":null },
},
viscosity: 1,
tempHigh: 78,
stateHigh: ["steam","carbon_dioxide"],
burn: 100,
burnTime: 3,
fireColor: ["#80ACF0","#96CDFE","#bee6d4"],
category: "liquids",
state: "liquid",
density: 785.1,
stain: -0.25,
},
"basalt": {
color: ["#2e2e2e","#333333","#3d3d3d"],
behavior: behaviors.STURDYPOWDER,
tempHigh: 1262.5,
stateHigh: "magma",
category: "land",
state: "solid",
density: 3000,
hardness: 0.65,
breakInto: "gravel",
},
"soap": {
color: "#f2f2f2",
behavior: [
"XX|CR:bubble%0.25|XX",
"M2|XX|M2",
"M2|M1|M2",
],
reactions: {
"rust": { "elem2": "iron" },
"oxidized_copper": { "elem2": "copper" },
"blood": { "elem2": "water" },
"dirty_water": { "elem2": "water" },
"salt_water": { "elem2": "water" },
"oxygen": { "elem2": "bubble" },
"plague": { "elem2": null },
"virus": { "elem2": null },
"infection": { "elem2": null },
"mushroom_spore": { "elem2": null },
"lichen": { "elem2": null },
"rotten_meat": { "elem2": "meat" },
"acid_gas": { "elem2": "hydrogen" },
"carbon_dioxide": { "elem2": "oxygen" },
"acid": { "elem2": "hydrogen" },
"acid_cloud": { "elem2": "rain_cloud" },
"oil": { "elem2": null },
},
tempHigh: 100,
stateHigh: "bubble",
viscosity: 500,
state: "liquid",
category:"liquids",
density: 1055,
stain: -1,
},
"bleach": {
color: "#ffffff",
behavior: behaviors.LIQUID,
reactions: {
"acid": { "elem1": "chlorine", "elem2":null },
"acid_gas": { "elem1": "chlorine", "elem2":null },
"acid_cloud": { "elem1": "chlorine", "elem2":null },
},
tempHigh: 111,
stateHigh: ["salt","steam"],
viscosity: 0.956,
state: "liquid",
category:"liquids",
density: 1210,
stain: 0.1,
},
"chlorine": {
color: "#A5AC50",
behavior: behaviors.GAS,
reactions: {
"water": { "elem1": "acid", "elem2":null },
"steam": { "elem1": "acid_gas", "elem2":null },
"hydrogen": { "elem1": "acid_gas", "elem2":null },
},
tempLow: -36.04,
stateLow: "liquid_chlorine",
state: "gas",
category:"gases",
density: 3.2,
stain: 0.005,
},
"liquid_chlorine": {
color: "#F4D217",
behavior: behaviors.LIQUID,
reactions: {
"water": { "elem1": "acid", "elem2":null },
"steam": { "elem2": "acid_gas", "elem1":null },
},
temp: -36.04,
tempHigh: -34.04,
stateHigh: "chlorine",
state: "liquid",
category:"liquids",
density: 1562.5,
stain: 0.01,
hidden: true,
},
"dye": {
color: ["#ff0000","#ff8800","#ffff00","#00ff00","#00ffff","#0000ff","#ff00ff"],
behavior: behaviors.LIQUID,
customColor: true,
stain: 0.66,
category: "liquids",
state: "liquid",
density: 998,
},
"ink": {
color: "#171717",
behavior: behaviors.LIQUID,
stain: 0.66,
category: "liquids",
state: "liquid",
density: 1074.3,
},
"blood": {
color: "#ff0000",
behavior: behaviors.LIQUID,
reactions: {
"vaccine": { "elem1":"antibody", "elem2":null },
"plague": { "elem1":"infection", "elem2":null },
"virus": { "elem1":"infection", "elem2":null },
"cancer": { "elem1":"infection" },
"cyanide": { "elem1":"infection", "elem2":null },
"mushroom_spore": { "elem1":"infection", "elem2":null },
"dirty_water": { "elem1":"infection", "elem2":null },
"rust": { "elem1":"infection", "chance":0.05 },
"oxidized_copper": { "elem1":"infection", "chance":0.05 },
"rat": { "elem1":"infection", "chance":0.075 },
"flea": { "elem1":"infection", "chance":0.03 },
"dirt": { "elem2":"mud" },
"sand": { "elem2":"wet_sand" },
},
viscosity: 10,
tempHigh: 124.55,
stateHigh: ["steam","salt","oxygen"],
category:"liquids",
state: "liquid",
density: 1060,
stain: 0.05,
},
"vaccine": {
color: "#e0d0ad",
behavior: behaviors.LIQUID,
reactions: {
"infection": { "elem1":null, "elem2":"antibody", "chance":0.1 },
"antibody": { "elem1":null, "chance":0.0025 },
"plague": { "elem2":null, "chance":0.1 },
"virus": { "elem2":null, "chance":0.1 },
"cancer": { "elem2":null, "chance":0.01 },
},
viscosity: 2.6,
tempHigh: 124.55,
stateHigh: "steam",
category:"liquids",
state: "liquid",
density: 1125,
},
"antibody": {
color: "#ff4040",
behavior: behaviors.LIQUID,
reactions: {
"blood": { "elem2":"antibody", "chance":0.01 },
"infection": { "elem2":"antibody", "chance":0.1 },
"cancer": { "elem2":null, "chance":0.01 },
},
viscosity: 6.3,
tempHigh: 124.55,
stateHigh: ["steam","salt","oxygen"],
category:"liquids",
hidden: true,
state: "liquid",
density: 1060,
stain: 0.05,
},
"infection": {
color: "#cf005d",
behavior: behaviors.LIQUID,
reactions: {
"blood": { "elem2":"infection", "chance":0.01 },
"frog": { "elem2":"rotten_meat", "chance":0.005 },
"fish": { "elem2":"rotten_meat", "chance":0.005 },
"meat": { "elem2":"rotten_meat", "chance":0.005 },
},
viscosity: 15,
tempHigh: 124.55,
stateHigh: ["plague","plague","plague","salt","oxygen"],
category:"liquids",
hidden: true,
state: "liquid",
density: 1060,
stain: 0.05,
},
"poison": {
color: "#00ff00",
behavior: behaviors.LIQUID,
reactions: {
"blood": { "elem1":null, "elem2":"infection" },
"water": { "elem1":null, "elem2":"dirty_water" },
"soap": { "elem1":null, "chance":0.02 },
"plant": { "elem1":null, "elem2":"dead_plant" },
"grass": { "elem1":null, "elem2":"dead_plant" },
"algae": { "elem1":null, "elem2":null },
"mushroom_spore": { "elem1":null, "elem2":null },
"lichen": { "elem1":null, "elem2":null },
"rat": { "elem1":null, "elem2":"rotten_meat" },
"frog": { "elem1":null, "elem2":"rotten_meat" },
"fish": { "elem1":null, "elem2":"rotten_meat" },
"head": { "elem1":null, "elem2":"rotten_meat" },
"body": { "elem1":null, "elem2":"rotten_meat" },
"ant": { "elem1":null, "elem2":null },
"worm": { "elem1":null, "elem2":null },
"fly": { "elem1":null, "elem2":null },
"firefly": { "elem1":null, "elem2":null },
"bee": { "elem1":null, "elem2":null },
"slug": { "elem1":null, "elem2":"slime" },
"snail": { "elem1":null, "elem2":"calcium" },
"sapling": { "elem1":null, "elem2":"dead_plant" },
"root": { "elem1":null, "elem2":"dead_plant" },
"flower_seed": { "elem1":null, "elem2":"dead_plant" },
"pistil": { "elem1":null, "elem2":"dead_plant" },
"petal": { "elem1":null, "elem2":"dead_plant" },
"grass_seed": { "elem1":null, "elem2":"dead_plant" },
"meat": { "elem1":null, "elem2":"rotten_meat" },
},
viscosity: 2,
tempHigh: 400,
stateHigh: "plague",
category:"liquids",
state: "liquid",
density: 1060,
},
"antidote": {
color: "#c9b836",
behavior: behaviors.LIQUID,
reactions: {
"poison": { "elem1":null, "elem2":null },
},
viscosity: 2,
tempHigh: 400,
stateHigh: "plague",
category:"liquids",
state: "liquid",
density: 1060,
},
"honey": {
color: ["#F6CE1A","#E79001","#BB5503"],
behavior: behaviors.LIQUID,
viscosity: 10000,
tempHigh: 71.11,
stateHigh: "caramel",
category:"liquids",
state: "liquid",
density: 1420,
},
"caramel": {
color: "#e89a51",
behavior: behaviors.LIQUID,
reactions: {
"fire": { "elem1": "molasses" },
},
viscosity: 500,
temp: 40,
tempLow: 24,
stateLow: "candy",
tempHigh: 204.44,
stateHigh: "fire",
category: "liquids",
state: "liquid",
density: 850,
},
"molasses": {
color: ["#210c06","#170804"],
behavior: behaviors.LIQUID,
viscosity: 7500,
tempHigh: 1000,
stateHigh: ["fire","sugar","steam"],
category:"liquids",
state: "liquid",
density: 1600,
stain: 0.05,
},
"ketchup": {
color: "#ff3119",
behavior: behaviors.LIQUID,
viscosity: 50000,
tempHigh: 260,
stateHigh: ["vinegar","steam","salt","sugar"],
category:"liquids",
state: "liquid",
density: 1235,
stain: 0.05,
},
"chocolate_syrup": {
color: "#3b160b",
behavior: behaviors.LIQUID,
tempLow: 0,
stateLow: "chocolate",
tempHigh: 99,
stateHigh: ["steam","sugar"],
category: "liquids",
viscosity: 40,
state: "liquid",
density: 1325,
hidden: true,
stain: 0.05,
},
"liquid_hydrogen": {
color: "#97afcf",
behavior: behaviors.LIQUID,
reactions: {
"liquid_oxygen": { "elem1":"ice", "elem2":null },
"oxygen": { "elem1":"ice", "elem2":null },
},
category: "liquids",
burn: 100,
burnTime: 2,
temp:-259.16,
tempHigh: -252.879,
stateHigh: "hydrogen",
state: "liquid",
density: 71,
},
"liquid_oxygen": {
color: "#00ad99",
behavior: behaviors.LIQUID,
reactions: {
"hydrogen": { "elem1":"ice", "elem2":null },
},
category: "liquids",
burn: 100,
burnTime: 2,
temp:-218.79,
tempHigh: -182.962,
stateHigh: "oxygen",
state: "liquid",
density: 1141,
},
"liquid_nitrogen": {
color: "#d3e1e3",
behavior: behaviors.LIQUID,
category: "liquids",
temp:-209.86,
tempHigh: -195.795,
stateHigh: "nitrogen",
tempLow: -259.86,
stateLow: "nitrogen_ice",
state: "liquid",
density: 804,
},
"liquid_helium": {
color: "#e3d3d3",
behavior: behaviors.LIQUID,
category: "liquids",
temp:-272.20,
tempHigh: -268.928,
stateHigh: "helium",
state: "liquid",
density: 145,
hidden: true,
},
"calcium": {
color: ["#515053","#7a787d","#748193","#FEF9FF","#748193","#7a787d","#515053"],
behavior: behaviors.POWDER,
tempHigh: 842,
category: "powders",
state: "solid",
density: 1550,
conduct: 0.40,
},
"limestone": {
color: ["#C5B79C","#D9CCB2","#F8F1DB","#FCFAEB"],
behavior: behaviors.STURDYPOWDER,
tempHigh: 825,
stateHigh: "quicklime",
category: "land",
state: "solid",
density: 2100,
hardness: 0.4,
breakInto: ["quicklime","calcium","dust"],
},
"quicklime": {
color: "#E9EBE7",
behavior: behaviors.POWDER,
tempHigh: 4662,
stateHigh: "molten_calcium",
category: "land",
state: "solid",
density: 1025,
hardness: 0.33,
breakInto: ["calcium","dust"],
},
"slaked_lime": {
color: "#adb8b5",
behavior: behaviors.STURDYPOWDER,
tempHigh: 580,
stateHigh: "quicklime",
category: "land",
hidden: true,
state: "solid",
density: 2211,
hardness: 0.2,
breakInto: ["calcium","dust"],
},
"metal_scrap": {
color: ["#b0afb4","#8c8f98","#cbcdcd","#6c6c6a","#fef9ff"],
behavior: behaviors.POWDER,
tempHigh: 1538,
stateHigh: ["molten_iron","molten_aluminum","molten_tin"],
category: "powders",
density: 2720,
state: "solid",
conduct: 0.43,
},
"slag": {
color: ["#4B3A2D","#6A5447","#6B5B53","#675851","#78756E"],
behavior: behaviors.POWDER,
tempHigh: 1780,
category: "powders",
density: 2400,
state: "solid",
conduct: 0.03,
},
"thermite": {
color: ["#5D4947","#5B3C42","#372A2D"],
behavior: behaviors.POWDER,
tick: function(pixel) {
if (pixel.burning) {
changePixel(pixel,"molten_thermite");
pixel.temp = 2200;
}
},
tempHigh: 660,
burn: 100,
burnTime: 1000,
category: "powders",
density: 700,
state: "solid",
},
"molten_thermite": {
tick: function(pixel) {
pixel.temp ++;
}
},
"color_smoke": {
color: ["#6b2e2e","#6b4f2e","#6b6b2e","#2e6b2e","#2e6b6b","#2e2e6b","#6b2e6b"],
behavior: behaviors.GAS,
category: "gases",
state: "gas",
density: 1.977,
customColor: true,
},
"neon": {
color: "#bababa",
behavior: behaviors.GAS,
behaviorOn: [
"M2|M1|M2",
"M1|CC:#ff0000|M1",
"M2|M1|M2",
],
tempLow: -248.59,
stateLow: "liquid_neon",
category: "gases",
density: 0.9002,
state: "gas",
conduct: 0.86,
},
"liquid_neon": {
color: "#d1d1d1",
behavior: behaviors.LIQUID,
behaviorOn: [
"XX|XX|XX",
"M2|CC:#ff0000|M2",
"M1|M1|M1",
],
temp: -258.59,
tempHigh: -248.59,
stateHigh: "neon",
category: "liquids",
hidden: true,
density: 1207,
state: "liquid",
conduct: 0.83,
},
"smog": {
color: "#989398",
behavior: [
"XX|M2%5|XX",
"M1%8|XX|M1%8",
"XX|M2%5|XX",
],
temp: 100,
tempLow: 47.5,
stateLow: "water",
category: "gases",
density: 590.3,
state: "gas",
conduct: 0.03,
stain: 0.0035,
},
"rain_cloud": {
color: "#636b78",
behavior: [
"XX|XX|XX",
"M1%5|CH:water%0.05|M1%5",
"CR:electric%0.05|CR:electric%0.05|CR:electric%0.05",
],
category:"gases",
temp: 80,
tempLow: 0,
stateLow: "snow_cloud",
state: "gas",
density: 0.5,
conduct: 0.03,
},
"snow_cloud": {
color: "#7e8691",
behavior: [
"XX|XX|XX",
"M1%5|CH:snow%0.025|M1%5",
"XX|XX|XX",
],
category:"gases",
temp: -10,
tempHigh: 30,
stateHigh: "rain_cloud",
tempLow: -40,
stateLow: "hail_cloud",
state: "gas",
density: 0.55,
conduct: 0.01,
},
"hail_cloud": {
color: "#7e8691",
behavior: [
"XX|XX|XX",
"M1%5|CH:hail%0.05|M1%5",
"XX|XX|XX",
],
category:"gases",
temp: -40,
tempHigh: -10,
stateHigh: "snow_cloud",
state: "gas",
density: 0.6,
conduct: 0.01,
},
"acid_cloud": {
color: "#637865",
behavior: [
"XX|XX|XX",
"M1%5|CH:acid%0.05|M1%5",
"XX|XX|XX",
],
reactions: {
"ash": { "elem1":"rain_cloud", "elem2":null, "chance":0.05 },
"limestone": { "elem1":"rain_cloud", "elem2":null, "chance":0.05 },
"quicklime": { "elem1":"rain_cloud", "elem2":null, "chance":0.05 },
"slaked_lime": { "elem1":"rain_cloud", "elem2":null, "chance":0.05 },
"borax": { "elem1":"rain_cloud", "elem2":null, "chance":0.05 },
"ammonia": { "elem1":"rain_cloud", "elem2":null, "chance":0.05 },
},
category:"gases",
burn: 15,
burnTime: 5,
state: "gas",
density: 0.575,
},
"pyrocumulus": {
color: "#2e2e2e",
behavior: [
"XX|XX|XX",
"M1%5|CH:ash%0.075|M1%5",
"XX|XX|XX",
],
reactions: {
"fireball": { "elem1":null, "elem2":"fire_cloud", "chance":0.25 },
},
category:"gases",
hidden: true,
state: "gas",
density: 0.58,
},
"fire_cloud": {
color: ["#332424","#473431","#473931"],
behavior: [
"XX|XX|XX",
"M1%5|CH:fireball%0.02|M1%5",
"XX|XX|XX",
],
reactions: {
"rain_cloud": { "elem1": "pyrocumulus", "elem2": "pyrocumulus" },
"snow_cloud": { "elem1": "pyrocumulus", "elem2": "rain_cloud" },
"hail_cloud": { "elem1": "pyrocumulus", "elem2": "snow_cloud" },
"acid_cloud": { "elem1": "fire", "elem2": "electric" },
},
temp: 500,
tempLow: 100,
stateLow: "pyrocumulus",
category:"gases",
state: "gas",
density: 0.59,
},
"battery": {
color: "#9c6c25",
behavior: [
"XX|SH|XX", // shocks (adds charge)
"SH|XX|SH",
"XX|SH|XX",
],
category: "machines",
tempHigh: 1455.5,
stateHigh: "molten_steel",
},
"led_r": {
behavior: behaviors.WALL,
color: "#660000",
colorOn: "#ff0000",
category: "machines",
tempHigh: 1500,
stateHigh: "molten_glass",
conduct: 1,
},
"led_g": {
behavior: behaviors.WALL,
color: "#006600",
colorOn: "#00ff00",
category: "machines",
tempHigh: 1500,
stateHigh: "molten_glass",
conduct: 1,
},
"led_b": {
behavior: behaviors.WALL,
color: "#000066",
colorOn: "#0000ff",
category: "machines",
tempHigh: 1500,
stateHigh: "molten_glass",
conduct: 1,
},
"sulfur": {
color: ["#E9D74C","#89761B","#DDC56B"],
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 115.21,
burn: 25,
burnTime: 207,
fireColor: ["#8180CC","#7F84E6"],
state: "solid",
density: 2070,
},
"molten_sulfur": {
reactions: {
"molten_copper": { "elem1": null, "elem2": "molten_copper_sulfate" },
},
density: 1819,
burn: 25,
burnTime: 507,
fireColor: ["#8180CC","#7F84E6"],
},
"copper_sulfate": {
color: ["#4391FD","#004CFE"],
behavior: behaviors.POWDER,
tempHigh: 110,
burn: 10,
burnTime: 1007,
fireColor: ["#91D106","#FEFF97","#248E01"],
state: "solid",
density: 3600,
hidden: true,
category: "powders",
},
"diamond": {
color: ["#03fcec","#03c6fc","#b3eeff","#8ab0e6"],
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 900,
stateHigh: "carbon_dioxide",
state: "solid",
density: 3515,
hardness: 1,
},
"glitter": {
color: ["#ACE4FB","#D9FCFF","#8F6EB2","#FDEAFC","#180E1C","#6B2778"],
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 100,
stateHigh: ["fire","fire","dioxin"],
state: "solid",
density: 1450,
burn: 50,
burnTime: 50,
burnInto: ["smoke","smoke","dioxin"],
},
"electric": {
color: "#dddd00",
behavior: [
"CL%5|CL%5 AND SH|CL%5",
"CL%5 AND SH|SH%5 AND DL%50|CL%5 AND SH",
"M1%15 AND CL%6|M1%50 AND CL%13 AND SH|M1%15 AND CL%6",
],
charge: 3,
category: "energy",
state: "solid",
density: 2.1,
},
"snake": {
color: "#00bf00",
behavior: [
"XX|XX|XX",
"XX|LB:plant AND RT%5|M1 AND BO:1,2,3",
"XX|XX|XX",
],
rotatable: true,
category: "special",
excludeRandom: true,
},
"loopy": {
color: "#eb3474",
behavior: [
"XX|M2|M1",
"XX|RT%20|M2",
"CR:smoke|XX|XX",
],
rotatable: true,
category: "special",
},
"cyanide": {
color: "#b6ccb6",
behavior: behaviors.GAS,
reactions: {
"frog": { "elem2":"meat" },
"ant": { "elem2":null },
"bee": { "elem2":null },
"fish": { "elem2":"meat" },
"firefly": { "elem2":null },
},
tempHigh: 550,
stateHigh: "fire",
burn: 100,
burnTime: 1,
state: "gas",
density: 687,
category: "gases",
},
"radiation": {
color: ["#00ff00","#6fff00"],
behavior: [
"XX|M1%0.5 AND HT|XX",
"M1%7 AND HT|DL%3|M1%7 AND HT",
"XX|M1%1 AND HT|XX",
],
reactions: {
"water": { "elem2":"rad_steam", "chance":0.4 },
"steam": { "elem2":"rad_steam", "chance":0.4 },
"salt_water": { "elem2":"rad_steam", "chance":0.4 },
"sugar_water": { "elem2":"rad_steam", "chance":0.4 },
"dirty_water": { "elem2":"rad_steam", "chance":0.4 },
"seltzer": { "elem2":"rad_steam", "chance":0.4 },
"bubble": { "elem2":"rad_steam", "chance":0.4 },
"foam": { "elem2":"rad_steam", "chance":0.4 },
"ice": { "elem2":"rad_steam", "chance":0.4 },
"snow": { "elem2":"rad_steam", "chance":0.4 },
"packed_snow": { "elem2":"rad_steam", "chance":0.4 },
"slime": { "elem2":"rad_steam", "chance":0.4 },
"milk": { "elem2":"cheese", "chance":0.4 },
"permafrost": { "elem1":"rad_steam", "elem2":"dirt", "chance":0.4 },
"mud": { "elem1":"rad_steam", "elem2":"dirt", "chance":0.4 },
"wet_sand": { "elem1":"rad_steam", "elem2":"sand", "chance":0.4 },
"clay": { "elem1":"rad_steam", "elem2":"clay_soil", "chance":0.4 },
"slaked_lime": { "elem1":"rad_steam", "elem2":"limestone", "chance":0.4 },
"rain_cloud": { "elem2":"rad_cloud", "chance":0.4 },
"snow_cloud": { "elem2":"rad_cloud", "chance":0.4 },
"hail_cloud": { "elem2":"rad_cloud", "chance":0.4 },
"plant": { "elem2":"dead_plant", "chance":0.4 },
"frozen_plant": { "elem2":"dead_plant", "chance":0.4 },
"grass": { "elem2":["dead_plant","straw","grass_seed","wheat_seed"], "chance":0.4 },
"algae": { "elem2":["mushroom_spore","lichen","yeast"], "chance":0.4 },
"mushroom_spore": { "elem2":["lichen","yeast"], "chance":0.4 },
"mushroom_cap": { "elem2":["lichen","plant"], "chance":0.4 },
"mushroom_stalk": { "elem2":["lichen","yeast"], "chance":0.4 },
"mushroom_gill": { "elem2":["lichen","yeast"], "chance":0.4 },
"flea": { "elem2":["ash","ant","termite"], "chance":0.4 },
"ant": { "elem2":["ash","flea","termite"], "chance":0.4 },
"termite": { "elem2":["ash","flea","ant"], "chance":0.4 },
"fly": { "elem2":["ash","firefly","bee"], "chance":0.4 },
"bee": { "elem2":["ash","firefly","fly"], "chance":0.4 },
"firefly": { "elem2":["ash","bee","fly"], "chance":0.4 },
"frog": { "elem2":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"fish": { "elem2":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
"rat": { "elem2":["ash","meat","rotten_meat","cooked_meat","plague"], "chance":0.4 },
"bone": { "elem2":["calcium","calcium","calcium","cancer"], "chance":0.4 },
"meat": { "elem2":["ash","rotten_meat","cooked_meat"], "chance":0.4 },
"rotten_meat": { "elem2":["ash","meat","cooked_meat"], "chance":0.4 },
"cooked_meat": { "elem2":["ash","rotten_meat"], "chance":0.4 },
"bamboo": { "elem2":["wood","plant","bamboo_plant"], "chance":0.4 },
"bamboo_plant": { "elem2":["wood","plant","bamboo"], "chance":0.4 },
"sapling": { "elem2":["wood","plant","tree_branch"], "chance":0.4 },
"tree_branch": { "elem2":["wood","plant","sapling"], "chance":0.4 },
"grass_seed": { "elem2":["straw","wheat_seed"], "chance":0.4 },
"lichen": { "elem2":"algae", "chance":0.4 },
"yeast": { "elem2":["algae","mushroom_spore","lichen"], "chance":0.4 },
"wheat_seed": { "elem2":["straw","wheat","grass_seed"], "chance":0.4 },
"flower_seed": { "elem2":["straw","grass","pistil","petal"], "chance":0.4 },
"pistil": { "elem2":["straw","grass","flower_seed","petal"], "chance":0.4 },
"petal": { "elem2":["straw","grass","flower_seed","pistil"], "chance":0.4 },
"vine": { "elem1":["vine"], "chance":0.4 },
"worm": { "elem2":"ash", "chance":0.4 },
"corn": { "elem2":"corn_seed", "chance":0.4 },
"corn_seed": { "elem2":"corn", "chance":0.4 },
"potato": { "elem2":"potato_seed", "chance":0.4 },
"potato_seed": { "elem2":"potato", "chance":0.4 },
"slug": { "elem2":"slime", "chance":0.4 },
"snail": { "elem2":"slime", "chance":0.4 },
"cell": { "elem2":"cancer", "chance":0.4 },
"blood": { "elem2":["infection","cancer"], "chance":0.4 },
"antibody": { "elem2":"cancer", "chance":0.4 },
"infection": { "elem2":"cancer", "chance":0.4 },
"cancer": { "elem2":null, "chance":0.1 },
},
state: "gas",
density: 0.2,
category: "energy",
},
"rad_steam": {
color: "#abffe4",
behavior: [
"M1%10|M1%10|M1%10",
"M2%10|XX|M2%10",
"XX|M2%10|XX",
],
reactions: {
"rad_steam": { "elem1": null, "elem2": "rad_cloud", "chance":0.3, "y":[0,15] },
"steam": { "elem1": null, "elem2": "rad_cloud", "chance":0.3, "y":[0,15] },
"rain_cloud": { "elem1": "rad_cloud", "chance":0.4, "y":[0,15] },
"snow_cloud": { "elem1": "rad_cloud", "chance":0.4, "y":[0,15] },
"hail_cloud": { "elem1": "rad_cloud", "chance":0.4, "y":[0,15] },
"pyrocumulus": { "elem1": "rad_cloud", "chance":0.4, "y":[0,15] },
"rad_cloud": { "elem1": "rad_cloud", "chance":0.3, "y":[0,15] },
},
tempLow: 10,
stateLow: "fallout",
category: "gases",
hidden: true,
state: "gas",
density: 0.7,
},
"rad_cloud": {
color: ["#2d7528","#557528"],
behavior: [
"XX|XX|XX",
"M1%5|CH:fallout,radiation%0.025|M1%5",
"CR:radiation%0.05|CR:radiation%0.05|CR:radiation%0.05",
],
category:"gases",
hidden: true,
state: "gas",
density: 0.55,
},
"fallout": {
color: ["#63b85a","#448044","#598044","#7bb85a"],
behavior: [
"XX|CR:radiation%2|XX",
"CR:radiation%2|CH:radiation%0.5|CR:radiation%2",
"M2|M1 AND CR:radiation%2|M2",
],
category:"energy",
hidden: true,
state: "solid",
density: 1490,
},
"uranium": {
color: ["#599e61","#364d3c","#494D4A","#6c8a42","#798d65","#b5e089"],
behavior: behaviors.RADPOWDER,
tempHigh: 1132.2,
category: "powders",
state: "solid",
density: 19100,
},
"molten_uranium": {
behavior: behaviors.RADMOLTEN,
},
"glass_shard": {
color: ["#5e807d","#679e99","#596b6e"],
behavior: behaviors.POWDER,
tempHigh: 1500,
stateHigh: "molten_glass",
category: "powders",
state: "solid",
density: 2500,
},
"bead": {
color: ["#ff5e5e","#ffcc5e","#76ff5e","#5ed4ff","#5e61ff","#cf5eff"],
behavior: behaviors.POWDER,
category: "powders",
tempHigh: 185,
stateHigh: "molten_plastic",
burn: 10,
burnTime: 400,
burnInto: "dioxin",
state: "solid",
density: 1052,
},
"borax": {
color: "#ffffff",
behavior: behaviors.POWDER,
category: "powders",
burn: 15,
burnTime: 200,
fireColor: ["#34eb67","#5ceb34"],
tempHigh: 743,
state: "solid",
density: 1730,
},
"epsom_salt": {
color: ["#f2f2f2","#e0e0e0"],
behavior: behaviors.POWDER,
category: "powders",
burn: 40,
burnTime: 200,
fireColor: ["#ffffff","#fcf0f0"],
tempHigh: 1124,
state: "solid",
density: 1680,
},
"potassium_salt": {
color: ["#f2f2f2","#e0e0e0"],
behavior: behaviors.POWDER,
category: "powders",
burn: 40,
burnTime: 200,
fireColor: ["#ff00ee","#ff6bf5"],
tempHigh: 292,
state: "solid",
density: 3980,
},
"explosion": {
color: ["#ffb48f","#ffd991","#ffad91"],
behavior: [
"XX|XX|XX",
"XX|EX:10|XX",
"XX|XX|XX",
],
temp: 300,
category: "energy",
state: "gas",
density: 1000,
excludeRandom: true,
},
"cook": {
color: ["#5c3322","#2b1107","#5c3322","#5c3322","#2b1107","#5c3322"],
tool: function(pixel) {
if (!shiftDown) {
pixel.temp += 0.5;
pixelTempCheck(pixel);
}
else {
pixel.temp += 1;
pixelTempCheck(pixel);
}
},
category: "energy",
excludeRandom: true,
},
"tnt": {
color: "#c92a2a",
behavior: behaviors.WALL,
behaviorOn: [
"XX|XX|XX",
"XX|EX:10|XX",
"XX|XX|XX",
],
conduct: 1,
category: "weapons",
burn: 100,
burnTime: 1,
burnInto: "explosion",
tempHigh: 600,
stateHigh: "explosion",
state: "solid",
density: 1630,
excludeRandom: true,
},
"c4": {
name: "C-4",
color: ["#D7C1A1","#C8A77C"],
behavior: behaviors.STURDYPOWDER,
behaviorOn: [
"XX|XX|XX",
"XX|EX:10|XX",
"XX|M1|XX",
],
conduct: 1,
category: "weapons",
burn: 100,
burnTime: 1,
burnInto: "explosion",
tempHigh: 600,
stateHigh: "explosion",
state: "solid",
density: 1630,
excludeRandom: true,
},
"grenade": {
color: "#5e5c57",
behavior: [
"XX|EX:6>metal_scrap,fire,fire,fire%1|XX",
"XX|XX|XX",
"M2|M1 AND EX:6>metal_scrap,fire,fire,fire%1|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"dynamite": {
color: ["#de5050","#c92a2a","#a61919"],
behavior: [
"XX|EX:15%1|XX",
"XX|XX|XX",
"M2|M1 AND EX:15%1|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 600,
stateHigh: "explosion",
breakInto: "explosion",
excludeRandom: true,
},
"gunpowder": {
color: ["#929980","#757767","#423D43"],
behavior: behaviors.POWDER,
category: "weapons",
burn: 100,
burnTime: 1,
burnInto: "explosion",
tempHigh: 600,
stateHigh: "explosion",
state: "solid",
density: 1700,
excludeRandom: true,
},
"ember": {
color: ["#ffe985","#ffd885","#ffc285"],
behavior: [
"XX|M1|M1",
"XX|XX|XX",
"XX|XX|XX",
],
flippableX: true,
category: "energy",
burn: 10,
burnTime: 10,
burnInto: "ash",
burning: true,
state: "gas",
density: 700,
hidden: true,
},
"firework": {
color: "#c44f45",
tick: function(pixel) {
if (pixel.burning) {
if (!tryMove(pixel, pixel.x, pixel.y-1)) {
// tryMove again to the top left or top right
tryMove(pixel, pixel.x+(Math.random() < 0.5 ? -1 : 1), pixel.y-1);
}
if (pixelTicks-pixel.burnStart > 50 && Math.random() < 0.1) {
explodeAt(pixel.x, pixel.y, 10, "fw_ember");
}
}
else {
if (!tryMove(pixel, pixel.x, pixel.y+1)) {
// tryMove again to the bottom left or bottom right
tryMove(pixel, pixel.x+(Math.random() < 0.5 ? -1 : 1), pixel.y+1);
}
}
},
burn: 90,
burnTime: 100,
density: 2000,
category: "weapons",
},
"fw_ember": {
color: ["#ff7a70","#ff9b70","#ffe270","#94ff70","#00ffff","#9b70ff","#ffa8d2"],
behavior: [
"XX|XX|XX",
"XX|DL%25|M2",
"XX|M2|M1",
],
name: "firework ember",
burning: true,
burnInto: "ash",
rotatable: true,
temp: 649,
category: "energy",
hidden: true,
},
"nuke": {
color: "#534636",
behavior: [
"XX|EX:60>plasma,plasma,plasma,plasma,radiation,rad_steam|XX",
"XX|XX|XX",
"M2|M1 AND EX:60>plasma,plasma,plasma,plasma,radiation,rad_steam|M2",
],
category: "weapons",
state: "solid",
density: 1500,
excludeRandom: true,
},
"dirty_bomb": {
color: "#415336",
behavior: [
"XX|EX:40>radiation,radiation,radiation,rad_steam|XX",
"XX|XX|XX",
"M2|M1 AND EX:40>radiation,radiation,radiation,rad_steam|M2",
],
category: "weapons",
state: "solid",
density: 1500,
excludeRandom: true,
},
"nitroglycerin": {
color: "#47c900",
behavior: behaviors.LIQUID,
behaviorOn: [
"XX|XX|XX",
"XX|EX:10|XX",
"XX|XX|XX",
],
conduct: 1,
category: "weapons",
tempHigh: 600,
stateHigh: "fire",
burn: 100,
burnTime: 1,
burnInto: "explosion",
viscosity: 36,
state: "liquid",
density: 1600,
excludeRandom: true,
},
"greek_fire": {
color: ["#4a3923","#594933","#78654a"],
behavior: behaviors.LIQUID,
category: "weapons",
tempHigh: 4000,
stateHigh: "fire",
burn: 100,
burnTime: 1500,
burnInto: "fire",
burning: true,
temp: 500,
insulate: true,
viscosity: 2,
state: "liquid",
density: 498.5,
excludeRandom: true,
},
"sticky_bomb": {
color: "#233096",
behavior: [
"XX|ST AND EX:10%2|XX",
"ST AND EX:10%2|XX|ST AND EX:10%2",
"XX|M1 AND ST AND EX:10%2|XX",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: ["molten_steel","slime"],
excludeRandom: true,
},
"cold_bomb": {
color: "#43646e",
behavior: [
"XX|EX:10>cold_fire|XX",
"XX|XX|XX",
"M2|M1 AND EX:10>cold_fire|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"hot_bomb": {
color: "#6c436e",
behavior: [
"XX|EX:10>plasma|XX",
"XX|XX|XX",
"M2|M1 AND EX:10>plasma|M2",
],
temp: 7065,
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 10455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"electro_bomb": {
color: "#6e6d43",
behavior: [
"XX|EX:10>electric|XX",
"XX|XX|XX",
"M2|M1 AND EX:10>electric|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1655.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"water_bomb": {
color: "#34599e",
behavior: [
"XX|EX:10>water|XX",
"XX|XX|XX",
"M2|M1 AND EX:10>water|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"antimatter_bomb": {
color: "#6e4343",
behavior: [
"XX|EX:20>antimatter|XX",
"XX|XX|XX",
"M2|M1 AND EX:20>antimatter|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 10455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"flashbang": {
color: "#65665c",
behavior: [
"XX|EX:20>flash%1|XX",
"XX|XX|XX",
"M2|M1 AND EX:20>flash%1|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"flash": {
color: "#ffffa8",
behavior: [
"XX|XX|XX",
"XX|DL%75|XX",
"XX|XX|XX",
],
category: "energy",
state: "gas",
density: 1,
tempLow: -270,
stateLow: "light",
hidden: true,
},
"smoke_grenade": {
color: "#65665c",
behavior: [
"XX|CR:smoke|XX",
"XX|EX:4>smoke%1|XX",
"M2|M1|M2",
],
category: "weapons",
state: "solid",
density: 7300,
conduct: 0.73,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"fireball": {
color: ["#782828","#783b28","#784b28"],
behavior: [
"XX|CR:fire%25|XX",
"XX|CC:782828,783b28,784b28%25|XX",
"M2|M1 AND EX:8|M2",
],
reactions: {
"water": { "elem1":"rock", "elem2":"steam" }
},
category: "weapons",
temp:600,
tempHigh: 1900,
stateHigh: "magma",
tempLow: -100,
stateLow: "rock",
burning: true,
burnInto: ["rock","rock","steam"],
burnTime: 170,
burn: 100,
state: "solid",
density: 1600,
excludeRandom: true,
},
"landmine": {
color: "#856C7D",
behavior: [
"XX|EX:20|XX",
"XX|XX|XX",
"XX|M1|XX",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"cluster_bomb": {
color: "#7d776d",
behavior: [
"XX|EX:10>smoke,smoke,smoke,smoke,smoke,grenade|XX",
"XX|XX|XX",
"M2|M1 AND EX:10>smoke,smoke,smoke,smoke,smoke,grenade|M2",
],
category: "weapons",
state: "solid",
density: 1300,
tempHigh: 1455.5,
stateHigh: "molten_steel",
excludeRandom: true,
},
"armageddon": {
color: "#a62900",
behavior: [
"XX|XX|XX",
"XX|EX:10>armageddon,fire,fire,fire,fire,fire,fire,fire,fire,fire,fire,fire,fire%25 AND DL%10|XX",
"M2|M1|M2",
],
category: "weapons",
state: "solid",
density: 1300,
hidden: true,
excludeRandom: true,
excludeRandom: true,
},
"tesla_coil": {
color: "#725C38",
behavior: behaviors.WALL,
behaviorOn: [
"XX|CR:plasma|XX",
"CR:plasma|XX|CR:plasma",
"XX|CR:plasma|XX",
],
category: "machines",
conduct: 1,
insulate: true,
temp: 7065,
},
"light_bulb": {
color: "#a8a897",
behavior: behaviors.WALL,
behaviorOn: [
"XX|CR:light|XX",
"CR:light|XX|CR:light",
"XX|CR:light|XX",
],
colorOn: "#ebebc3",
category: "machines",
tempHigh: 1500,
stateHigh: ["molten_glass","molten_glass","molten_copper"],
conduct: 1,
},
"shocker": {
color: "#78784c",
behavior: behaviors.WALL,
behaviorOn: [
"XX|CR:electric AND SH|XX",
"CR:electric AND SH|XX|CR:electric AND SH",
"XX|CR:electric AND SH|XX",
],
colorOn: "#ffff59",
category: "machines",
conduct: 1,
},
"pressure_plate": {
color: "#8a8a84",
tick: function(pixel) {
if (!isEmpty(pixel.x, pixel.y-1)){
if (pixelMap[pixel.x][pixel.y-1].element != "pressure_plate" || pixelMap[pixel.x][pixel.y-1].on) {
pixel.on = true;
var coordsToShock = [
[pixel.x, pixel.y+1],
[pixel.x+1, pixel.y],
[pixel.x-1, pixel.y],
]
for (var i = 0; i < coordsToShock.length; i++) {
var x = coordsToShock[i][0];
var y = coordsToShock[i][1];
if (!isEmpty(x,y,true)) {
var newpixel = pixelMap[x][y];
if (elements[newpixel.element].conduct) {
newpixel.charge = 1;
}
}
}
}
}
else if (pixel.on) {
pixel.on = false;
}
tryMove(pixel, pixel.x, pixel.y+1);
},
category: "machines",
},
"primordial_soup": {
color: ["#501F24","#6D2E1D"],
behavior: [
"XX|CR:foam%2|XX",
"M2|CH:algae,cell,mushroom_spore,lichen,yeast,antibody,cellulose%0.005|M2",
"M1|M1|M1",
],
reactions: {
"cancer": { "elem1":"dirty_water" },
"cyanide": { "elem1":"dirty_water" },
"infection": { "elem1":"dirty_water" },
"plague": { "elem1":"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 },
},
category: "life",
tempHigh: 100,
stateHigh: "steam",
conduct: 0.33,
state: "liquid",
density: 955,
},
};
function hexToRGB(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
currentPixels = [];
//currentID = 0;
// Pixel class, with attributes such as x, y, and element
class Pixel {
constructor(x, y, element) {
this.x = x;
this.y = y;
this.element = element;
var elementInfo = elements[element];
this.color = pixelColorPick(this);
// If element doesn't have temp attribute, set temp to airTemp
if (elementInfo.temp==undefined) {
this.temp = airTemp;
} else {
this.temp = elementInfo.temp;
}
this.start = pixelTicks;
//this.id = currentID;
//currentID++;
if (elementInfo.burning) {
this.burning = true;
this.burnStart = pixelTicks;
}
else {
this.burning = false;
}
if (elementInfo.charge) {
this.charge = elementInfo.charge;
}
// If elementInfo.flippableX, set it to true or false randomly
if (elementInfo.flipX !== undefined) { this.flipX = elementInfo.flipX }
else if (elementInfo.flippableX) {
this.flipX = Math.random() >= 0.5;
}
// If elementInfo.flippableY, set it to true or false randomly
if (elementInfo.flipY !== undefined) { this.flipY = elementInfo.flipY }
else if (elementInfo.flippableY) {
this.flipY = Math.random() >= 0.5;
}
// If elementInfo.rotatable, set it to a number between 0 and 3
if (elementInfo.r !== undefined) { this.r = elementInfo.r }
else if (elementInfo.rotatable) {
this.r = Math.floor(Math.random() * 4);
}
// If elementInfo.properties, set each key to its value
if (elementInfo.properties !== undefined) {
for (var key in elementInfo.properties) {
// If it is an array or object, make a copy of it
if (typeof elementInfo.properties[key] == "object") {
this[key] = JSON.parse(JSON.stringify(elementInfo.properties[key]));
}
else {
this[key] = elementInfo.properties[key];
}
}
}
pixelMap[x][y] = this;
}
}
// If the screen size is under 768px, set pixelSize to 5, otherwise 6
if (window.innerWidth < 700) {
pixelSize = 5;
} else {
pixelSize = 6;
}
function outOfBounds(x,y) {
// Returns true if the pixel is out of bounds
return y > height-1 || y < 1 || x > width-1 || x < 1
}
function isEmpty(x, y, ignoreBounds=false) {
if (outOfBounds(x,y)) {
return ignoreBounds;
}
return pixelMap[x][y] == undefined;
}
function canMove(pixel,x,y) {
if (isEmpty(x,y)) {
return true;
}
}
function movePixel(pixel,x,y,leaveBehind=null) {
// Delete the pixel from the old position
delete pixelMap[pixel.x][pixel.y];
if (leaveBehind != null && isEmpty(pixel.x,pixel.y)) { createPixel(leaveBehind,pixel.x,pixel.y); }
pixel.x = x;
pixel.y = y;
pixelMap[x][y] = pixel;
}
function clonePixel(pixel,x,y) {
currentPixels.push(new Pixel(x, y, pixel.element));
}
function createPixel(element,x,y) {
currentPixels.push(new Pixel(x, y, element));
}
function deletePixel(x,y) {
// remove pixelMap[x][y] from currentPixels
currentPixels.splice(currentPixels.indexOf(pixelMap[x][y]),1);
if (pixelMap[x][y]) {pixelMap[x][y].del = true;}
delete pixelMap[x][y];
/*for (var i = 0; i < currentPixels.length; i++) {
if (currentPixels[i].x == x && currentPixels[i].y == y) {
currentPixels.splice(i, 1);
break;
}
}*/
/*if (id != null) {
for (var i = 0; i < currentPixels.length; i++) {
if (currentPixels[i].id == id) {
currentPixels.splice(i, 1);
return;
}
}
}*/
}
function swapPixels(pixel1,pixel2) {
var tempX = pixel1.x;
var tempY = pixel1.y;
pixel1.x = pixel2.x;
pixel1.y = pixel2.y;
pixel2.x = tempX;
pixel2.y = tempY;
pixelMap[pixel1.x][pixel1.y] = pixel1;
pixelMap[pixel2.x][pixel2.y] = pixel2;
}
function changePixel(pixel,element) {
pixel.element = element;
pixel.color = pixelColorPick(pixel);
pixel.start = pixelTicks;
if (elements[element].burning == true) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
else if (pixel.burning && !elements[element].burn) {
pixel.burning = false;
delete pixel.burnStart;
}
delete pixel.origColor; // remove stain
if (pixel.r && !elements[element].rotatable) {
delete pixel.r;
}
if (pixel.flipX && !elements[element].flippableX) {
delete pixel.flipX;
}
if (pixel.flipY && !elements[element].flippableY) {
delete pixel.flipY;
}
if (elements[element].temp != undefined) {
pixel.temp = elements[element].temp;
pixelTempCheck(pixel)
}
}
function reactPixels(pixel1,pixel2) {
var r = elements[pixel1.element].reactions[pixel2.element];
if (r.chance !== undefined && Math.random() > r.chance) {
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.y !== undefined && (pixel1.y < r.y[0] || pixel1.y > r.y[1])) {
return false;
}
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.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 (r.charge1) { pixel1.charge = r.charge1; }
}
}
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; }
}
}
return true;
}
validDensitySwaps = ["solid>liquid","liquid>gas","liquid>liquid","gas>gas","solid>gas"];
function tryMove(pixel,nx,ny,leaveBehind=undefined) {
var info = elements[pixel.element];
if (isEmpty(nx,ny)) { // If coords is empty, move to coords
movePixel(pixel,nx,ny,leaveBehind);
return true;
}
else {
if (!outOfBounds(nx,ny)) {
// Reactions
newPixel = pixelMap[nx][ny];
if (info.reactions != undefined && info.reactions[newPixel.element] != undefined) {
if (reactPixels(pixel,newPixel)) {
return true;
}
}
else if (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 (pixel.element != newPixel.element) {
if (elements[newPixel.element].density != undefined && info.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.includes(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;
}
}
}
}
}
}
return false;
}
function behaviorCoords(x,y,bx,by) {
return {x:x+bx-1,y:y+by-1};
}
function relativeCoords(x,y,bx,by) {
return {x:bx-1,y:by-1};
}
/* Behavior Example (Sand)
[
["XX","XX","XX"],
["XX","XX","XX"],
["M2","M1","M2"]
] */
behaviorCache = {};
function rotateBehavior(behavior,rotation) {
// returns rotated 2D array counter-clockwise depending on rotation 1, 2, or 3
// if the rotation is under 0, subtract it from 3
if (rotation < 0) {
rotation = 4 + rotation;
}
var check = behaviorCache[behavior.toString()+rotation];
if (check != undefined) { return check; }
var newBehavior = []
if (rotation == 1) {
// rotate counter-clockwise 90 degrees
for (var i = 0; i < behavior.length; i++) {
newBehavior[i] = [];
for (var j = 0; j < behavior[i].length; j++) {
newBehavior[i][j] = behavior[j][behavior.length-1-i];
}}
}
else if (rotation == 2) {
// rotate counter-clockwise 180 degrees
for (var i = 0; i < behavior.length; i++) {
newBehavior[i] = [];
for (var j = 0; j < behavior[i].length; j++) {
newBehavior[i][j] = behavior[behavior.length-1-i][behavior[i].length-1-j];
}}
}
else if (rotation == 3) {
// rotate counter-clockwise 270 degrees
for (var i = 0; i < behavior.length; i++) {
newBehavior[i] = [];
for (var j = 0; j < behavior[i].length; j++) {
newBehavior[i][j] = behavior[behavior[i].length-1-j][i];}
}
}
else {
// no rotation
return behavior;
}
behaviorCache[behavior.toString()+rotation] = newBehavior;
return newBehavior;
}
function flipBehavior(behavior,axis) {
// returns flipped 2D array depending on axis "x" or "y"
var check = behaviorCache[behavior.toString()+axis];
if (check != undefined) { return check; }
if (axis === "x") {
var newBehavior = [];
for (var i = 0; i < behavior.length; i++) {
newBehavior[i] = [];
for (var j = 0; j < behavior[i].length; j++) {
newBehavior[i][j] = behavior[i][behavior[i].length-1-j];
}}
behaviorCache[behavior.toString()+axis] = newBehavior;
return newBehavior;
}
else { // axis === y
newBehavior = behavior.slice().reverse();
behaviorCache[behavior.toString()+axis] = newBehavior;
return newBehavior;
}
return behavior;
}
/* Behavior Rules
XX = Ignore
M1 = Move (First Priority)
M2 = Move (Second Priority)
SP = Support (Doesn't move if all aren't empty)
SA = Support Any (Doesn't move if any aren't empty)
DL = Delete
DB = Delete Both (Self and target)
CL = Clone
CF = Clone first touched
CH = Change
C2 = Change Self after M2
CR:element_name = Create a pixel of element_name
LB:element_name = Leave behind a pixel of element_name when moved (Must be center cell)
L1:element_name = Leave behind only on M1 moves
L2:element_name = Leave behind only on M2 moves
SW = Swap
HT = Heat
CO = Cool
CC = Change Color (Hexadecimal)
ST = Stick
SH = Shock with electricity
FX = Flip X
FY = Flip Y
RT = Rotate
BO = Bounce off of
EX:radius>fire substitute = Explode on touch
%number = Chance of rule happening
*/
function pixelTick(pixel,custom=null) {
if (pixel.start === pixelTicks) {return}
var info = elements[pixel.element];
if (custom) { var behavior = custom; }
else if (pixel.charge && info.behaviorOn) { var behavior = info.behaviorOn; }
else { var behavior = info.behavior; }
if (pixel.flipX) { behavior = flipBehavior(behavior,"x"); }
if (pixel.flipY) { behavior = flipBehavior(behavior,"y"); }
if (pixel.r) { behavior = rotateBehavior(behavior,pixel.r); }
var x = pixel.x;
var y = pixel.y;
var move1Spots = [];
var move2Spots = [];
var supportSpots = [];
var swapSpots = [];
var leaveBehind = null;
var leaveBehind1 = null;
var leaveBehind2 = null;
var move = true;
// Parse behavior
for (var by = 0; by < behavior.length; by++) {
var behaviorby = behavior[by];
for (var bx = 0; bx < behaviorby.length; bx++) {
var b0 = behaviorby[bx];
if (b0 === "XX") {continue}
//if (b.includes(" OR ")) {
// b = b.split(" OR ")[Math.floor(Math.random()*b.split(" OR ").length)];
//}
// Loop through b0.split(" AND ")
if (b0.includes(" AND ")) { var andsplit = b0.split(" AND "); }
else { var andsplit = [b0]; }
for (var i = 0; i < andsplit.length; i++) {
var b = andsplit[i];
if (b.includes(":")) {
var arg = b.split(":")[1].split(/[\:\%]/)[0];
if (!b.includes("%")) {
b = b.split(/[\:\%]/)[0];
}
}
else { var arg = null;}
// If b has "%" followed by a number in it, it's a chance to move
if (b.includes("%")) {
// Split the string at the "%" and use the second half as the chance (float)
var chance = parseFloat(b.split("%")[1]);
//console.log(b+": "+(Math.random()*100 < chance));
b = b.split(/[\:\%]/)[0];
}
else { var chance = 100; }
if (chance==100 || Math.random()*100 < chance) {
var newCoords = behaviorCoords(x,y,bx,by);
if (b == "M1") {
if (info.viscosity != undefined) {
if (!((Math.random()*100) < 100 / ((info.viscosity) ** 0.25))) {
newCoords.x = x;
}
}
move1Spots.push(newCoords);
}
else if (b == "M2") {
if (info.viscosity != undefined) {
if (!((Math.random()*100) < 100 / ((info.viscosity) ** 0.25))) {
newCoords.x = x;
}
}
move2Spots.push(newCoords);
}
else if (b == "SP") {
supportSpots.push({x:newCoords.x,y:newCoords.y,arg:arg});
}
else if (b == "SA") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
move = false;
}
}
else if (b == "DL") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
// if the pixel at newCoords is the same element as the pixel, ignore
newPixel = pixelMap[newCoords.x][newCoords.y];
// if info.ignore exists and newPixel.element is in it
if (info.ignore && info.ignore.includes(newPixel.element)) {
continue;
}
if ((!(newPixel.element == pixel.element)) || (newCoords.x == x && newCoords.y == y)) {
if (arg != null) { var args = arg.split(","); }
if (arg == null || args.includes(newPixel.element)) {
if (!elements[newPixel.element].hardness || Math.random() > elements[newPixel.element].hardness) {
deletePixel(newCoords.x,newCoords.y);
if (newCoords.x == x && newCoords.y == y) {
var deleted = true;
}
swapSpots = [];
}
}
}
}
}
else if (b == "DB") { // Delete Both
if (!isEmpty(newCoords.x,newCoords.y,true)) {
// if the pixel at newCoords is the same element as the pixel, ignore
newPixel = pixelMap[newCoords.x][newCoords.y];
// if info.ignore exists and newPixel.element is in it
if (info.ignore && info.ignore.includes(newPixel.element)) {
continue;
}
if (!(newPixel.element == pixel.element)) {
if (arg != null) { var args = arg.split(","); }
if (arg == null || args.includes(newPixel.element)) {
if (!elements[newPixel.element].hardness || Math.random() > elements[newPixel.element].hardness) {
deletePixel(newCoords.x,newCoords.y);
if (pixelMap[pixel.x][pixel.y] != undefined) {
deletePixel(pixel.x,pixel.y);
}
var deleted = true;
swapSpots = [];
}
}
}
}
}
//Change pixel
else if (b == "CH") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (info.ignore && info.ignore.includes(newPixel.element)) {
continue;
}
if (!elements[newPixel.element].hardness || Math.random() > elements[newPixel.element].hardness) {
if (arg.includes(">")) {
var argfrom = arg.split(">")[0];
var argto = arg.split(">")[1];
}
else {
var argfrom = null;
var argto = arg;
}
if (argto.includes(",")) {
var argto = argto.split(",")[Math.floor(Math.random()*argto.split(",").length)];
}
if (elements[argto]) {
if ((newPixel.element != argto) && (argfrom == null || argfrom == newPixel.element)) {
changePixel(newPixel,argto);
}
}
}
}
}
//Swap
else if (b == "SW") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (arg != null) { var args = arg.split(","); }
if (arg == null || args.includes(newPixel.element)) {
if (!elements[newPixel.element].hardness || Math.random() > elements[newPixel.element].hardness) {
swapSpots.push({x:newCoords.x,y:newCoords.y});
}
}
}
}
//Create pixel
else if (b == "CR") {
if (isEmpty(newCoords.x,newCoords.y)) {
if (arg == null) {
arg = pixel.element;
}
else if (arg.includes(",")) {
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
}
if (elements[arg]) {
createPixel(arg,newCoords.x,newCoords.y);
pixelMap[newCoords.x][newCoords.y].temp = pixel.temp
}
}
}
// Clone self
else if (b == "CL") {
if (isEmpty(newCoords.x,newCoords.y)) {
if (arg == null || pixel.temp >= parseFloat(arg)) {
clonePixel(pixel,newCoords.x,newCoords.y);
}
}
}
// Clone first touched
else if (b == "CF") {
if (pixel.clone) {
if (isEmpty(newCoords.x,newCoords.y)) {
createPixel(pixel.clone,newCoords.x,newCoords.y);
pixelMap[newCoords.x][newCoords.y].temp = pixel.temp;
}
}
else {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
newPixel = pixelMap[newCoords.x][newCoords.y];
if (info.ignore && info.ignore.includes(newPixel.element)) {
continue;
}
if (newPixel.element != pixel.element && newPixel.element != "wire") {
pixel.clone = newPixel.element;
pixel.temp = newPixel.temp;
}
else if (newPixel.clone) {
pixel.clone = newPixel.clone;
pixel.temp = newPixel.temp;
}
}
}
}
else if (b=="SH") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
var con = elements[newPixel.element].conduct;
if (con != undefined) {
if (Math.random() < con) { // If random number is less than conductivity
if (!newPixel.charge && !newPixel.chargeCD) {
newPixel.charge = (parseFloat(arg) || 1);
if (elements[newPixel.element].colorOn) {
newPixel.color = pixelColorPick(newPixel);
}
}
}
}
}
}
//Stick
else if (b=="ST") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (newPixel.element != pixel.element && (arg == null || newPixel.element == arg)) {
var sticking = true
}
}
}
//Leave behind element
else if (b == "LB" || b == "L1" || b == "L2") {
if (arg != null && arg.includes(",")) {
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
}
if (elements[arg]) {
if (b=="LB") {leaveBehind = arg;}
else if (b=="L1") {leaveBehind1 = arg;}
else if (b=="L2") {leaveBehind2 = arg;}
}
}
//Change color
else if (b == "CC") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (arg == null) {arg = newPixel.colorObject}
else {
if (arg.includes(",")) {
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
}
if (!arg.startsWith("#")) {
arg = "#" + arg;
}
}
newPixel.color = pixelColorPick(newPixel,arg);
}
}
//Heat
else if (b == "HT") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
// if the element isn't the same or the coords ARE the same
if (!(newPixel.element == pixel.element) || (newCoords.x == pixel.x && newCoords.y == pixel.y)) {
if (arg != null) {arg = parseFloat(arg)}
else {arg = 1}
if (isNaN(arg)) {arg = 1}
newPixel.temp += arg;
pixelTempCheck(newPixel);
}
}
}
//Cool
else if (b == "CO") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (!(newPixel.element == pixel.element) || (newCoords.x == pixel.x && newCoords.y == pixel.y)) {
if (arg != null) {arg = parseFloat(arg)}
else {arg = 1}
if (isNaN(arg)) {arg = 1}
newPixel.temp -= arg;
pixelTempCheck(newPixel);
}
}
}
// Flip X
else if (b == "FX") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (elements[newPixel.element].flippableX) {
if (arg === "0") { newPixel.flipX = false; }
else if (arg === "1") { newPixel.flipX = true; }
newPixel.flipX = !newPixel.flipX;
}
}
}
// Flip Y
else if (b == "FY") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
if (elements[newPixel.element].flippableY) {
if (arg === "0") { newPixel.flipY = false; }
else if (arg === "1") { newPixel.flipY = true; }
else { newPixel.flipY = !newPixel.flipY; }
}
}
}
// Rotate
else if (b == "RT") {
if (!isEmpty(newCoords.x,newCoords.y,true)) {
var newPixel = pixelMap[newCoords.x][newCoords.y];
// If arg isn't null, set arg to a random choice from arg.split(",")
if (arg != null && arg.includes(",")) {
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
}
if (elements[newPixel.element].rotatable) {
newPixel.r = ((newPixel.r||0) + (parseInt(arg)||1)) % 4;
}
}
}
// Bounce
else if (b == "BO") {
if (!isEmpty(newCoords.x,newCoords.y)) {
if (info.flippableX) {
pixel.flipX = !pixel.flipX;
}
if (info.flippableY) {
pixel.flipY = !pixel.flipY;
}
if (info.rotatable) {
// If arg isn't null, set arg to a random choice from arg.split(",")
if (arg != null && arg.includes(",")) {
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
}
if (pixel.r !== undefined) {
pixel.r = (pixel.r + (parseInt(arg)||2)) % 4;
}
else { pixel.r = (parseInt(arg)||2); }
}
}
}
// Change When M2
else if (b == "C2") {
if (arg.includes(",")) {
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
}
var C2 = arg;
}
// Explode
else if (b == "EX") {
if (!isEmpty(newCoords.x,newCoords.y)) {
if (outOfBounds(newCoords.x,newCoords.y) || (newCoords.x == x && newCoords.y == y) || (pixel.element !== pixelMap[newCoords.x][newCoords.y].element && elements[pixelMap[newCoords.x][newCoords.y].element].state !== "gas")) {
// if arg contains ">", var fire = everything after it, arg = everything before it
if (arg.includes(">")) {
var fire = arg.split(">")[1];
arg = arg.split(">")[0];
}
else { var fire = "fire" }
// arg = a number
if (arg != null) {
arg = parseInt(arg);
if (isNaN(arg)) {arg = 3}
}
else {arg = 3}
explodeAt(x,y,arg,fire);
if (!pixel.del && info.hardness !== 1) {
deletePixel(x,y);
var deleted = true;
}
swapSpots = [];
}
}
}
}
}
}
}
if (typeof deleted !== "undefined") {return;}
if (supportSpots.length > 0) {
var supportCount = 0;
var allEmpty = true;
for (var i = 0; i < supportSpots.length; i++) {
var bx = supportSpots[i].x;
var by = supportSpots[i].y;
var arg = supportSpots[i].arg;
if (!isEmpty(bx,by,true)) {
if ((arg == null && !validDensitySwaps.includes(info.state+">"+elements[pixelMap[bx][by].element].state)) || pixelMap[bx][by].element == arg) {
supportCount++;
}
}
}
if (supportCount == supportSpots.length) {
move = false;
}
}
var moved = false;
if (swapSpots.length > 0) {
var coords = swapSpots[Math.floor(Math.random()*swapSpots.length)];
if (pixelMap[coords.x][coords.y] != undefined) {
swapPixels(pixel,pixelMap[coords.x][coords.y]);
move = false;
moved = true;
}
}
if (typeof sticking !== "undefined") {
move = false;
}
// Move First Priority
if (move) {
if (move1Spots.length > 0) {
// While move1Spots is not empty
while (move1Spots.length > 0) {
// coords = random item of move1Spots
var coords = move1Spots[Math.floor(Math.random()*move1Spots.length)];
var nx = coords.x;
var ny = coords.y;
moved = tryMove(pixel,nx,ny,leaveBehind1 || leaveBehind);
if (moved) {
break;
}
else {
// remove coords from move1Spots
move1Spots.splice(move1Spots.indexOf(coords),1);
}
}
}
// Move Second Priority
if (!moved && move2Spots.length > 0) {
// While move2Spots is not empty
while (move2Spots.length > 0) {
// coords = random item of move2Spots
var coords = move2Spots[Math.floor(Math.random()*move2Spots.length)];
var nx = coords.x;
var ny = coords.y;
moved = tryMove(pixel,nx,ny,leaveBehind2 || leaveBehind);
if (moved) {
if (typeof C2 !== "undefined" && elements[C2]) {
changePixel(pixel,C2);
}
break;
}
else {
// remove coords from move2Spots
move2Spots.splice(move2Spots.indexOf(coords),1);
}
}
}
}
// Change tempearture if needed (unused)
/*if (info.tempChange != undefined) {
pixel.temp += info.tempChange;
pixelTempCheck(pixel);
}*/
// Burning
doBurning(pixel);
// Heat Transfer
if (info.insulate != true) {
doHeat(pixel);
}
// Electricity Transfer
doElectricity(pixel);
// Staining
if (info.stain) {
doStaining(pixel);
}
}
function doBurning(pixel) {
if (pixel.burning) { // Burning
var info = elements[pixel.element];
pixel.temp += 1;
pixelTempCheck(pixel);
var burnSpots = [
{x:pixel.x+1,y:pixel.y},
{x:pixel.x-1,y:pixel.y},
{x:pixel.x,y:pixel.y+1},
{x:pixel.x,y:pixel.y-1},
];
// loop through burnspots
for (var i = 0; i < burnSpots.length; i++) {
var burnSpot = burnSpots[i];
if (!isEmpty(burnSpot.x,burnSpot.y,true)) {
var newPixel = pixelMap[burnSpot.x][burnSpot.y];
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;
if (burnInto == undefined) {
burnInto = 'fire';
}
else if (burnInto instanceof Array) {
burnInto = burnInto[Math.floor(Math.random()*burnInto.length)];
}
changePixel(pixel,burnInto);
if (info.fireColor != undefined && burnInto == "fire") {
pixel.color = pixelColorPick(pixel,info.fireColor);
}
else {
pixel.color = pixelColorPick(pixel)
}
}
else if (pixel.element != "fire" && isEmpty(pixel.x,pixel.y-1) && Math.floor(Math.random()*100)<10) {
createPixel("fire",pixel.x,pixel.y-1);
pixelMap[pixel.x][pixel.y-1].temp = pixel.temp//+(pixelTicks - (pixel.burnStart || 0));
if (info.fireColor != undefined) {
pixelMap[pixel.x][pixel.y-1].color = pixelColorPick(pixelMap[pixel.x][pixel.y-1],info.fireColor);
}
}
}
}
function doHeat(pixel) {
// Check right and bottom adjacent pixels
var coordsToCheck = [
{x:pixel.x+1,y:pixel.y},
{x:pixel.x,y:pixel.y+1},
];
for (var i = 0; i < coordsToCheck.length; i++) {
var coords = coordsToCheck[i];
if (!isEmpty(coords.x,coords.y,true)) {
var newPixel = pixelMap[coords.x][coords.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 doElectricity(pixel) {
if (pixel.charge) {
// Check each adjacent pixel, if that pixel's charge is false, set it to the same charge
var coordsToCheck = [
{x:pixel.x+1,y:pixel.y},
{x:pixel.x-1,y:pixel.y},
{x:pixel.x,y:pixel.y+1},
{x:pixel.x,y:pixel.y-1},
];
for (var i = 0; i < coordsToCheck.length; i++) {
var coords = coordsToCheck[i];
if (!isEmpty(coords.x,coords.y,true)) {
var newPixel = pixelMap[coords.x][coords.y];
var con = elements[newPixel.element].conduct;
if (con == undefined) {continue}
if (Math.random() < con) { // If random number is less than conductivity
if (!newPixel.charge && !newPixel.chargeCD) {
newPixel.charge = 1;
if (elements[newPixel.element].colorOn) {
newPixel.color = pixelColorPick(newPixel);
}
}
}
else if (elements[newPixel.element].insulate != true) { // Otherwise heat the pixel (Resistance simulation)
newPixel.temp += pixel.charge/4;
pixelTempCheck(newPixel);
}
}
}
pixel.charge -= 0.25;
if (pixel.charge <= 0) {
delete pixel.charge;
pixel.chargeCD = 4;
if (elements[pixel.element].colorOn) {
pixel.color = pixelColorPick(pixel);
}
}
}
// Lower charge cooldown
else if (pixel.chargeCD) {
pixel.chargeCD -= 1;
if (pixel.chargeCD <= 0) {
delete pixel.chargeCD;
}
}
}
function doStaining(pixel) {
if (settings["stainoff"]) { return }
var stain = elements[pixel.element].stain;
if (stain > 0) {
var newColor = pixel.color.match(/\d+/g);
}
else {
var newColor = null;
}
var coords = [
[pixel.x+1,pixel.y],
[pixel.x-1,pixel.y],
[pixel.x,pixel.y+1],
[pixel.x,pixel.y-1],
]
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];
if (!isEmpty(coord[0],coord[1],true)) {
var newPixel = pixelMap[coord[0]][coord[1]];
if ((newPixel.element != pixel.element || elements[newPixel.element].stainSelf) && (elements[newPixel.element].state == "solid" || !elements[newPixel.element].state || newPixel.element == pixel.element)) {
if (Math.random() < Math.abs(stain)) {
if (stain < 0) {
if (newPixel.origColor) {
newColor = newPixel.origColor.match(/\d+/g);
}
else { continue; }
}
else if (!newPixel.origColor) {
newPixel.origColor = newPixel.color;
}
// 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);
// get the average of rgb and newColor, more intense as stain reaches 1
var avg = [];
for (var j = 0; j < rgb.length; j++) {
avg.push(Math.floor((rgb[j]*(1-Math.abs(stain))) + (newColor[j]*Math.abs(stain))));
}
// set newPixel color to avg
newPixel.color = "rgb("+avg.join(",")+")";
}
}
}
}
}
function pixelColorPick(pixel,customColor=null) {
var element = pixel.element;
var elementInfo = elements[element];
//if (elementInfo.behavior instanceof Array) {
if (pixel.charge && elementInfo.colorOn) {
customColor = elementInfo.colorOn;
}
if (customColor != null) {
if (Array.isArray(customColor)) {
customColor = customColor[Math.floor(Math.random() * customColor.length)];
}
if (customColor.startsWith("#")) {
customColor = hexToRGB(customColor);
}
var rgb = customColor;
}
else {
var rgb = elements[element].colorObject; // {r, g, b}
// If rgb is an array, choose a random item
if (Array.isArray(rgb)) {
rgb = rgb[Math.floor(Math.random() * rgb.length)];
}
}
// Randomly darken or lighten the RGB color
var coloroffset = Math.floor(Math.random() * (Math.random() > 0.5 ? -1 : 1) * Math.random() * 15);
var r = rgb.r + coloroffset;
var g = rgb.g + coloroffset;
var b = rgb.b + coloroffset;
// Make sure the color is within the RGB range
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
var color = "rgb("+r+","+g+","+b+")";
/*}
else {
var color = elementInfo.color;
if (Array.isArray(color)) {
color = color[Math.floor(Math.random() * color.length)];
}
}*/
return color;
}
function pixelTempCheck(pixel) {
var elementInfo = elements[pixel.element];
if (pixel.temp < -273.15) { // Absolute Zero
pixel.temp = -273.15;
}
// If the pixel's temp >= the elementInfo tempHigh, change pixel.element to elementInfo.stateHigh
if (pixel.temp >= elementInfo.tempHigh) {
var result = elementInfo.stateHigh;
// If result is an array, choose a random item
if (Array.isArray(result)) {
result = result[Math.floor(Math.random() * result.length)];
}
if (result === null) {deletePixel(pixel.x,pixel.y);}
else {
changePixel(pixel,result);
}
}
// If the pixel's temp <= the elementInfo tempLow, change pixel.element to elementInfo.stateLow
else if (pixel.temp <= elementInfo.tempLow) {
var result = elementInfo.stateLow;
// If result is an array, choose a random item
if (Array.isArray(result)) {
result = result[Math.floor(Math.random() * result.length)];
}
if (result === null) {deletePixel(pixel.x,pixel.y);}
else {
changePixel(pixel,result);
}
}
}
function getNeighbors(pixel) {
var neighbors = [];
var x = pixel.x;
var y = pixel.y;
if (!isEmpty(x-1,y,true)) { neighbors.push(pixelMap[x-1][y]); }
if (!isEmpty(x+1,y,true)) { neighbors.push(pixelMap[x+1][y]); }
if (!isEmpty(x,y-1,true)) { neighbors.push(pixelMap[x][y-1]); }
if (!isEmpty(x,y+1,true)) { neighbors.push(pixelMap[x][y+1]); }
return neighbors;
}
function circleCoords(x,y,radius) {
var coords = [];
for (var i = x - radius; i <= x + radius; i++) {
for (var j = y - radius; j <= y + radius; j++) {
if (Math.pow(i-x,2) + Math.pow(j-y,2) <= Math.pow(radius,2)) {
coords.push({x:i,y:j});
}
}
}
return coords;
}
function drawCirclePixels(x,y,radius) {
var coords = circleCoords(x,y,radius);
for (var i = 0; i < coords.length; i++) {
if (isEmpty(coords[i].x,coords[i].y)) {
createPixel(currentElement,coords[i].x,coords[i].y);
}
}
}
// pixelMap is a 2D array of pixels.
// function to get a new 2D array of pixels from a rectangular area
function selection(x1,y1,x2,y2) {
var selection = [];
for (var i = x1; i <= x2; i++) {
selection[i] = [];
for (var j = y1; j <= y2; j++) {
selection[i][j] = pixelMap[i][j];
}
}
return selection;
}
unicodeSkips = {
0: 65, // null -> 0
58: 65, // : -> A
91: 97, // [ -> a
123: 192, // { -> À
215: 216, // × -> Ø
247: 248, // ÷ -> ø
688: 880,
884: 886,
888: 891,
894: 895,
896: 902,
903: 904,
907: 908,
909: 910,
930: 931,
1155: 1162,
1328: 1329,
1367: 1376,
1417: 1488,
1514: 12448,
12544: 13312
};
// version;codes;pixels;
function generateSave(pixelarray=null) {
if (pixelarray == null) {
pixelarray = pixelMap;
}
var n = 65;
var codes = "";
var codelist = {" ":" "};
var save = "";
// Add char*the number of consecutive pixels with the same element
var lastelem = "";
var samecount = 0;
for (var i = 0; i < pixelarray.length; i++) {
for (var j = 0; j < pixelarray[i].length; j++) {
var pixel = pixelarray[i][j];
if (pixel) {
if (codelist[pixel.element] == undefined) {
var char = String.fromCharCode(n);
codelist[pixel.element] = char;
codes += char+"="+pixel.element+",";
n++;
}
if (pixel.element == lastelem) {
samecount++;
}
else {
if (samecount > 0) {
save += codelist[lastelem]+"*"+samecount;
}
samecount = 1;
lastelem = pixel.element;
}
}
else {
// use " " for empty pixels
if (lastelem == " ") {
samecount++;
}
else {
if (samecount > 0) {
save += codelist[lastelem]+"*"+samecount
}
samecount = 1;
lastelem = " ";
}
}
}
save += "|";
}
// save = codes(without the last character) + save
save = codes.slice(0,-1)+";"+save;
return save;
}
function explodeAt(x,y,radius,fire="fire") {
// if fire contains , split it into an array
if (fire.includes(",")) {
fire = fire.split(",");
}
var coords = circleCoords(x,y,radius);
var power = radius/10;
//for (var p = 0; p < Math.round(radius/10+1); p++) {
for (var i = 0; i < coords.length; i++) {
// 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) {
createPixel("smoke",coords[i].x,coords[i].y);
}
else {
// if fire is an array, choose a random item
if (Array.isArray(fire)) {
createPixel(fire[Math.floor(Math.random() * fire.length)],coords[i].x,coords[i].y);
}
else {
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 (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.25) {
if (info.breakInto) {
// if it is an array, choose a random item, else just use the value
if (Array.isArray(info.breakInto)) {
var result = info.breakInto[Math.floor(Math.random() * info.breakInto.length)];
}
else {
var result = info.breakInto;
}
// change the pixel to the result
changePixel(pixel,result)
}
else {
if (Array.isArray(fire)) {
var newfire = fire[Math.floor(Math.random() * fire.length)];
}
else {
var newfire = fire;
}
changePixel(pixel,newfire)
}
}
if (damage > 0.75) {
if (info.burn) {
pixel.burning = true;
pixel.burnStart = pixelTicks;
}
}
pixel.temp += damage*radius*power;
pixelTempCheck(pixel);
}
}
}
function drawPixels(forceTick=false) {
// newCurrentPixels = shuffled currentPixels
var newCurrentPixels = currentPixels.slice();
newCurrentPixels.sort(function() {return 0.5 - Math.random()});
for (var i = 0; i < newCurrentPixels.length; i++) {
pixel = newCurrentPixels[i];
//if (pixelMap[pixel.x][pixel.y] == undefined || currentPixels.indexOf(pixel) == -1) {continue}
if (pixel.del) {continue}
if ((!paused) || forceTick) {
if (elements[pixel.element].tick) { // Run tick function if it exists
elements[pixel.element].tick(pixel);
}
if (elements[pixel.element].behavior) { // Parse behavior if it exists
pixelTick(pixel);
}
};
}
// Draw the current pixels
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
for (var i = 0; i < newCurrentPixels.length; i++) {
pixel = newCurrentPixels[i];
if (pixelMap[pixel.x][pixel.y] == undefined) {continue}
if (view===null) {
ctx.fillStyle = pixel.color;
}
else if (view === "thermal") {
// set the color to pixel.temp, from hottest at 0 hue to coldest 225 hue, with the minimum being -273, max being 6000
var temp = pixel.temp;
if (temp < -273) {temp = -273}
if (temp > 6000) {temp = 6000}
var hue = 225 - (temp/6000)*225;
if (hue < 0) {hue = 0}
if (hue > 225) {hue = 225}
ctx.fillStyle = "hsl("+hue+",100%,50%)";
}
ctx.fillRect(pixel.x*pixelSize, pixel.y*pixelSize, pixelSize, pixelSize);
if (pixel.charge) { // Yellow glow on charge
if (!elements[pixel.element].colorOn) {
ctx.fillStyle = "rgba(255,255,0,0.5)";
ctx.fillRect(pixel.x*pixelSize, pixel.y*pixelSize, pixelSize, pixelSize);
}
}
}
if ((!paused) || forceTick) {pixelTicks++};
}
function tick() {
// If mouseIsDown, do mouseAction
if (mouseIsDown) {
mouseAction(null,mousePos.x,mousePos.y);
}
// Get the canvas
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
// Clear the canvas
if (!settings["bg"]) {ctx.clearRect(0, 0, canvas.width, canvas.height)}
else {
ctx.fillStyle = settings["bg"];
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
drawPixels();
if (currentElement == "pick" || currentElement == "lookup") {
var mouseOffset = 0;
}
else {
var mouseOffset = Math.trunc(mouseSize/2);
}
var topLeft = [mousePos.x-mouseOffset,mousePos.y-mouseOffset];
var bottomRight = [mousePos.x+mouseOffset,mousePos.y+mouseOffset];
// Draw a rectangle around the mouse
ctx.strokeStyle = "white";
ctx.strokeRect(topLeft[0]*pixelSize,topLeft[1]*pixelSize,(bottomRight[0]-topLeft[0]+1)*pixelSize,(bottomRight[1]-topLeft[1]+1)*pixelSize);
updateStats();
//ticks ++;
}
currentElement = "sand";
currentColor = "#ff0000";
mouseIsDown = false;
mouseType = null;
function mouseClick(e) {
mouseIsDown = true;
// If it's a left click
if (e.button == 0) {
mouseType = "left";
}
else if (e.button == 2) {
mouseType = "right";
}
// middle click
else if (e.button == 1) {
mouseType = "middle";
}
else {
mouseType = "left";
}
mouseMove(e);
return false;
}
function mouseUp(e) {
mouseIsDown = false;
}
function getMousePos(canvas, evt) {
// If evt.touches is defined, use the first touch
if (evt.touches) {
evt.preventDefault();
evt = evt.touches[0];
}
var rect = canvas.getBoundingClientRect();
return {
// Round to nearest pixel
x: Math.round((evt.clientX - rect.left)/pixelSize-0.5),
y: Math.round((evt.clientY - rect.top)/pixelSize-0.5)
};
}
function mouseMove(e) {
if (mouseIsDown) {
mouseAction(e);
}
else {
var canvas = document.getElementById("game");
mousePos = getMousePos(canvas, e);
}
}
function mouseAction(e,mouseX=undefined,mouseY=undefined) {
if (showingMenu && currentElement != "lookup") {
closeMenu();
}
if (mouseType == "left") { mouse1Action(e,mouseX,mouseY); }
else if (mouseType == "right") { mouse2Action(e,mouseX,mouseY); }
else if (mouseType == "middle") { mouseMiddleAction(e,mouseX,mouseY); }
}
mouseSize = 5;
mousePos = {x:0,y:0};
function mouseRange(mouseX,mouseY) {
var coords = [];
var mouseOffset = Math.trunc(mouseSize/2);
var topLeft = [mouseX-mouseOffset,mouseY-mouseOffset];
var bottomRight = [mouseX+mouseOffset,mouseY+mouseOffset];
// Starting at the top left, go through each pixel
for (var x = topLeft[0]; x <= bottomRight[0]; x++) {
for (var y = topLeft[1]; y <= bottomRight[1]; y++) {
// If the pixel is empty, add it to coords
coords.push([x,y]);
}
}
return coords;
}
function mouse1Action(e,mouseX=undefined,mouseY=undefined) {
if (currentElement == "erase") { mouse2Action(e,mouseX,mouseY); return; }
else if (currentElement == "pick") { mouseMiddleAction(e,mouseX,mouseY); return; }
// If x and y are undefined, get the mouse position
if (mouseX == undefined && mouseY == undefined) {
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
mousePos = getMousePos(canvas, e);
var mouseX = mousePos.x;
var mouseY = mousePos.y;
}
if (currentElement == "lookup") {
if (!isEmpty(mouseX,mouseY,true)) {
showInfo(pixelMap[mouseX][mouseY].element);
}
return;
}
var coords = mouseRange(mouseX,mouseY);
var element = elements[currentElement];
var mixList = [];
// For each x,y in coords
for (var i = 0; i < coords.length; i++) {
var x = coords[i][0];
var y = coords[i][1];
// If element name is heat or cool
if (currentElement == "heat" || currentElement == "cool") {
if (!isEmpty(x,y,false)) {
if (outOfBounds(x,y)) {
continue;
}
var pixel = pixelMap[x][y];
if (shiftDown) {pixel.temp += element.temp+(Math.random()*element.temp*1.5)*20;}
else {pixel.temp += element.temp+(Math.random()*element.temp*1.5);}
pixelTempCheck(pixel);
}
}
else if (currentElement == "mix") {
if (!isEmpty(x,y,true)) {
var pixel = pixelMap[x][y];
if ((pixel.element != "fire" && pixel.element != "smoke") || shiftDown) {
mixList.push(pixel);
}
}
}
else if (currentElement == "shock") {
if (!isEmpty(x,y,true)) {
// One loop that repeats 5 times if shiftDown else 1 time
for (var j = 0; j < (shiftDown ? 5 : 1); j++) {
var pixel = pixelMap[x][y];
var con = elements[pixel.element].conduct;
if (con == undefined) {continue}
if (Math.random() < con) { // If random number is less than conductivity
if (!pixel.charge && !pixel.chargeCD) {
pixel.charge = 1;
if (elements[pixel.element].colorOn) {
pixel.color = pixelColorPick(pixel);
}
}
}
else if (elements[pixel.element].insulate != true) { // Otherwise heat the pixel (Resistance simulation)
pixel.temp += 0.25;
pixelTempCheck(pixel);
}
}
}
}
else if (currentElement == "random" && isEmpty(x, y)) {
// create pixel with random element from "randomChoices" array
currentPixels.push(new Pixel(x, y, randomChoices[Math.floor(Math.random() * randomChoices.length)]));
}
else if (elements[currentElement].tool) {
// run the tool function on the pixel
if (!isEmpty(x,y,true)) {
var pixel = pixelMap[x][y];
elements[currentElement].tool(pixel);
}
}
else if (mode == "replace") {
if (outOfBounds(x,y)) {
continue;
}
// Remove pixel at position from currentPixels
var index = currentPixels.indexOf(pixelMap[x][y]);
if (index > -1) {
currentPixels.splice(index, 1);
}
if (currentElement == "random") {
currentPixels.push(new Pixel(x, y, randomChoices[Math.floor(Math.random() * randomChoices.length)]));
}
else {
currentPixels.push(new Pixel(x, y, currentElement));
}
}
else if (isEmpty(x, y)) {
currentPixels.push(new Pixel(x, y, currentElement));
if (elements[currentElement].customColor) {
pixelMap[x][y].color = pixelColorPick(currentElement,currentColor);
}
}
}
if (currentElement == "mix") {
// 1. repeat for each pixel in mixList
// 2. choose 2 random pixels and swap their x and y
// 3. remove pixel from mixList
for (var i = 0; i < mixList.length; i++) {
var pixel1 = mixList[Math.floor(Math.random()*mixList.length)];
var pixel2 = mixList[Math.floor(Math.random()*mixList.length)];
swapPixels(pixel1,pixel2);
mixList.splice(mixList.indexOf(pixel1),1);
mixList.splice(mixList.indexOf(pixel2),1);
}
}
}
function mouse2Action(e,mouseX=undefined,mouseY=undefined) {
// Erase pixel at mouse position
if (mouseX == undefined && mouseY == undefined) {
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
mousePos = getMousePos(canvas, e);
var mouseX = mousePos.x;
var mouseY = mousePos.y;
}
// If the current element is "pick" or "lookup", coords = [mouseX,mouseY]
if (currentElement == "pick" || currentElement == "lookup") {
var coords = [[mouseX,mouseY]];
}
else {
var coords = mouseRange(mouseX,mouseY);
}
// For each x,y in coords
for (var i = 0; i < coords.length; i++) {
var x = coords[i][0];
var y = coords[i][1];
if (!isEmpty(x, y)) {
if (outOfBounds(x,y)) {
continue
}
var pixel = pixelMap[x][y];
delete pixelMap[x][y];
// Remove pixel from currentPixels
for (var j = 0; j < currentPixels.length; j++) {
if (currentPixels[j].x == x && currentPixels[j].y == y) {
currentPixels.splice(j, 1);
break;
}
}
}
}
}
function mouseMiddleAction(e, mouseX=undefined, mouseY=undefined) {
if (mouseX == undefined && mouseY == undefined) {
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
mousePos = getMousePos(canvas, e);
var mouseX = mousePos.x;
var mouseY = mousePos.y;
}
if (!isEmpty(mouseX, mouseY,true)) {
selectElement(pixelMap[mouseX][mouseY].element);
mouseIsDown = false;
}
}
function wheelHandle(e) {
e.preventDefault();
var deltaY = e.deltaY*0.1;
if (Math.round(deltaY) == 0) {
if (deltaY > 0) { deltaY = 1; }
else { deltaY = -1; }
}
mouseSize += Math.round(deltaY*2);
if (mouseSize < 1) { mouseSize = 1; }
if (mouseSize > (height > width ? height : width)) { mouseSize = (height > width ? height : width); }
}
function chooseElementPrompt() {
var e = prompt("Enter the element's ID")
if (elements[e] != undefined) {
e = e.replace(/ /g,"_");
selectElement(e);
var btn = document.getElementById("elementButton-"+e);
if (btn != null) {
btn.setAttribute("current","true");
}
};
}
function togglePause() {
paused = !paused;
if (paused) {
document.getElementById("pauseButton").setAttribute("on","true");
}
else {
document.getElementById("pauseButton").setAttribute("on","false");
}
}
function doFrame() {
if (!paused) {
paused = true;
document.getElementById("pauseButton").setAttribute("on","true");
}
drawPixels(true);
}
function selectElement(element) {
var e1 = document.getElementById("elementButton-"+currentElement);
if (e1 != null) { e1.setAttribute("current","false"); }
currentElement = element;
var e2 = document.getElementById("elementButton-"+element);
if (e2 != null) { e2.setAttribute("current","true"); }
if (elements[element].customColor) {
// show the colorSelector
document.getElementById("colorSelector").style.display = "block";
}
else {
// hide the colorSelector
document.getElementById("colorSelector").style.display = "none";
}
}
function selectCategory(category) {
var categoryButton = document.getElementById("categoryButton-"+category);
var categoryDiv = document.getElementById("category-"+category);
// Show this categoryDiv and hide all others
for (var i = 0; i < categoryButton.parentNode.children.length; i++) {
var e = categoryDiv.parentNode.children[i];
e.style.display = "none";
// Set the categoryButton of categoryDiv's category attribute to current=false
document.getElementById("categoryButton-"+e.getAttribute("category")).setAttribute("current",false);
}
categoryDiv.style.display = "block";
categoryButton.setAttribute("current", true);
}
function setView(n) {
// 2 for thermal
if (n == 2) {
view = "thermal";
}
else { // reset view
view = null;
}
}
worldgentypes = {
// layers: [minimum y from bottom, element, chance per pixel]
"grass": {
layers: [
[0.85, "grass"],
[0.50, "dirt"],
[0.05, "rock"],
[0, "basalt"],
]
},
"dirt": {
layers: [
[0.50, "dirt"],
[0.05, "rock"],
[0, "basalt"],
]
},
"forest": {
layers: [
[0.85, "sapling", 0.1],
[0.85, "grass"],
[0.50, "dirt"],
[0.05, "rock"],
[0, "basalt"],
],
baseHeight: 0.25,
},
"jungle": {
layers: [
[0.85, "sapling", 0.1],
[0.85, "grass"],
[0.50, "mud"],
[0.05, "gravel"],
[0, "basalt"],
],
baseHeight: 0.25,
},
"ocean": {
layers: [
[0.9, "fish", 0.1],
[0.9, "snail", 0.01],
[0.9, "algae", 0.4],
[0.25, "water"],
[0.1, "clay", 0.1],
[0.1, "gravel", 0.2],
[0.1, "wet_sand"],
[0.03, "gravel", 0.5],
[0.03, "rock"],
[0, "basalt"],
]
},
"rock": {
layers: [
[0, "rock"],
],
baseHeight: 0.33
},
"volcanic": {
layers: [
[0.3, "basalt"],
[0.2, "basalt", 0.5],
[0, "magma"]
],
baseHeight: 0.4,
temperature: 950
},
"desert": {
layers: [
[0.65, "sand"],
[0.55, "bone", 0.03],
[0.50, "dirt"],
[0.05, "rock"],
[0, "basalt"],
],
temperature: 38,
},
};
function clearAll() {
currentPixels = [];
pixelMap = [];
for (var i = 0; i < width; i++) {
pixelMap[i] = [];
for (var j = 0; j < height; j++) {
pixelMap[i][j] = undefined;
}
}
pixelTicks = 0;
if (settings["worldgen"] && settings["worldgen"] != "off") {
worldGen(worldgentypes[settings["worldgen"]]);
}
}
function mean(arr) {
var sum = 0;
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum/arr.length;
}
function generateTerrainHeights(width,heightVariance,complexity) {
// array of (width) 0s
var newHeights = [];
for (var i = 0; i < width; i++) {
newHeights[i] = 0;
}
// do midpoint displacement (complexity) times on newHeights
for (var i = 0; i < complexity; i++) {
var newHeights2 = [];
for (var j = 0; j < width; j++) {
newHeights2[j] = 0;
}
for (var j = 0; j < width; j++) {
var x = j;
var y = newHeights[j];
var y2 = y + Math.random()*heightVariance - heightVariance/2;
newHeights2[x] = y2;
}
newHeights = newHeights2;
}
return newHeights;
}
function worldGen(worldtype) {
var complexity = worldtype.complexity || 20;
var heightVariance = worldtype.heightVariance || 0.5;
var baseHeight = height-(height*(worldtype.baseHeight || 0.5));
var layers = worldtype.layers || {0:"rock"};
var yoffsets = generateTerrainHeights(width,heightVariance,complexity);
// 2D world vertical generator
for (var x = 1; x < width; x++) {
var yoffset = yoffsets[x];
var worldHeight = baseHeight+yoffset;
for (var y = 0; y < height; y++) {
// Change element type based on y, from grass > dirt > rock > basalt
if (y > worldHeight) {
// distance from the bottom of worldHeight
var frombottom = worldHeight-(y-worldHeight);
var element = null;
for (var i in layers) {
var layer = layers[i];
if (layer[0] == 0 && yoffset < 0) {
layer[0] = yoffset;
}
if (frombottom > worldHeight*layer[0] && Math.random() < (layer[2] || 1)) {
if (elements[layer[1]]) {
element = layer[1];
break
}
}
}
if (element) {
createPixel(element,x,y);
if (worldtype.temperature) {
pixelMap[x][y].temp = worldtype.temperature;
}
}
}
}
}
}
// Update stats
function updateStats() {
var statsDiv = document.getElementById("stats");
var stats = "<span id='stat-pos' class='stat'>x"+mousePos.x+",y"+mousePos.y+"</span>";
stats += "<span id='stat-pixels' class='stat'>Pxls:" + currentPixels.length+"</span>";
stats += "<span id='stat-tps' class='stat'>" + tps+"tps</span>";
stats += "<span id='stat-ticks' class='stat'>" + pixelTicks+"</span>";
if (typeof pixelMap == 'undefined') { return; }
if (pixelMap[mousePos.x] != undefined) {
var currentPixel = pixelMap[mousePos.x][mousePos.y];
if (currentPixel != undefined) {
stats += "<span id='stat-element' class='stat'>Elem:"+(elements[currentPixel.element].name || currentPixel.element).toUpperCase()+"</span>";
stats += "<span id='stat-temperature' class='stat'>Temp:"+formatTemp(currentPixel.temp)+"</span>";
if (currentPixel.charge) {
stats += "<span id='stat-charge' class='stat'>C"+currentPixel.charge+"</span>";
}
if (currentPixel.burning) {
stats += "<span id='stat-burning' class='stat'>Burning</span>";
}
}
}
if (shiftDown) {
if (shiftDown==1) {stats += "<span id='stat-shift' class='stat'>[↑ ]</span>";}
else if (shiftDown==2) {stats += "<span id='stat-shift' class='stat'>[A ]</span>";}
else if (shiftDown==3) {stats += "<span id='stat-shift' class='stat'>[ ↑]</span>";}
else if (shiftDown==4) {stats += "<span id='stat-shift' class='stat'>[ A]</span>";}
}
// If the view is not null, show the view in all caps
if (view != null) {
stats += "<span id='stat-view' class='stat'>"+view.toUpperCase()+"</span>";
}
statsDiv.innerHTML = stats;
}
function formatTemp(temp) { // temp is Celcius
if (!settings["units"] || settings["units"] === "m") { // Celsius
return Math.round(temp)+"°C"
}
else if (settings["units"] === "i") { // Fahrenheit
return Math.round(temp*1.8+32)+"°F"
}
else if (settings["units"] === "s") { // Kelvin
return Math.round(temp+273.15)+"K"
}
}
function formatDensity(density) { // temp is kg/m3
// default/metric = kg/m3, imperial = lb/ft3, si = g/cm3
if (!settings["units"] || settings["units"] === "m") { // kg/m3
return Math.round(density)+" kgm<sup>3</sup>"
}
else if (settings["units"] === "i") { // lb/ft3
return Math.round(density/16.018)+" lbft<sup>3</sup>"
}
else if (settings["units"] === "s") { // g/cm3
// round to 2 decimal places
return Math.round(density/10)/100+" gcm<sup>3</sup>"
}
}
showingMenu = false;
function infoLink(l) {
if (l instanceof Array) {
var newtext = "";
for (var i = 0; i < l.length; i++) {
var element = l[i];
// add to newtext a span with the element's name and its onclick to showInfo(element)
if (element=="pixels" || element=="itself") { newtext += element+", "}
else { newtext += "<span class='infoLink' onclick='showInfo(\""+element+"\")'>"+(elements[element].name || element).toUpperCase().replace(/_/g," ")+"</span>, ";}
}
// remove the last comma and space
newtext = newtext.substring(0, newtext.length-2);
return newtext
}
else {
if (l=="pixels" || l=="[???]" || l=="itself") {return l}
else {return "<span class='infoLink' onclick='showInfo(\""+l+"\")'>"+l.toUpperCase().replace(/_/g," ")+"</span>";}
}
}
function showInfo(element) { // this is such a mess please don't look at it
showingMenu = "info";
var infoParent = document.getElementById("infoParent");
infoParent.style.display = "block";
var infoSearch = document.getElementById("infoSearch");
infoSearch.focus();
var infoTitle = document.getElementById("infoTitle");
var infoText = document.getElementById("infoText");
if (element != undefined) {
// replace all spaces with underscores
element = element.replace(/ /g,"_");
infoSearch.value = element;
info = elements[element];
if (info) {
infoTitle.innerHTML = info.name || element.replace(/_/g," ");
infoTitle.innerHTML = infoTitle.innerHTML.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
infoText.innerHTML = "";
infoSearch.style.backgroundColor = "rgb(66, 66, 66)";
if (info.color) {
if (!(info.color instanceof Array)) {
infoText.innerHTML += "\nColor: <span style='background-color:"+info.color+"'> </span>";
}
else {
//gradient
var gradient = info.color;
var gradientString = "linear-gradient(to right";
for (var i = 0; i < gradient.length; i++) {
gradientString += ", "+gradient[i]+" "+(i*100/gradient.length)+"%";
}
gradientString += ")";
infoText.innerHTML += "\nColor: <span style='background:"+gradientString+"'> </span>";
}
}
if (info.desc) {
infoText.innerHTML += "\n"+info.desc;
}
else if (info.extraInfo) {
infoText.innerHTML += "\n"+info.extraInfo;
}
var moves = false;
var deletes = [];
var swaps = [];
var creates = [];
var heats = false;
var cools = false;
var clones = false;
var explodes = false;
var sticks = [];
if (info.behavior) {
// for x and y in behavior array
for (var i = 0; i < info.behavior.length; i++) {
for (var j = 0; j < info.behavior[i][1].length; j++) {
var b0 = info.behavior[i][j];
if (!b0) { continue; }
for (var k = 0; k < b0.split(" AND ").length; k++) {
var b = b0.split(" AND ")[k];
// remove everything after %
b = b.split("%")[0];
if (b.indexOf(":") != -1) {
var arg = b.split(":")[1];
}
else { var arg = undefined }
var b = b.split(":")[0];
if (b == "M1" || b == "M2") {
moves = true;
}
else if (b == "DL") {
if (i==1 && j==1) { arg = "itself" }
else if (!arg) { arg = "pixels" }
if (deletes.indexOf(arg) == -1) { deletes = deletes.concat(arg.split(",")); }
}
else if (b == "SW") {
if (!arg) { arg = "pixels" }
if (swaps.indexOf(arg) == -1) { swaps = swaps.concat(arg.split(",")); }
}
else if (b == "CL") {
clones = true;
}
else if (b == "CR" || b == "CH" || b == "LB" || b == "L1" || b == "L2") {
if (!arg) { arg = "[???]" }
else if (arg.indexOf(">") != -1) { arg = arg.split(">")[1]; }
if (creates.indexOf(arg) == -1) { creates = creates.concat(arg.split(",")); }
}
else if (b == "HT") {
heats = true;
}
else if (b == "CO") {
cools = true;
}
else if (b == "ST") {
if (!arg) { arg = "pixels" }
if (sticks.indexOf(arg) == -1) { sticks = sticks.concat(arg.split(",")); }
}
else if (b == "EX") {
explodes = true;
}
}}}}
// make sure deletes, swaps, creates, and sticks have no duplicate items
deletes = deletes.filter(function(item, pos) {return deletes.indexOf(item) == pos;});
swaps = swaps.filter(function(item, pos) {return swaps.indexOf(item) == pos;});
creates = creates.filter(function(item, pos) {return creates.indexOf(item) == pos;});
sticks = sticks.filter(function(item, pos) {return sticks.indexOf(item) == pos;});
if (info.category == "tools" || info.tool) { infoText.innerHTML += "\nTool."}
else {
if (!moves && info.behavior) { infoText.innerHTML += "\nStationary."; }
if (info.category) { infoText.innerHTML += "\nCategory: "+info.category.toUpperCase()+"."; }
if (info.conduct) { infoText.innerHTML += "\nConducts electricity."; }
if (swaps.length > 0) { infoText.innerHTML += "\nMoves through "+infoLink(swaps)+"."; }
if (creates.length > 0) { infoText.innerHTML += "\nMakes "+infoLink(creates)+"."; }
if (clones) { infoText.innerHTML += "\nClones self." }
if (deletes.length > 0) { infoText.innerHTML += "\nDeletes "+infoLink(deletes)+"."; }
if (heats) { infoText.innerHTML += "\nHeats pixels." }
if (cools) { infoText.innerHTML += "\nCools pixels." }
if (sticks.length > 0) { infoText.innerHTML += "\nSticks to "+infoLink(sticks)+"."; }
if (explodes) { infoText.innerHTML += "\nExplodes." }
if (!settings["unhide"] && info.hidden) { infoText.innerHTML += "\nHidden from toolbar."; }
if (info.density != undefined) { infoText.innerHTML += "\nDensity: "+formatDensity(info.density)+"."; }
if (info.tempHigh != undefined) {
infoText.innerHTML += "\nTurns into "+infoLink(info.stateHigh || "[???]")+" above "+formatTemp(info.tempHigh)+".";
}
if (info.tempLow != undefined) {
infoText.innerHTML += "\nTurns into "+infoLink(info.stateLow || "[???]")+" below "+formatTemp(info.tempLow)+".";
}
if (info.burn != undefined) { infoText.innerHTML += "\nFlammability: "+info.burn+"%."; }
if (info.burnTime != undefined) {
infoText.innerHTML += "\nBurns for "+info.burnTime+" tick";
if (info.burnTime != 1) { infoText.innerHTML += "s"; }
infoText.innerHTML += ".";
}
if (info.burnInto) { infoText.innerHTML += "\nBurns into "+infoLink(info.burnInto)+"."; }
if (info.fireColor) {
if (!(info.fireColor instanceof Array)) {
infoText.innerHTML += "\nFlame Color: <span style='background-color:"+info.fireColor+"'> </span>";
}
else {
//gradient
var gradient = info.fireColor;
var gradientString = "linear-gradient(to right";
for (var i = 0; i < gradient.length; i++) {
gradientString += ", "+gradient[i]+" "+(i*100/gradient.length)+"%";
}
gradientString += ")";
infoText.innerHTML += "\nFlame Color: <span style='background:"+gradientString+"'> </span>";
}
}
if (info.breakInto) { infoText.innerHTML += "\nBreaks into "+infoLink(info.breakInto)+"."; }
if (info.stain) {
if (info.stain < 0) { infoText.innerHTML += "\nCleans stains."; }
else { infoText.innerHTML += "\nStains solids."; }
}
if (info.customColor) { infoText.innerHTML += "\nColor is customizable."; }
if (info.reactions) {
infoText.innerHTML += "\nReacts with " + infoLink(Object.keys(info.reactions)) + ".";
}
}
infoText.innerHTML += "\n\n\n\n"
}
else {
infoTitle.innerHTML = "";
infoText.innerHTML = "";
// infoSearch red background
infoSearch.style.backgroundColor = "rgb(100, 33, 33)";
}
}
else {
infoTitle.innerHTML = "";
infoText.innerHTML = "";
infoSearch.style.backgroundColor = "rgb(66, 66, 66)";
}
}
function closeMenu() {
if (!showingMenu) { return; }
if (showingMenu == "info") {
var infoParent = document.getElementById("infoParent");
var infoSearch = document.getElementById("infoSearch");
infoParent.style.display = "none";
infoSearch.value = "";
showingMenu = false;
}
else if (showingMenu == "mods") {
var modParent = document.getElementById("modParent");
var modManagerUrl = document.getElementById("modManagerUrl");
modParent.style.display = "none";
modManagerUrl.value = "";
showingMenu = false;
}
else if (showingMenu == "settings") {
var settingsParent = document.getElementById("settingsParent");
settingsParent.style.display = "none";
showingMenu = false;
}
}
function showModManager() {
var modParent = document.getElementById("modParent");
var modManagerUrl = document.getElementById("modManagerUrl");
modParent.style.display = "block";
modManagerUrl.focus();
showingMenu = "mods";
}
function addMod(url) {
// remove trailing slashes
while (url.charAt(url.length-1) == "/") { url = url.substring(0, url.length-1); }
// if the mod is in enabledMods, return
for (var i = 0; i < enabledMods.length; i++) {
if (enabledMods[i] == url) { return; }
}
// if the url doesn't have a slash or a dot, alert
if (url.indexOf("/") == -1 && url.indexOf(".") == -1) {
alert("Invalid mod URL.");
return;
}
// if the url doesn't start with http, add "mods/" to the beginning
if (url.indexOf("http") == -1) { url = "mods/"+url; }
// add it to enabledMods and set the localStorage
enabledMods.push(url);
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
// add to modManagerList
var modManagerList = document.getElementById("modManagerList");
var modName = url.split("/").pop();
modManagerList.innerHTML += "<li><a href='" + url + "' target='_blank'>" + modName + "</a> <span class='removeModX' onclick='removeMod(\"" + url + "\")'>X</span></li>";
alert("Added mod. Refresh the page to see changes.");
}
function removeMod(url) {
// remove url from enabledMods and set the localStorage
for (var i = 0; i < enabledMods.length; i++) {
if (enabledMods[i] == url) {
enabledMods.splice(i, 1);
break;
}
}
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
// remove from modManagerList by href
var modManagerList = document.getElementById("modManagerList");
var modManagerListLinks = modManagerList.getElementsByTagName("a");
for (var i = 0; i < modManagerListLinks.length; i++) {
if (modManagerListLinks[i].href.endsWith(url)) {
modManagerListLinks[i].parentNode.remove();
break;
}
}
alert("Removed mod. Refresh the page to see changes.");
}
function showSettings() {
var settingsParent = document.getElementById("settingsParent");
settingsParent.style.display = "block";
showingMenu = "settings";
}
function setSetting(setting,value) {
settings[setting] = value;
saveSettings();
}
// On window load, run tick() 20 times per second
tps = 30;
tickInterval = window.setInterval(tick, 1000/tps);
function resetInterval(newtps=30) {
window.clearInterval(tickInterval);
tickInterval = window.setInterval(tick, 1000/newtps);
}
//ticks = 0;
pixelTicks = 0;
mode = null;
view = null;
paused = false;
function focusGame() { document.getElementById("game").focus(); if(showingMenu) { closeMenu(); } }
//on window load
window.onload = function() {
// 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]();
}
// Loop through behaviors and each behavior, if it is a string, split the items and replace the value with the array
for (var behavior in behaviors) {
if (typeof behaviors[behavior][0] === "string") {
var newbehavior = [];
for (var i = 0; i < behaviors[behavior].length; i++) {
newbehavior.push(behaviors[behavior][i].split("|"));
}
behaviors[behavior] = newbehavior;
}
}
// convert every color in the elements object to rgb
for (var key in elements) {
if (elements.hasOwnProperty(key)) {
// if the element has no color, skip it
if (elements[key].color === undefined) {
continue;
}
// if the color is an array, loop over each one
if (elements[key].color instanceof Array) {
var rgbs = [];
var rgbos = [];
for (var i = 0; i < elements[key].color.length; i++) {
var c = elements[key].color[i];
if (c.startsWith("#")) {
var rgb = hexToRGB(c);
rgbs.push("rgb("+rgb.r+","+rgb.g+","+rgb.b+")");
rgbos.push(rgb);
}
else {
rgbs.push(c);
}
}
elements[key].color = rgbs;
elements[key].colorObject = rgbos;
} else {
// if elements[key].color starts with #
if (elements[key].color.startsWith("#")) {
var rgb = hexToRGB(elements[key].color);
elements[key].color = "rgb("+rgb.r+","+rgb.g+","+rgb.b+")";
elements[key].colorObject = rgb;
}
}
}
}
// Automatic molten element generation
// Loop through each element. If it has a tempHigh, but not a stateHigh, create a new molten element
for (element in elements) {
if (elements[element].tempHigh && elements[element].stateHigh===undefined) {
var newname = "molten_"+element;
elements[element].stateHigh = newname;
var newcolor = elements[element].colorObject;
var colorList = [];
var colorObjectList = [];
// if newcolor is not an array, put it in an array
if (!(newcolor instanceof Array)) {
newcolor = [newcolor];
}
// 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];
r = c.r * 2;
g = c.g * 1.25;
b = c.b * 0.5;
if (r > 255) {r = 255;}
if (g > 255) {g = 255;}
colorList.push("rgb("+r+","+g+","+b+")");
colorObjectList.push({r:r,g:g,b:b});
r = c.r * 2;
g = c.g;
b = c.b * 0.5;
if (r > 255) {r = 255;}
if (g > 255) {g = 255;}
colorList.push("rgb("+r+","+g+","+b+")");
colorObjectList.push({r:r,g:g,b:b});
r = c.r * 2;
g = c.g * 0.75;
b = 0;
if (r > 255) {r = 255;}
if (g > 255) {g = 255;}
colorList.push("rgb("+r+","+g+","+b+")");
colorObjectList.push({r:r,g:g,b:b});
}
var newmolten = {
//"name": newname.replaceAll("_"," "),
color: colorList,
colorObject: colorObjectList,
behavior: behaviors.MOLTEN,
temp: elements[element].tempHigh,
tempLow: elements[element].tempHigh-100,
stateLow: element,
viscosity: elements[element].viscosity || 10000,
hidden: true,
state: "liquid",
category: "molten",
}
// If the element has a density, add it to the new molten element * 0.9
if (elements[element].density) { newmolten.density = Math.round(elements[element].density * 0.9 * 10) / 10; }
// If the element has a conductivity, add it to the new molten element * 1.1
if (elements[element].conduct) { newmolten.conductivity = Math.round(elements[element].conduct * 1.1 * 10) / 10; }
// Same for burn, burnTime, burnInto, and fireColor
if (elements[element].burn) { newmolten.burn = Math.round(elements[element].burn * 1.1 * 10) / 10; }
if (elements[element].burnTime) { newmolten.burnTime = Math.round(elements[element].burnTime * 1.1 * 10) / 10; }
if (elements[element].burnInto) { newmolten.burnInto = elements[element].burnInto; }
if (elements[element].fireColor) { newmolten.fireColor = elements[element].fireColor; }
// If the new element doesn't exist, add it
if (!elements[newname]) { elements[newname] = newmolten; }
else {
// Loop through newmolten's keys and values, copy them to the new element if they are not already defined
for (var key in newmolten) {
if (elements[newname][key] == undefined) {
elements[newname][key] = newmolten[key];
}
}
}
// Slag reactions
// If the element doesn't have reactions, set it to {}
if (!elements[newname].reactions) {
elements[newname].reactions = {};
}
elements[newname].reactions.ash = { "elem1":null, "elem2":"molten_slag" };
elements[newname].reactions.dust = { "elem1":null, "elem2":"molten_slag" };
if (newname != "molten_slag") {elements[newname].reactions.magma = { "elem1":null, "elem2":"molten_slag" }};
}
if (elements[element].behavior && typeof elements[element].behavior[0] === "string") {
var newbehavior = [];
for (var i = 0; i < elements[element].behavior.length; i++) {
newbehavior.push(elements[element].behavior[i].split("|"));
}
elements[element].behavior = newbehavior;
}
if (elements[element].behaviorOn && typeof elements[element].behaviorOn[0] === "string") {
var newbehavior = [];
for (var i = 0; i < elements[element].behaviorOn.length; i++) {
newbehavior.push(elements[element].behaviorOn[i].split("|"));
}
elements[element].behaviorOn = newbehavior;
}
}
// Loop through each element, final checks
for (key in elements) {
// If the element has no behavior, set it to behaviors.WALL
if (!elements[key].behavior && !elements[key].tick) {
elements[key].tick = function(pixel) {};
}
// If the element has no color, set it to white
if (elements[key].color === undefined) {
elements[key].color = "rgb(255,255,255)";
elements[key].colorObject = {r:255,g:255,b:255};
}
if (elements[key].behavior) {
// If the element's behavior[1][1] includes "FX", set it's flippableX to true
if (elements[key].behavior[1][1].includes("FX")) {
elements[key].flippableX = true;
}
// If the element's behavior[1][1] includes "FY", set it's flippableY to true
if (elements[key].behavior[1][1].includes("FY")) {
elements[key].flippableY = true;
}
// If the element's behavior stringified includes "BO", loop through the behavior
if (elements[key].behavior.toString().includes("BO") && !elements[key].rotatable) {
for (var i = 0; i < elements[key].behavior.length; i++) {
// Loop through each array in the behavior
for (var j = 0; j < elements[key].behavior[i].length; j++) {
// If the behavior includes "BO", set the behaviorOn to the behavior
if (elements[key].behavior[i][j].includes("BO")) {
if ((i==0 && j==0) || (i==0 && j==2) || (i==2 && j==0) && (i==2 && j==2)) {
elements[key].flippableX = true;
elements[key].flippableY = true;
}
else if (i==0 || i==2) {
elements[key].flippableY = true;
}
else if (j==0 || j==2) {
elements[key].flippableX = true;
}
}
}
}
}
// If the element's behavior[1][1] includes "RT", set it's rotatable to "true"
if (elements[key].behavior[1][1].includes("RT")) {
elements[key].rotatable = true;
}
}
// If the element has reactions, loop through each one (it is an object), if the value for elem1 or elem2 is not an element and is not null, remove that key
if (elements[key].reactions) {
for (var reaction in elements[key].reactions) {
// If elem1 exists
if (elements[key].reactions[reaction].elem1) {
// If elem1 is an array, loop through each element, else check once. Don't delete if it === null
if (Array.isArray(elements[key].reactions[reaction].elem1)) {
for (var i = 0; i < elements[key].reactions[reaction].elem1.length; i++) {
if (elements[key].reactions[reaction].elem1[i] && !elements[elements[key].reactions[reaction].elem1[i]]) {
elements[key].reactions[reaction].elem1.splice(i,1);
}
}
}
else if (elements[key].reactions[reaction].elem1 && !elements[elements[key].reactions[reaction].elem1]) {
delete elements[key].reactions[reaction].elem1;
}
}
// If elem2 exists
if (elements[key].reactions[reaction].elem2) {
// If elem2 is an array, loop through each element, else check once. Don't delete if it === null
if (Array.isArray(elements[key].reactions[reaction].elem2)) {
for (var i = 0; i < elements[key].reactions[reaction].elem2.length; i++) {
if (elements[key].reactions[reaction].elem2[i] && !elements[elements[key].reactions[reaction].elem2[i]]) {
elements[key].reactions[reaction].elem2.splice(i,1);
}
}
}
else if (elements[key].reactions[reaction].elem2 && !elements[elements[key].reactions[reaction].elem2]) {
delete elements[key].reactions[reaction].elem2;
}
}
}
}
// If the element's stateHigh or stateLow is not an element, remove it and tempHigh/Low
if (elements[key].stateHigh) {
// If it's an array, do it for each item, otherwise, just do it once
if (Array.isArray(elements[key].stateHigh)) {
for (var i = 0; i < elements[key].stateHigh.length; i++) {
if (!elements[elements[key].stateHigh[i]] && elements[key].stateHigh[i] !== null) {
elements[key].stateHigh.splice(i,1);
}
}
if (elements[key].stateHigh.length == 0) {
delete elements[key].stateHigh;
delete elements[key].tempHigh;
}
}
else {
if (!elements[elements[key].stateHigh] && elements[key].stateHigh !== null) {
delete elements[key].stateHigh;
delete elements[key].tempHigh;
}
}
}
if (elements[key].stateLow) {
if (Array.isArray(elements[key].stateLow)) {
for (var i = 0; i < elements[key].stateLow.length; i++) {
if (!elements[elements[key].stateLow[i]] && elements[key].stateLow[i] !== null) {
elements[key].stateLow.splice(i,1);
}
}
if (elements[key].stateLow.length == 0) {
delete elements[key].stateLow;
delete elements[key].tempLow;
}
}
else {
if (!elements[elements[key].stateLow] && elements[key].stateLow !== null) {
delete elements[key].stateLow;
delete elements[key].tempLow;
}
}
}
// same for burnInto
if (elements[key].burnInto) {
if (Array.isArray(elements[key].burnInto)) {
for (var i = 0; i < elements[key].burnInto.length; i++) {
if (!elements[elements[key].burnInto[i]]) {
delete elements[key].burnInto[i];
}
}
if (elements[key].burnInto.length == 0) {
delete elements[key].burnInto;
}
}
else {
if (!elements[elements[key].burnInto]) {
delete elements[key].burnInto;
}
}
}
}
// 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
for (var key in worldgentypes) {
document.getElementById("worldgenselect").innerHTML += "<option value='" + key + "'>" + key.replace(/_/g, " ").replace(/\b\w/g, l => l.toUpperCase()) + "</option>";
}
if (settings["worldgen"] && !worldgentypes[settings["worldgen"]]) {
settings["worldgen"] = "off";
}
// 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.
var settingSpans = document.getElementsByClassName("setting-span");
for (var i = 0; i < settingSpans.length; i++) {
var setting = settingSpans[i].getAttribute("setting");
if (setting in settings) {
var settingValue = settings[setting];
var settingElements = settingSpans[i].getElementsByTagName("select") || settingSpans[i].getElementsByTagName("input");
if (settingElements.length > 0) {
settingElements[0].value = settingValue;
}
}
}
// While the mouse is down, run mouseDown()
var gameCanvas = document.getElementById("game");
// Get context
var ctx = gameCanvas.getContext("2d");
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 800, set it to 800
if (newWidth > 1000) { newWidth = 1000; }
// If we are on a desktop and the new height is greater than 600, set it to 600
if (window.innerWidth > 1000 && newHeight > 500) { newHeight = 500; }
ctx.canvas.width = newWidth;
ctx.canvas.height = newHeight;
width = Math.round(newWidth/pixelSize)-1;
height = Math.round(newHeight/pixelSize)-1;
if (settings["worldgen"]) {
clearAll();
}
else {
// Object with width arrays of pixels starting at 0
pixelMap = [];
for (var i = 0; i < width; i++) {
pixelMap[i] = [];
}
}
// randomChoices = the keys of "elements" with any element with the category "tools" or the property excludeRandom set to true removed
randomChoices = Object.keys(elements).filter(function(e) {
return elements[e].excludeRandom != true && elements[e].category != "tools" && !elements[e].tool;
});
//...drawing code...
gameCanvas.addEventListener("mousedown", mouseClick);
gameCanvas.addEventListener("touchstart", mouseClick, { passive: false });
window.addEventListener("mouseup", mouseUp);
window.addEventListener("touchend", mouseUp, { passive: false });
window.addEventListener("mousemove", mouseMove);
gameCanvas.addEventListener("touchmove", mouseMove, { passive: false });
gameCanvas.addEventListener("wheel", wheelHandle);
gameCanvas.ontouchstart = function(e) {
if (e.touches) e = e.touches[0];
return false;
}
window.onbeforeunload = function(){ // Confirm leaving page if there are pixels on-screen
if (currentPixels.length > 0){
return 'Are you sure you want to leave?';
}
};
// If enabledMods has items, add an li to modManagerList for each item with the href to the item, target blank, and the item's name, with "<span class="removeModX" onclick='removeMod('>X</span>" after the link
if (enabledMods.length > 0) {
modManagerList = document.getElementById("modManagerList");
for (var i = 0; i < enabledMods.length; i++) {
var mod = enabledMods[i];
// modName is the last part of the mod's path
var modName = mod.split("/").pop();
modManagerList.innerHTML += "<li><a href='" + mod + "' target='_blank'>" + modName + "</a> <span class='removeModX' onclick='removeMod(\"" + mod + "\")'>X</span></li>";
}
}
shiftDown = 0;
// If the user presses [ or -, decrease the mouse size by 2
document.addEventListener("keydown", function(e) {
if (e.ctrlKey || e.metaKey) {
return
}
// else if tab, set document.body.class to "usingTab"
else if (e.keyCode == 9) {
document.body.classList.add("usingTab");
}
// F1 = hide #underDiv, #infoParent, #modParent, #pagetitle, #colorSelector if they aren't hidden, otherwise show them
if (e.keyCode == 112) {
e.preventDefault();
if (document.getElementById("underDiv").style.display == "none") {
document.getElementById("underDiv").style.display = "block";
document.getElementById("pagetitle").style.display = "block";
document.getElementById("colorSelector").style.display = "block";
} else {
document.getElementById("underDiv").style.display = "none";
if (showingMenu) {
closeMenu()
};
document.getElementById("pagetitle").style.display = "none";
document.getElementById("colorSelector").style.display = "none";
}
}
if (showingMenu) {
// esc or / or tab / or \ (while in settings) to close
if (e.keyCode == 27 || (e.keyCode == 191 && showingMenu=="info") || e.keyCode == 9 || (e.keyCode == 220 && showingMenu=="settings")) {
e.preventDefault();
closeMenu();
}
// enter to clear infoSearch
else if (e.keyCode == 13 && showingMenu == "info") {
var infoSearch = document.getElementById("infoSearch");
infoSearch.value = "";
showInfo();
}
return;
}
if (e.keyCode == 219 || e.keyCode == 189) {
if (shiftDown) {mouseSize = 1}
else {
mouseSize -= 2;
if (mouseSize < 1) { mouseSize = 1; }
}
}
// If the user presses ] or =, increase the mouse size by 2
if (e.keyCode == 221 || e.keyCode == 187) {
if (shiftDown) {mouseSize = (mouseSize+15)-((mouseSize+15) % 15)}
else {mouseSize += 2;}
// if height>width and mouseSize>height, set mouseSize to height, if width>height and mouseSize>width, set mouseSize to width
if (mouseSize > (height > width ? height : width)) { mouseSize = (height > width ? height : width); }
}
// User presses shift
else if (e.keyCode == 16) {
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_LEFT) {
shiftDown = 1;
} else if (event.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
shiftDown = 3;
}
}
// User presses alt
else if (e.keyCode == 18) {
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_LEFT) {
shiftDown = 2;
} else if (event.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
shiftDown = 4;
}
}
// p or spacebar or ` or k = pause
if (e.keyCode == 80 || e.keyCode == 32 || e.keyCode == 192 || e.keyCode == 75) {
e.preventDefault();
togglePause();
}
// e = chooseElementPrompt()
else if (e.keyCode == 69) {
e.preventDefault();
chooseElementPrompt();
}
// . = doFrame()
else if (e.keyCode == 190) {
e.preventDefault();
doFrame();
}
// / or i = showInfo()
else if (e.keyCode == 191 || e.keyCode == 73) {
e.preventDefault();
showInfo();
}
// f = full screen
else if (e.keyCode == 70) {
e.preventDefault();
if (document.fullscreenElement) {
document.exitFullscreen(document.body);
} else {
requestFullScreen(document.body);
}
}
// 0-9 = setView(the number)
else if (e.keyCode >= 48 && e.keyCode <= 57) {
// if not command or control down, set view to the number
e.preventDefault();
setView(e.keyCode-48);
}
// right arrow = switch the category to the one after the current category
else if (e.keyCode == 39) {
e.preventDefault();
// in categoryControls, find the button with the class categoryButton and the attribute current="true"
var currentButton = document.querySelector(".categoryButton[current='true']");
var currentCategory = currentButton.getAttribute("category");
// get the categoryButton that is after the current one in the div
var nextButton = currentButton.nextElementSibling;
// if there is no next button, go to the first one
if (nextButton == null) {
nextButton = document.querySelector(".categoryButton");
}
var nextCategory = nextButton.getAttribute("category");
selectCategory(nextCategory);
// focus on categoryControls
document.getElementById("categoryControls").focus();
}
// left arrow = switch the category to the one before the current category
else if (e.keyCode == 37) {
e.preventDefault();
// in categoryControls, find the button with the class categoryButton and the attribute current="true"
var currentButton = document.querySelector(".categoryButton[current='true']");
var currentCategory = currentButton.getAttribute("category");
// get the categoryButton that is before the current one in the div
var prevButton = currentButton.previousElementSibling;
// if there is no previous button, go to the last one
if (prevButton == null) {
prevButton = document.querySelector(".categoryButton:last-child");
}
var prevCategory = prevButton.getAttribute("category");
selectCategory(prevCategory);
}
// m = closeMenu() and showModManager()
else if (e.keyCode == 77) {
e.preventDefault();
closeMenu();
showModManager();
}
// \ = closeMenu() and showSettings()
else if (e.keyCode == 220) {
e.preventDefault();
closeMenu();
showSettings();
}
// c or F2 = screenshot
else if (e.keyCode == 67 || e.keyCode == 113) {
e.preventDefault();
var link = document.createElement('a');
link.setAttribute('download', 'sandboxels-screenshot.png');
link.setAttribute('href', document.getElementById("game").toDataURL("image/png").replace("image/png", "image/octet-stream"));
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// x = explodeAt()
/*else if (e.keyCode == 88) {
e.preventDefault();
explodeAt(mousePos.x, mousePos.y, Math.round(mouseSize/2));
}*/
});
// If the user releases either shift
document.addEventListener("keyup", function(e) {
if (e.keyCode == 16 || e.keyCode == 18) { shiftDown = 0; }
});
// Create buttons for elements
// For each element type in elements, create a button in controls that sets the current element to that type
// Alphabetically sort and loop through dictionary named "elements"
elementCount = 0;
hiddenCount = 0;
for (var element in elements) {
elementCount++;
if (elements[element].hidden && !settings["unhide"]) { hiddenCount++; continue; }
var category = elements[element].category;
if (category==null) {category="Other"}
var categoryDiv = document.getElementById("category-"+category);
if (categoryDiv == null) {
categoryButton = document.createElement("button");
categoryButton.id = "categoryButton-"+category;
categoryButton.innerHTML = category.replace("."," ").replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}).replace(" ",".").replace(/ /g, "");;
categoryButton.className = "categoryButton";
categoryButton.setAttribute("category",category);
categoryButton.onclick = function() {
selectCategory(this.getAttribute("category"));
}
document.getElementById("categoryControls").appendChild(categoryButton);
categoryDiv = document.createElement("div");
//categoryDiv.innerHTML = "<span class='categoryName'>"+category+"</span>";
categoryDiv.setAttribute("id","category-"+category);
categoryDiv.setAttribute("category",category);
categoryDiv.setAttribute("class","category");
document.getElementById("elementControls").appendChild(categoryDiv);
}
var button = document.createElement("button");
// if the element has the attribute "name", use that as the button's text, otherwise use the element with underscores replaced by spaces
if (elements[element].name) {
button.innerHTML = elements[element].name;
}
else {
button.innerHTML = element.replace(/_/g, " ");
}
//capitalize first letter of each word
button.innerHTML = button.innerHTML.replace("."," ").replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}).replace(" ",".").replace(/ /g, "");
//set attribute of element to the element
button.setAttribute("element", element);
button.setAttribute("current", "false");
button.className = "elementButton";
//color of the element
// if the element color is an array, make a gradient background color, otherwise, set the background color to the element color
if (elements[element].color instanceof Array) {
button.style.backgroundImage = "linear-gradient(to bottom right, "+elements[element].color.join(", ")+")";
// choose the middlemost item in array
var colorObject = elements[element].colorObject[Math.floor(elements[element].colorObject.length/2)];
if ((colorObject.r+colorObject.g+colorObject.b)/3 > 200) {
button.className += " bright"
}
}
else {
button.style.background = elements[element].color;
var colorObject = elements[element].colorObject;
if ((colorObject.r+colorObject.g+colorObject.b)/3 > 200) {
button.className += " bright"
}
}
button.id = "elementButton-" + element;
button.onclick = function() {
selectElement(this.getAttribute("element"));
}
// on right click, show the element's info
button.oncontextmenu = function(e) {
e.preventDefault();
closeMenu();
showInfo(this.getAttribute("element"));
}
categoryDiv.appendChild(button);
}
// Set the first button in categoryControls div to be the current category
document.getElementById("categoryControls").children[0].click()
document.getElementById("extraInfo").innerHTML += "<p><small>There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.</small></p>";
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();
}
}
}
</script>
</head>
<body>
<h1 class="pagetitle" id="pagetitle"><a href="https://R74n.com" class="backbutton" target="_blank">&lt;</a></h1>
<div id="gameDiv">
<div id="canvasDiv">
<canvas id="game" width="800" height="600" oncontextmenu="return false;">
Your browser does not support the HTML5 canvas tag.<br>
Please update your browser to the latest version.<br>
<a href="https://www.google.com/chrome/" tabindex="-1">Chrome</a> 4.0+<br>
<a href="https://www.mozilla.org/firefox/new/" tabindex="-1">Firefox</a> 2.0+<br>
<a href="http://www.apple.com/safari/" tabindex="-1">Safari</a> 3.1+<br><br>
<a href="http://www.opera.com/" tabindex="-1">Opera</a> 9.0+<br>
<a href="http://www.microsoft.com/windows/internet-explorer/default.aspx" tabindex="-1">Internet Explorer</a> 9.0+<br>
</canvas>
<input id="colorSelector" type="color" value="#ff0000" onchange="currentColor=this.value;
document.getElementById('elementButton-'+currentElement).style.removeProperty('background-image');
document.getElementById('elementButton-'+currentElement).style.background = currentColor;" oninput="currentColor=this.value;
document.getElementById('elementButton-'+currentElement).style.removeProperty('background-image');
document.getElementById('elementButton-'+currentElement).style.background = currentColor;">
</div>
<div id="underDiv">
<div id="stats"></div>
<div id="controls">
<div id="toolControls">
<button id="pauseButton" title="Pause/play the simulation" class="controlButton" onclick='togglePause();focusGame();' on="false">Pause</button><button id="frameButton" title="Pause and play one frame" class="controlButton" onclick='doFrame();focusGame();' on="false">Step</button><button id="sizeDownButton" title="Decrease the brush size" class="controlButton" onclick="mouseSize -= 2;if (mouseSize < 1) { mouseSize = 1; };focusGame();">-</button><button id="sizeUpButton" title="Increase the brush size" class="controlButton" onclick="mouseSize += 2;if (mouseSize > (height > width ? height : width)) { mouseSize = (height > width ? height : width); };focusGame();">+</button><button id="resetButton" title="Clear the entire scene" class="controlButton" onclick="if (confirm('Are you sure you want to clear the whole scene?')) {clearAll();};focusGame();">Reset</button><button id="replaceButton" title="Override existing pixels when placing" class="controlButton" onclick='if (mode == "replace") {mode = null;this.setAttribute("on","false");}else {mode = "replace";this.setAttribute("on","true");};focusGame();' on="false">Replace</button><button id="elemSelectButton" title="Select an element by ID" class="controlButton" onclick='chooseElementPrompt();focusGame();'>E</button><button id="tpsButton" title="Change the simulation Ticks Per Second (TPS)" class="controlButton" onclick='var newtps = prompt("Enter the new simulation Ticks Per Second (TPS). This is how many updates per second the simulation will run.\n\nThe default is 30.\n\nThe current TPS is " + tps + ".");if (newtps !== null) {if (isNaN(newtps) || newtps == "" || newtps == "0") {alert("You did not enter a valid TPS.");}else if (newtps > 1000) {alert("You entered a TPS that is too high. The TPS will be set to the maximum, 1000.");tps = 1000;}else {tps = parseInt(newtps);if (isNaN(tps)) {alert("You did not enter a valid TPS.");tps = 30;}}resetInterval(tps);}focusGame();'>Tps</button><!--<button id="hideButton" title="Stops updating the scene to allow more resources towards simulation" class="controlButton" onclick='if (hiding) {hiding = false;this.setAttribute("on","false");}else {hiding = true;this.setAttribute("on","true");};focusGame();' on="false">Hide</button>--><button id="infoButton" title="Brings up the element info screen" class="controlButton" onclick='if (showingMenu!="info"){closeMenu();showInfo(currentElement)}else{closeMenu()};' on="false">Info</button><button id="modsButton" title="Brings up the Mod Manager" class="controlButton" onclick='if (showingMenu!="mods"){closeMenu();showModManager()}else{closeMenu()};' on="false">Mods</button><button id="settingsButton" title="Brings up the settings screen" class="controlButton" onclick='if (showingMenu!="settings"){closeMenu();showSettings()}else{closeMenu()};' on="false">Settings</button>
</div>
<div id="category-tools" category="tools" style="display: block;"></div>
<div id="categoryControls"></div>
<div id="elementControls"></div>
</div>
<div id="extraInfo"><small><a href="controls.txt" target="_blank">Controls</a><a href="changelog.txt" target="_blank">Changelog</a><a href="https://docs.google.com/document/d/1R8xljj_J-K5oU-9y4louwplQmM-ZBvUfXmhbgj5LYdk/edit?usp=sharing" target="_blank">Feedback</a><a href="https://discord.gg/ejUc6YPQuS" target="_blank">Discord</a></small></div>
</div>
</div>
<div id="infoParent">
<div id="infoScreen"> <!--Element Info Page-->
<button class="XButton" onclick="closeMenu();">-</button>
<span class="menuTitle" id="infoTitle">Title</span>
<div class="menuText" id="infoText">Text</div>
</div>
<input type="text" id="infoSearch" placeholder="Element..." oninput="showInfo(this.value);"></input>
</div>
<!--Mod Manager Page with the list of current mods and a url input box with a plus button to add it-->
<div id="modParent">
<div id="modManager">
<button class="XButton" onclick="closeMenu();">-</button>
<span class="menuTitle">Enabled Mods</span>
<ul class="menuText" id="modManagerList"></ul>
<br><br><br><br>
<!--If the key is Enter, addMod -->
</div>
<input type="text" id="modManagerUrl" placeholder=".JS URL..." onkeydown="if (event.keyCode == 13) {addMod(this.value);this.value = '';};this.focus();"></input>
<!-- <button id="modManagerAdd" onclick="addMod(document.getElementById('modManagerUrl').value); document.getElementById('modManagerUrl').value = '';">+</button> -->
</div>
<!--Settings Menu-->
<div id="settingsParent">
<div id="settingsMenu">
<button class="XButton" onclick="closeMenu();">-</button>
<span class="menuTitle">Settings</span>
<div class="menuText" style="padding-top:1em">
<span setting="units" style="display:block;padding-bottom:0.5em" class="setting-span">
Units <select onchange="setSetting('units',this.value);">
<option value="m" selected>Metric</option>
<option value="i">Imperial</option>
<option value="s">SI</option>
</select>
</span>
<span setting="unhide" style="display:block;padding-bottom:0.5em" class="setting-span">
Hiding <select onchange="setSetting('unhide',parseInt(this.value));this.nextElementSibling.innerText='Refresh.'">
<option value="0" selected>Hide Some Elements</option>
<option value="1">Unhide All Elements</option>
</select>
<a onclick="window.location.reload();" style="font-style:italic;cursor:pointer"></a>
</span>
<span setting="bg" style="display:block;padding-bottom:0.5em" class="setting-span">
Background <input onchange="setSetting('bg',this.value);" type="color" value="#000000">
</span>
<span setting="stain" style="display:block;padding-bottom:0.5em" class="setting-span">
Staining <select onchange="setSetting('stainoff',parseInt(this.value));">
<option value="0" selected>Enabled</option>
<option value="1">Disabled</option>
</select>
</span>
<span setting="worldgen" style="display:block;padding-bottom:0.5em" class="setting-span">
World Gen [Beta] <select id="worldgenselect" onchange="setSetting('worldgen',this.value);this.nextElementSibling.innerText='Reset.'">
<option value="off" selected>Disabled</option>
</select>
<span onclick="clearAll();" style="font-style:italic;cursor:pointer"></span>
</span>
</div>
<br><br><br><br>
</div>
</div>
<!-- i like having this but ublock blocks these things anyway -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-93720349-9"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-93720349-9');
</script>
</body>
</html>