diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index a6b9d61e..548ea550 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -7,4 +7,4 @@ Rules for publishing mods:
Failure to follow these rules may result in your pull request being ignored!
-Learn more about [submitting your mod](https://sandboxels.wiki.gg/wiki/Modding_tutorial#Putting_it_online).
+Learn more about [submitting your mod](https://sandboxels.wiki.gg/wiki/Modding/Putting_it_online).
diff --git a/README.md b/README.md
index 66e6eeaa..010907ce 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,12 @@ Play for free at [Sandboxels.R74n.com](https://sandboxels.r74n.com/).
Join the [Discord server](https://discord.com/invite/ejUc6YPQuS).

-
+
+# Modding
+New to modding? Read the Sandboxels Wiki articles on [getting started with modding](https://sandboxels.wiki.gg/wiki/Modding/Getting_started) or [publishing your mod](https://sandboxels.wiki.gg/wiki/Modding/Putting_it_online).
+
+Please read the [Contribution Guidelines](https://github.com/R74nCom/sandboxels/tree/main/.github/CONTRIBUTING.md) before submitting your mod.
+
# Controls
* Left Click = Draw pixels
* Right Click = Erase pixels
diff --git a/mod-list.html b/mod-list.html
index 0d6e153d..be779ef8 100644
--- a/mod-list.html
+++ b/mod-list.html
@@ -71,6 +71,9 @@
.R74nLink {
color: #00ffff;
}
+ ol li {
+ margin-bottom: 10px;
+ }
@@ -81,7 +84,9 @@
Sandboxels has a huge selection of mods that add new content to the simulator. They are created by community members and aren't endorsed by the developer of Sandboxels.
-How to enable a mod
+Jump to: Create your own mod, Issues with mods
+
+How to enable a mod
- Go to the official Sandboxels website.
- Press the Mods button in the toolbar to open the Mod Manager.
@@ -89,7 +94,7 @@
- Press enter, then refresh the page.
-Sandboxels Mod List
+Sandboxels Mod List
Mods submitted to our GitHub repo are listed here.
@@ -189,6 +194,7 @@
| text.js | Tools to write text | RedBirdly |
| texturepack.js | Tools that let you create and share custom texture packs | nousernamefound |
| the_ground.js | Several rock types, worldgen settings, and gemstones | Alice |
+| worldEdit.js | Selection and editing tools | RedBirdly |
| worldgenlibrary.js | World generation library | Adora |
| Science & Chemistry |
@@ -263,6 +269,7 @@
| pullers.js | Pixels that pull pixels towards them | voidapex11 |
| pushers.js | Pixels that push elements away from them | Alice |
| sandboxels.js | Digital screen to play a mini version of Sandboxels | Nekonico |
+| schematics.js | Schematics for logic gates | SquareScreamYT |
| spouts.js | Spouts for all liquids | kaeud |
| state_voids.js | Several elements that delete specific states of matter | Alice |
| switches.js | Electrical switches that can be toggled | Alice |
@@ -394,6 +401,7 @@
| Visual Effects |
| acid_and_shapes.js | Weird visual effects enabled in settings | Alice |
+| asciiboxels.js | Renders pixels as ASCII characters | Nekonico |
| clouds.js | Moving clouds, sky.js recommended | RedBirdly |
| customBackground.js | Set your background to an image link | Jayd |
| fast_lightmap.js | Light sources glow, but faster | RedBirdly |
@@ -473,11 +481,12 @@
-How to create your own mod
-To create a Sandboxels mod yourself, you may need knowledge of JavaScript programming and GitHub.
-There is a modding tutorial on the Sandboxels Wiki, and an Example Mod to base yours off of.
+How to create your own mod
-Issues with mods
+To learn to create your own Sandboxels mod, read the Modding Tutorial on the Sandboxels Wiki, and an Example Mod to base yours off of.
+Mods are submitted to the GitHub repo.
+
+Issues with mods
We don't provide support for unofficial mods. You may ask for help in our Discord server, or press Clear Mods in Settings.
Some mods may not work every time you load the game, or even at all!
diff --git a/mods/aChefsDream.js b/mods/aChefsDream.js
index 93318077..30b65ead 100644
--- a/mods/aChefsDream.js
+++ b/mods/aChefsDream.js
@@ -1,5 +1,6 @@
-// created by SquareScreamYT
-// https://github.com/SquareScreamYT/aChefsDream.js
+// created by SquareScreamYT/sq
+// https://github.com/SquareScreamYT/
+// https://youtube.com/@sqec
runAfterLoad(function() {
console.log("Thanks for using aChefsDream.js! -sqec")
@@ -2335,7 +2336,7 @@ elements.lemon_juice = {
hidden: true,
tempLow: 0,
reactions: {
- "sugar": {elem1:"lemonade", elem2: "null", chance:0.35}
+ "sugar": {elem1:"lemonade", elem2: null, chance:0.35}
}
};
eLists.JUICEMIXABLE.push("lemon_juice");
@@ -7447,8 +7448,8 @@ elements.raw_beef = {
stateHigh: "steak",
reactions: {
"smoke": {elem1: "smoked_beef"},
- "charcoal": {elem1: "barbecued_beef", tempMin: 70},
- "fire": {elem1: "barbecued_beef"}
+ "charcoal": {elem1: "brisket", tempMin: 70},
+ "fire": {elem1: "brisket"}
}
};
diff --git a/mods/aChefsDream2.js b/mods/aChefsDream2.js
index a5a45cf6..4a089e68 100644
--- a/mods/aChefsDream2.js
+++ b/mods/aChefsDream2.js
@@ -1,393 +1,598 @@
-// created by SquareScreamYT
// the sequel to aChefsDream!
+// created by SquareScreamYT/sq
+// https://github.com/SquareScreamYT/
+// https://youtube.com/@sqec
+
+version = "v2.1.0"
runAfterLoad(function() {
- console.log("Thanks for using aChefsDream2.js! -sqec")
+ console.log("Current aChefsDream version: "+version)
})
-var mods_to_include = ["mods/aChefsDream.js"]
+dependOn("aChefsDream.js", function(){
-var mods_included = mods_to_include.map(mod => enabledMods.includes(mod));
-var all_mods_included = mods_included.reduce(function(a,b) { return a && b });
-
-if(!all_mods_included) {
- var mods_needed = mods_to_include.filter(function(modPath) { return !(enabledMods.includes(modPath)) });
-
- mods_needed.forEach(function(modPath) {
- enabledMods.splice(enabledMods.indexOf("mods/aChefsDream2"),0,modPath);
- });
- localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
-}
+console.log("we recommend using nousersthings.js, elementEraser.js and delete_all_of_element.js for a better cooking experience!")
// Pork and Pigs
elements.pig = {
- color: ["#9c6732", "#dbb997", "#fcaeae"],
- behavior: [
- "M2%1|XX|M2%1",
- "M2%10|XX|M2%10",
- "XX|M1|XX",
- ],
- category:"life",
+ color: ["#9c6732", "#dbb997", "#fcaeae"],
+ behavior: [
+ "M2%1|XX|M2%1",
+ "M2%10|XX|M2%10",
+ "XX|M1|XX",
+ ],
+ category:"life",
state: "solid",
- reactions: {
- "petal": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
- "corn": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "lettuce": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "wheat": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "grass": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
- "grape": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "pumpkin_seed": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "pumpkin": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
- "nut": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
- "lichen": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
- "oxygen": { elem2:"carbon_dioxide", chance:0.3 },
- "mercury": { elem1:"rotten_meat", chance:0.1 },
- "bleach": { elem1:"rotten_meat", chance:0.1 },
- "infection": { elem1:"rotten_meat", chance:0.025 },
- "uranium": { elem1:"rotten_meat", chance:0.1 },
- "cyanide": { elem1:"rotten_meat", chance:0.1 },
- "chlorine": { elem1:"meat", chance:0.1 },
- "dirty_water": { elem1:"rotten_meat", chance:0.0001 },
- },
- egg: "piglet",
- foodNeed: 10,
- temp: 40,
- tempHigh: 75,
- stateHigh: "cooked_pork",
- tempLow: -18,
- stateLow: "frozen_meat",
- breakInto: "raw_pork",
- burn:85,
- burnTime:450,
- state: "solid",
- density: 1117,
- conduct: 0.3,
- extractInto: "raw_pork",
+ reactions: {
+ "petal": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
+ "corn": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "lettuce": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "wheat": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "grass": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
+ "grape": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "pumpkin_seed": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "pumpkin": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
+ "nut": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
+ "lichen": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
+ "oxygen": { elem2:"carbon_dioxide", chance:0.3 },
+ "mercury": { elem1:"rotten_meat", chance:0.1 },
+ "bleach": { elem1:"rotten_meat", chance:0.1 },
+ "infection": { elem1:"rotten_meat", chance:0.025 },
+ "uranium": { elem1:"rotten_meat", chance:0.1 },
+ "cyanide": { elem1:"rotten_meat", chance:0.1 },
+ "chlorine": { elem1:"meat", chance:0.1 },
+ "dirty_water": { elem1:"rotten_meat", chance:0.0001 },
+ },
+ egg: "piglet",
+ foodNeed: 10,
+ temp: 40,
+ tempHigh: 75,
+ stateHigh: "cooked_pork",
+ tempLow: -18,
+ stateLow: "frozen_meat",
+ breakInto: "raw_pork",
+ burn:85,
+ burnTime:450,
+ state: "solid",
+ density: 1117,
+ conduct: 0.3,
+ extractInto: "raw_pork",
};
elements.piglet = {
- color: ["#f7bebe", "#d1a88e"],
- behavior: [
- "M2%1|XX|M2%1",
- "M2%10|FX%5 AND CH:pig%0.1|M2%10",
- "XX|M1|XX",
- ],
- category: "life",
- state: "solid",
- foodNeed: 20,
- temp: 40,
- tempHigh: 75,
- stateHigh: "cooked_pork",
- tempLow: -18,
- stateLow: "frozen_meat",
- breakInto: "blood",
- burn:85,
- burnTime:450,
- state: "solid",
- density: 900,
- conduct: 0.1,
- reactions: {
- "petal": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
- "corn": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "lettuce": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "wheat": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "grass": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
- "grape": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "pumpkin_seed": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
- "pumpkin": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
- "nut": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
- "lichen": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
- "oxygen": { elem2:"carbon_dioxide", chance:0.3 },
- "mercury": { elem1:"rotten_meat", chance:0.1 },
- "bleach": { elem1:"rotten_meat", chance:0.1 },
- "infection": { elem1:"rotten_meat", chance:0.025 },
- "uranium": { elem1:"rotten_meat", chance:0.1 },
- "cyanide": { elem1:"rotten_meat", chance:0.1 },
- "chlorine": { elem1:"meat", chance:0.1 },
- "dirty_water": { elem1:"rotten_meat", chance:0.0001 },
- },
+ color: ["#f7bebe", "#d1a88e"],
+ behavior: [
+ "M2%1|XX|M2%1",
+ "M2%10|FX%5 AND CH:pig%0.1|M2%10",
+ "XX|M1|XX",
+ ],
+ category: "life",
+ state: "solid",
+ foodNeed: 20,
+ temp: 40,
+ tempHigh: 75,
+ stateHigh: "cooked_pork",
+ tempLow: -18,
+ stateLow: "frozen_meat",
+ breakInto: "blood",
+ burn:85,
+ burnTime:450,
+ state: "solid",
+ density: 900,
+ conduct: 0.1,
+ reactions: {
+ "petal": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
+ "corn": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "lettuce": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "wheat": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "grass": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
+ "grape": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "pumpkin_seed": { elem2:null, chance:0.3, func:behaviors.FEEDPIXEL },
+ "pumpkin": { elem2:null, chance:0.1, func:behaviors.FEEDPIXEL },
+ "nut": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
+ "lichen": { elem2:null, chance:0.2, func:behaviors.FEEDPIXEL },
+ "oxygen": { elem2:"carbon_dioxide", chance:0.3 },
+ "mercury": { elem1:"rotten_meat", chance:0.1 },
+ "bleach": { elem1:"rotten_meat", chance:0.1 },
+ "infection": { elem1:"rotten_meat", chance:0.025 },
+ "uranium": { elem1:"rotten_meat", chance:0.1 },
+ "cyanide": { elem1:"rotten_meat", chance:0.1 },
+ "chlorine": { elem1:"meat", chance:0.1 },
+ "dirty_water": { elem1:"rotten_meat", chance:0.0001 },
+ },
};
elements.barbecued_pork = {
- color:["#a1391f","#ab5e32"],
- behavior: behaviors.STURDYPOWDER,
- category: "food",
- state: "solid",
- temp:55,
- tempHigh: 600,
- stateHigh: ["ash","smoke"],
- isFood: true,
- hidden: true,
+ color:["#a1391f","#ab5e32"],
+ behavior: behaviors.STURDYPOWDER,
+ category: "food",
+ state: "solid",
+ temp:55,
+ tempHigh: 600,
+ stateHigh: ["ash","smoke"],
+ isFood: true,
+ hidden: true,
}
elements.cooked_pork = {
- color: ["#e6bf8a", "#e3be96"],
- behavior: behaviors.STURDYPOWDER,
- category: "food",
- state: "solid",
- temp: 40,
- tempHigh: 600,
- stateHigh: ["ash", "smoke"],
- hidden: true,
- alias: "cooked_pork"
+ color: ["#e6bf8a", "#e3be96"],
+ behavior: behaviors.STURDYPOWDER,
+ category: "food",
+ state: "solid",
+ temp: 40,
+ tempHigh: 600,
+ stateHigh: ["ash", "smoke"],
+ hidden: true,
+ alias: "cooked_pork"
};
elements.raw_pork = {
- color: ["#ed5d47", "#e0423d"],
- behavior: behaviors.STURDYPOWDER,
- category: "food",
- state: "solid",
- burnInto: "cooked_pork",
- temp:25,
- tempHigh: 200,
- stateHigh: "cooked_pork",
- reactions: {
- "charcoal": {elem1: "barbecued_pork", tempMin: 70},
- "fire": {elem1: "barbecued_pork"}
- }
+ color: ["#ed5d47", "#e0423d"],
+ behavior: behaviors.STURDYPOWDER,
+ category: "food",
+ state: "solid",
+ burnInto: "cooked_pork",
+ temp:25,
+ tempHigh: 200,
+ stateHigh: "cooked_pork",
+ reactions: {
+ "charcoal": {elem1: "barbecued_pork", tempMin: 70},
+ "fire": {elem1: "barbecued_pork"}
+ }
};
// Extraction tool
elements.extract = {
- color: "#82452c",
- // other needed properties
- tool: (pixel) => {
- //store extractInto as a variable for legibility
- var extractInto = elements[pixel.element].extractInto;
- //if there’s no extractInto, it should equal undefined, which is falsey and !undefined = true
- if (!extractInto) { return };
- //if extractInto is an array, randomly pick one of its elements
- if(extractInto instanceof Array) { extractInto = extractInto[Math.floor(Math.random() * extractInto.length)] };
- //change pixel into the (chosen) element
- if (shiftDown) {
- if (Math.random() < 0.5) {
- var thiselement = pixel.element;
- changePixel(pixel, extractInto)
- pixelTempCheck(pixel);
- if (elements[thiselement].extractIntoColor) {
- pixel.color = pixelColorPick(pixel, elements[thiselement].extractIntoColor);
- }
- }
+ color: "#82452c",
+ // other needed properties
+ tool: (pixel) => {
+ //store extractInto as a variable for legibility
+ var extractInto = elements[pixel.element].extractInto;
+ //if there’s no extractInto, it should equal undefined, which is falsey and !undefined = true
+ if (!extractInto) { return };
+ //if extractInto is an array, randomly pick one of its elements
+ if(extractInto instanceof Array) { extractInto = extractInto[Math.floor(Math.random() * extractInto.length)] };
+ //change pixel into the (chosen) element
+ if (shiftDown) {
+ if (Math.random() < 0.5) {
+ var thiselement = pixel.element;
+ changePixel(pixel, extractInto)
+ pixelTempCheck(pixel);
+ if (elements[thiselement].extractIntoColor) {
+ pixel.color = pixelColorPick(pixel, elements[thiselement].extractIntoColor);
}
- else if (!shiftDown) {
- if (Math.random() < 0.1) {
- var thiselement = pixel.element;
- changePixel(pixel, extractInto)
- pixelTempCheck(pixel);
- if (elements[thiselement].extractIntoColor) {
- pixel.color = pixelColorPick(pixel, elements[thiselement].extractIntoColor);
- }
- }
+ }
+ }
+ else if (!shiftDown) {
+ if (Math.random() < 0.1) {
+ var thiselement = pixel.element;
+ changePixel(pixel, extractInto)
+ pixelTempCheck(pixel);
+ if (elements[thiselement].extractIntoColor) {
+ pixel.color = pixelColorPick(pixel, elements[thiselement].extractIntoColor);
}
- },
- category: "tools",
- canPlace: false,
- desc: "Use on pixels to extract the essence from them, if possible. [BETA]"
+ }
+ }
+ },
+ category: "tools",
+ canPlace: false,
+ desc: "Use on pixels to extract the essence from them, if possible. [BETA]"
}
// spices
elements.allspice = {
- color: ["#7B5B3A", "#A75B3D", "#B67B57", "#C19A6B"],
- behavior: behaviors.POWDER,
- category: "food",
- state: "solid",
- isFood: true,
- temp: 20,
- hidden: true,
- tempHigh: 250,
- stateHigh: ["ash", "smoke"],
+ color: ["#7B5B3A", "#A75B3D", "#B67B57", "#C19A6B"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
}
elements.cumin = {
- color: "#A58459",
- behavior: behaviors.POWDER,
- category: "food",
- state: "solid",
- isFood: true,
- temp: 20,
- hidden: true,
- tempHigh: 250,
- stateHigh: ["ash", "smoke"],
+ color: "#A58459",
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
}
elements.paprika = {
- color: ["#C72C29","#b22b02"],
- behavior: behaviors.POWDER,
- category: "food",
- state: "solid",
- isFood: true,
- temp: 20,
- hidden: true,
- tempHigh: 250,
- stateHigh: ["ash", "smoke"],
+ color: ["#C72C29","#b22b02"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
}
elements.turmeric = {
- color: ["#E5B635","#D9A322"],
- behavior: behaviors.POWDER,
- category: "food",
- state: "solid",
- isFood: true,
- temp: 20,
- hidden: true,
- tempHigh: 250,
- stateHigh: ["ash", "smoke"],
+ color: ["#E5B635","#D9A322"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
}
elements.saffron = {
- color: ["#b83b3b","#a82525"],
- behavior: behaviors.POWDER,
- category: "food",
- state: "solid",
- isFood: true,
- temp: 20,
- hidden: true,
- tempHigh: 250,
- stateHigh: ["ash", "smoke"],
+ color: ["#b83b3b","#a82525"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
}
// sugarcane
elements.sugarcane_plant = {
- color: ["#fbc852","#dfad54"],
- behavior: [
- "XX|M2%2|XX",
- "XX|L2:sugarcane AND C2:sugarcane%10|XX",
- "XX|M1|XX",
- ],
- tick: behaviors.SEEDRISE,
- tempHigh: 100,
- stateHigh: "dead_plant",
- tempLow: -2,
- stateLow: "sugarcane",
- burn: 30,
- burnTime: 100,
- category: "life",
- state: "solid",
- density: 686,
- breakInto: "cane_sugar",
- cooldown: defaultCooldown,
- seed: true
+ color: ["#fbc852","#dfad54"],
+ behavior: [
+ "XX|M2%2|XX",
+ "XX|L2:sugarcane AND C2:sugarcane%10|XX",
+ "XX|M1|XX",
+ ],
+ tick: behaviors.SEEDRISE,
+ tempHigh: 100,
+ stateHigh: "dead_plant",
+ tempLow: -2,
+ stateLow: "sugarcane",
+ burn: 30,
+ burnTime: 100,
+ category: "life",
+ state: "solid",
+ density: 686,
+ breakInto: "cane_sugar",
+ cooldown: defaultCooldown,
+ seed: true
}
elements.sugarcane = {
- color: ["#7cc05c","#77a052"],
- behavior: behaviors.STURDYPOWDER,
- tempHigh: 380,
- stateHigh: ["ember","fire","fire","fire"],
- burn: 10,
- burnTime: 200,
- burnInto: ["ember","fire","fire","fire"],
- category: "food",
- state: "solid",
- density: 686,
- breakInto: "cane_sugar",
- seed: "sugarcane_plant"
+ color: ["#7cc05c","#77a052"],
+ behavior: behaviors.STURDYPOWDER,
+ tempHigh: 380,
+ stateHigh: ["ember","fire","fire","fire"],
+ burn: 10,
+ burnTime: 200,
+ burnInto: ["ember","fire","fire","fire"],
+ category: "food",
+ state: "solid",
+ density: 686,
+ breakInto: "cane_sugar",
+ seed: "sugarcane_plant"
}
elements.cane_sugar = {
- color: "#ffeedb",
- behavior: behaviors.POWDER,
- reactions: {
- "grape": { elem1:null, elem2:"jelly", chance:0.005, tempMin:100 },
- "water": { elem1:null, elem2:"sugar_water"},
- },
- category: "food",
- tempHigh: 186,
- stateHigh: "caramel",
- state: "solid",
- density: 1590,
- isFood: true
+ color: "#ffeedb",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "grape": { elem1:null, elem2:"jelly", chance:0.005, tempMin:100 },
+ "water": { elem1:null, elem2:"sugar_water"},
+ },
+ category: "food",
+ tempHigh: 186,
+ stateHigh: "caramel",
+ state: "solid",
+ density: 1590,
+ isFood: true
}
elements.tea_leaves = {
- color: ["#3e6e26","#507e28","#759e2e"],
- reactions: {
- "water": { elem2:"tea", tempMin:80 },
- "salt_water": { elem2:"tea", tempMin:80 },
- "sugar_water": { elem2:"tea", tempMin:80 },
- "seltzer": { elem2:"tea", tempMin:80 },
- "stench": { elem2:null, chance:0.25 },
- "steam": { elem2:"fragrance", chance:0.1 },
- "flea": { elem2:null, chance:0.01 },
- "termite": { elem2:null, chance:0.01 },
- "fly": { elem2:null, chance:0.01 },
- "ant": { elem2:null, chance:0.01 },
- "stink_bug": { elem2:null, chance:0.01 },
- },
- behavior: behaviors.POWDER,
- tempHigh: 300,
- stateHigh: ["fire","smoke","smoke","smoke","ash"],
- tempLow: -2,
- stateLow: "frozen_plant",
- burn:10,
- burnTime:300,
- burnInto: ["fire","smoke","smoke","smoke","smoke","smoke","smoke","fragrance"],
- category:"food",
- state: "solid",
- density: 1400,
- isFood: true,
+ color: ["#3e6e26","#507e28","#759e2e"],
+ reactions: {
+ "water": { elem2:"tea", tempMin:80 },
+ "salt_water": { elem2:"tea", tempMin:80 },
+ "sugar_water": { elem2:"tea", tempMin:80 },
+ "seltzer": { elem2:"tea", tempMin:80 },
+ "stench": { elem2:null, chance:0.25 },
+ "steam": { elem2:"fragrance", chance:0.1 },
+ "flea": { elem2:null, chance:0.01 },
+ "termite": { elem2:null, chance:0.01 },
+ "fly": { elem2:null, chance:0.01 },
+ "ant": { elem2:null, chance:0.01 },
+ "stink_bug": { elem2:null, chance:0.01 },
+ },
+ behavior: behaviors.POWDER,
+ tempHigh: 300,
+ stateHigh: ["fire","smoke","smoke","smoke","ash"],
+ tempLow: -2,
+ stateLow: "frozen_plant",
+ burn:10,
+ burnTime:300,
+ burnInto: ["fire","smoke","smoke","smoke","smoke","smoke","smoke","fragrance"],
+ category:"food",
+ state: "solid",
+ density: 1400,
+ isFood: true,
}
elements.cinnamon = {
- color: "#986544",
- reactions: {
- "stench": { elem2:null, chance:0.25 },
- "steam": { elem2:"fragrance", chance:0.1 },
- "flea": { elem2:null, chance:0.01 },
- "termite": { elem2:null, chance:0.01 },
- "fly": { elem2:null, chance:0.01 },
- "ant": { elem2:null, chance:0.01 },
- "stink_bug": { elem2:null, chance:0.01 },
- },
- behavior: behaviors.STURDYPOWDER,
- tempHigh: 300,
- stateHigh: ["fire","smoke","smoke","smoke","ash"],
- burn:10,
- burnTime:300,
- burnInto: ["fire","smoke","smoke","smoke","fragrance"],
- category:"food",
- state: "solid",
- density: 1400,
- isFood: true,
- breakInto: "cinnamon_powder"
+ color: "#986544",
+ reactions: {
+ "stench": { elem2:null, chance:0.25 },
+ "steam": { elem2:"fragrance", chance:0.1 },
+ "flea": { elem2:null, chance:0.01 },
+ "termite": { elem2:null, chance:0.01 },
+ "fly": { elem2:null, chance:0.01 },
+ "ant": { elem2:null, chance:0.01 },
+ "stink_bug": { elem2:null, chance:0.01 },
+ },
+ behavior: behaviors.STURDYPOWDER,
+ tempHigh: 300,
+ stateHigh: ["fire","smoke","smoke","smoke","ash"],
+ burn:10,
+ burnTime:300,
+ burnInto: ["fire","smoke","smoke","smoke","fragrance"],
+ category:"food",
+ state: "solid",
+ density: 1400,
+ isFood: true,
+ breakInto: "cinnamon_powder"
}
elements.cinnamon_powder = {
- color: "#D2691E",
- reactions: {
- "stench": { elem2:null, chance:0.25 },
- "steam": { elem2:"fragrance", chance:0.1 },
- "flea": { elem2:null, chance:0.01 },
- "termite": { elem2:null, chance:0.01 },
- "fly": { elem2:null, chance:0.01 },
- "ant": { elem2:null, chance:0.01 },
- "stink_bug": { elem2:null, chance:0.01 },
- },
- behavior: behaviors.POWDER,
- tempHigh: 300,
- stateHigh: ["fire","smoke","smoke","smoke","ash"],
- burn:10,
- burnTime:300,
- burnInto: ["fire","smoke","smoke","smoke","smoke","smoke","smoke","fragrance"],
- category:"food",
- state: "solid",
- density: 1400,
- isFood: true,
+ color: "#D2691E",
+ reactions: {
+ "stench": { elem2:null, chance:0.25 },
+ "steam": { elem2:"fragrance", chance:0.1 },
+ "flea": { elem2:null, chance:0.01 },
+ "termite": { elem2:null, chance:0.01 },
+ "fly": { elem2:null, chance:0.01 },
+ "ant": { elem2:null, chance:0.01 },
+ "stink_bug": { elem2:null, chance:0.01 },
+ },
+ behavior: behaviors.POWDER,
+ tempHigh: 300,
+ stateHigh: ["fire","smoke","smoke","smoke","ash"],
+ burn:10,
+ burnTime:300,
+ burnInto: ["fire","smoke","smoke","smoke","smoke","smoke","smoke","fragrance"],
+ category:"food",
+ state: "solid",
+ density: 1400,
+ isFood: true,
}
elements.cola_syrup = {
- color: "#4f0e0e",
- behavior: behaviors.LIQUID,
- tempHigh: 170,
- stateHigh: ["sugar","smoke","smoke"],
- tempLow: -15,
- category:"liquids",
- state: "liquid",
- viscosity: 15,
- hidden: true,
- density: 1400,
- reactions: {
- "seltzer": { elem1: ["cola_syrup", "cola_syrup", "foam"], elem2:"soda"},
- "soda": { elem1: "foam", chance:0.001},
- },
+ color: "#4f0e0e",
+ behavior: behaviors.LIQUID,
+ tempHigh: 170,
+ stateHigh: ["sugar","smoke","smoke"],
+ tempLow: -15,
+ category:"liquids",
+ state: "liquid",
+ viscosity: 15,
+ hidden: true,
+ density: 1400,
+ reactions: {
+ "seltzer": { elem1: ["cola_syrup", "cola_syrup", "foam"], elem2:"soda"},
+ "soda": { elem1: "foam", chance:0.001},
+ },
}
if (!elements.sugar_water.reactions) elements.sugar_water.reactions = {};
elements.sugar_water.reactions.lemon_juice = { elem1: "sugar_water", elem2: null, color1: "#fff7ba" }
if (!elements.sugar_water.reactions) elements.sugar_water.reactions = {};
-elements.sugar_water.reactions.cinnamon_powder = { elem1: "cola_syrup", elem2: null }
\ No newline at end of file
+elements.sugar_water.reactions.cinnamon_powder = { elem1: "cola_syrup", elem2: null }
+
+elements.brisket = {
+ color:["#704534", "#6b3d2b", "#733526"],
+ behavior: behaviors.SUPPORT,
+ category: "food",
+ state: "solid",
+ temp:55,
+ tempHigh: 600,
+ stateHigh: ["ash","smoke"],
+ isFood: true,
+ hidden: true,
+}
+
+if (!elements.cured_meat.reactions) elements.cured_meat.reactions = {};
+elements.cured_meat.reactions.smoke = { elem1: "brisket", elem2: null }
+
+elements.cured_meat.tempHigh = 111
+
+// spices
+
+elements.star_anise = {
+ color: ["#8B4513", "#A0522D", "#D2691E"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.curry_leaves = {
+ color: ["#228B22", "#32CD32", "#6B8E23"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.laksa_leaves = {
+ color: ["#6a8e3d", "#7d9a57", "#8ea54b"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.bay_leaves = {
+ color: ["#556B2F", "#808000", "#9ACD32"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.rosemary = {
+ color: ["#483C32", "#708238", "#8FBC8F"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.coriander_leaves = {
+ color: ["#4b5f44", "#6b7b55", "#3f5c32"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.coriander_seeds = {
+ color: ["#F4A460", "#D2691E"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.parsley = {
+ color: ["#228B22", "#32CD32", "#3CB371"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+elements.cloves = {
+ color: ["#654321", "#8B4513", "#A0522D"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ hidden: true,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+}
+
+var spices = [
+ // 2
+ "allspice",
+ "cumin",
+ "paprika",
+ "turmeric",
+ "saffron",
+ "cinnamon_powder",
+ "star_anise",
+ "curry_leaves",
+ "laksa_leaves",
+ "bay_leaves",
+ "rosemary",
+ "coriander_leaves",
+ "coriander_seeds",
+ "parsley",
+ "cloves",
+ "cinnamon",
+ // 1
+ "pepper",
+ "chilli_powder",
+ "onion_powder",
+ "herb",
+ "cut_ginger",
+ "fried_onion",
+ "chopped_spring_onion",
+ "salt"
+];
+
+/*elements.spice_mix = {
+ color: ["#8B7D6B", "#A0935C", "#B8A77A"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+ tick: function(pixel) {
+ var randomSpice = spices[Math.floor(Math.random() * spices.length)];
+ changePixel(pixel, randomSpice);
+ }
+}*/
+
+elements.pistachio = {
+ color: ["#E8D5B7", "#F2E3C1", "#DDD0A8"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+ breakInto: "pistachio_powder",
+ cutInto: "pistachio_meat"
+}
+
+elements.pistachio_meat = {
+ color: ["#98C93A", "#A3D645", "#8BB832"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+ breakInto: "pistachio_powder",
+ hidden: true
+}
+
+elements.pistachio_powder = {
+ color: ["#7A9B2F", "#85A635", "#6F8728"],
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "solid",
+ isFood: true,
+ temp: 20,
+ tempHigh: 250,
+ stateHigh: ["ash", "smoke"],
+ hidden: true
+}
+
+},true)
\ No newline at end of file
diff --git a/mods/aChefsDream_beta.js b/mods/aChefsDream_beta.js
index a2524503..bc711841 100644
--- a/mods/aChefsDream_beta.js
+++ b/mods/aChefsDream_beta.js
@@ -1,7 +1,7 @@
// created by SquareScreamYT
// please visit the repo to see the code
-fetch('https://raw.githubusercontent.com/SquareScreamYT/aChefsDream.js/main/aChefsDream.js')
+fetch('https://raw.githubusercontent.com/SquareScreamYT/sandboxels/main/mods/aChefsDream2.js')
.then(response => response.text())
.then(code => {
eval(code);
diff --git a/mods/asciiboxels.js b/mods/asciiboxels.js
new file mode 100644
index 00000000..0693cebd
--- /dev/null
+++ b/mods/asciiboxels.js
@@ -0,0 +1,231 @@
+/*window.addEventListener('load', function() { // original plan for mod
+ for (var element in elements) {
+ elements[element].renderer = function(pixel, ctx) {}
+ }
+}); */
+
+if (!enabledMods.includes("mods/betterSettings.js")) { enabledMods.unshift("mods/betterSettings.js"); localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); window.location.reload() };
+
+var ascii_settingsTab = new SettingsTab("Ascii");
+
+var asciicustomcolor_setting = new Setting("Custom Colors", "customcolors", settingType.BOOLEAN, false, defaultValue=false);
+
+var bw_setting = new Setting("Ascii B&W", "bw", settingType.BOOLEAN, false, defaultValue=true);
+
+var asciicolor_setting = new Setting("Ascii Color", "asciicolor", settingType.COLOR, false, defaultValue="#ff0000");
+
+var darklight_setting = new Setting("Flip Darkness", "asciidarklight", settingType.BOOLEAN, false, defaultValue=true, description="Whether the shading of ascii pixels flip depending on background or not.");
+
+ascii_settingsTab.registerSettings("Color", asciicustomcolor_setting);
+
+ascii_settingsTab.registerSettings("Color", bw_setting);
+
+ascii_settingsTab.registerSettings("Color", asciicolor_setting);
+
+ascii_settingsTab.registerSettings("Color", darklight_setting);
+
+settingsManager.registerTab(ascii_settingsTab);
+
+asciiListD = "`.-':~,^=;><+!rc*/z?sLTv)J7(|Fi{C}fI31tlu[neoZ5Yxjya]2ESwqkP6h9d4VpOGbUAKXHm8RD#$Bg0MNWQ%&@"
+asciiListL = "@&%QWNM0gB$#DR8mHXKAUbGOpV4d9h6PkqwSE2]ayjxY5Zoen[ult13If}C{iF|(7J)vTLs?z/*cr!+<>;=^,~:'-.`"
+asciiNum = [-1, 0.0829, 0.0848, 0.1227, 0.1403, 0.1559, 0.185, 0.2183, 0.2417, 0.2571, 0.2852, 0.2902, 0.2919, 0.3099, 0.3192, 0.3232, 0.3294, 0.3384, 0.3609, 0.3619, 0.3667, 0.3737, 0.3747, 0.3838, 0.3921, 0.396, 0.3984, 0.3993, 0.4075, 0.4091, 0.4101, 0.42, 0.423, 0.4247, 0.4274, 0.4293, 0.4328, 0.4382, 0.4385, 0.442, 0.4473, 0.4477, 0.4503, 0.4562, 0.458, 0.461, 0.4638, 0.4667, 0.4686, 0.4693, 0.4703, 0.4833, 0.4881, 0.4944, 0.4953, 0.4992, 0.5509, 0.5567, 0.5569, 0.5591, 0.5602, 0.5602, 0.565, 0.5776, 0.5777, 0.5818, 0.587, 0.5972, 0.5999, 0.6043, 0.6049, 0.6093, 0.6099, 0.6465, 0.6561, 0.6595, 0.6631, 0.6714, 0.6759, 0.6809, 0.6816, 0.6925, 0.7039, 0.7086, 0.7235, 0.7302, 0.7332, 0.7602, 0.7834, 0.8037, 0.9999]
+
+hex_is_light = function(color) {
+ hex = color.replace('#', '');
+ c_r = parseInt(hex.substring(0, 0 + 2), 16);
+ c_g = parseInt(hex.substring(2, 2 + 2), 16);
+ c_b = parseInt(hex.substring(4, 4 + 2), 16);
+ brightness = ((c_r * 334) + (c_g * 334) + (c_b * 332)) / 1000;
+ if (brightness > 127.5) {
+ return true
+ }
+ else {
+ return false
+ }
+}
+
+invertColor = function(color) {
+ let hex = color.replace(/^#/, '');
+ if (hex.length === 3) hex = hex.replace(/./g, '$&$&'); // Expand
+ if (hex.length !== 6) throw new Error(`Invalid HEX color: ${color}`);
+ return `#${(0xFFFFFF ^ parseInt(hex, 16)).toString(16).padStart(6, '0')}`;
+}
+/* // original plan for mod
+renderPostPixel(function(ctx){
+ for (pixel of currentPixels){
+ if (pixel.color){
+ ctx.font = `${pixelSize}pt Arial`
+ if (asciicustomcolor_setting.value == false) {
+ ctx.fillStyle = pixel.color;
+ }
+ else if (bw_setting.value !== true && asciicolor_setting.value) {
+ ctx.fillStyle = asciicolor_setting.value;
+ }
+ else {
+ ctx.fillStyle = invertColor(settings.bg)
+ }
+ var rgb1 = pixel.color.match(/\d+/g);
+ // average the colors
+ let sum = 0;
+ for (const number of rgb1) {
+ sum += Number(number);
+ }
+ var rgb = ((sum / rgb1.length)/225)
+ if (hex_is_light(settings.bg) == false || darklight_setting.value == false) {
+ for (i = 0; i < asciiNum.length; i++) {
+ if (rgb > asciiNum[i]) {
+ var asciiType = asciiListD[i]
+ }
+ }
+ }
+ else if (hex_is_light(settings.bg) == true) {
+ for (i = 0; i < asciiNum.length; i++) {
+ if (rgb > asciiNum[i]) {
+ var asciiType = asciiListL[i]
+ }
+ }
+ }
+ if (asciiType) {
+ ctx.fillText(asciiType, canvasCoord(pixel.x), canvasCoord(pixel.y+1), pixelSize)
+ }
+ }
+ }
+}) */
+
+drawSquare = function(ctx,color,x,y,scale=1,opacity=1) {
+ if (color) {
+ if (scale) {
+ ctx.font = `${pixelSize*scale}pt Arial`
+ }
+ else {
+ ctx.font = `${pixelSize}pt Arial`
+ }
+ if (ctx.globalAlpha !== opacity) { ctx.globalAlpha = opacity; }
+ if (asciicustomcolor_setting.value == false) {
+ ctx.fillStyle = color;
+ }
+ else if (bw_setting.value !== true && asciicolor_setting.value) {
+ ctx.fillStyle = asciicolor_setting.value;
+ }
+ else {
+ ctx.fillStyle = invertColor(settings.bg)
+ }
+ var rgb1 = color.match(/\d+/g);
+ // average the colors
+ let sum = 0;
+ for (const number of rgb1) {
+ sum += Number(number);
+ }
+ var rgb = ((sum / rgb1.length)/255)
+ if (hex_is_light(settings.bg) == false || darklight_setting.value == false) {
+ for (i = 0; i < asciiNum.length; i++) {
+ if (rgb > asciiNum[i]) {
+ var asciiType = asciiListD[i]
+ }
+ }
+ }
+ else if (hex_is_light(settings.bg) == true) {
+ for (i = 0; i < asciiNum.length; i++) {
+ if (rgb > asciiNum[i]) {
+ var asciiType = asciiListL[i]
+ }
+ }
+ }
+ //ctx.fillRect(canvasCoord(x), canvasCoord(y), pixelSize*scale, pixelSize*scale);
+ ctx.fillText(asciiType, canvasCoord(x), canvasCoord(y+scale), pixelSize*scale)
+ }
+}
+
+drawPlus = function(ctx,color,x,y,scale=1,opacity=1) {
+ if (color) {
+ opacity = 0.5*opacity;
+ if (ctx.globalAlpha!==opacity) { ctx.globalAlpha = opacity; }
+ ctx.font = `${pixelSize}pt Arial`
+ if (asciicustomcolor_setting.value == false) {
+ ctx.fillStyle = color;
+ }
+ else if (bw_setting.value !== true && asciicolor_setting.value) {
+ ctx.fillStyle = asciicolor_setting.value;
+ }
+ else {
+ ctx.fillStyle = invertColor(settings.bg)
+ }
+ var rgb1 = color.match(/\d+/g);
+ // average the colors
+ let sum = 0;
+ for (const number of rgb1) {
+ sum += Number(number);
+ }
+ var rgb = ((sum / rgb1.length)/255)
+ if (hex_is_light(settings.bg) == false || darklight_setting.value == false) {
+ for (i = 0; i < asciiNum.length; i++) {
+ if (rgb > asciiNum[i]) {
+ var asciiType = asciiListD[i]
+ }
+ }
+ }
+ else if (hex_is_light(settings.bg) == true) {
+ for (i = 0; i < asciiNum.length; i++) {
+ if (rgb > asciiNum[i]) {
+ var asciiType = asciiListL[i]
+ }
+ }
+ }
+ ctx.fillText(asciiType, canvasCoord(x-1), canvasCoord(y+scale), pixelSize)
+ ctx.fillText(asciiType, canvasCoord(x+1), canvasCoord(y+scale), pixelSize)
+ ctx.fillText(asciiType, canvasCoord(x), canvasCoord((y+scale)+1), pixelSize)
+ ctx.fillText(asciiType, canvasCoord(x), canvasCoord((y+scale)-1), pixelSize)
+ ctx.fillText(asciiType, canvasCoord(x), canvasCoord(y+scale), pixelSize)
+ }
+}
+
+function drawCursor() {
+ var layerCtx = canvasLayers.gui.getContext('2d');
+ var mouseOffset = Math.trunc(mouseSize/2);
+ var topLeft = [mousePos.x-mouseOffset,mousePos.y-mouseOffset];
+ var bottomRight = [mousePos.x+mouseOffset,mousePos.y+mouseOffset];
+ // Draw a square around the mouse
+ layerCtx.globalAlpha = mouseAlpha;
+ layerCtx.lineWidth = 2;
+ layerCtx.font = `${pixelSize}pt Arial`
+ if (asciicustomcolor_setting.value == false) {
+ layerCtx.fillStyle = mouseColor;
+ }
+ else if (bw_setting.value !== true && asciicolor_setting.value) {
+ layerCtx.fillStyle = asciicolor_setting.value;
+ }
+ else {
+ layerCtx.fillStyle = invertColor(settings.bg)
+ }
+ if (mouseSize > 1) {
+ for (i = mousePos.x-mouseOffset; i <= mousePos.x+mouseOffset; i++) { // top
+ layerCtx.fillText("_", (i)*pixelSize, (mousePos.y-mouseOffset)*pixelSize, pixelSize)
+ }
+ for (i = mousePos.y-mouseOffset; i <= mousePos.y+mouseOffset; i++) { // left
+ layerCtx.fillText("|", (mousePos.x-mouseOffset)*pixelSize, ((i)*pixelSize)+pixelSize, pixelSize)
+ }
+ for (i = mousePos.x+mouseOffset; i >= mousePos.x-mouseOffset; i--) { // bottom
+ layerCtx.fillText("_", (i)*pixelSize, ((mousePos.y+mouseOffset)*pixelSize)+pixelSize, pixelSize)
+ }
+ for (i = mousePos.y+mouseOffset; i >= mousePos.y-mouseOffset; i--) { // right
+ layerCtx.fillText("|", ((mousePos.x+mouseOffset)*pixelSize)+pixelSize, ((i)*pixelSize)+pixelSize, pixelSize)
+ }
+ }
+ else {
+ layerCtx.font = `${pixelSize*1.5}pt Arial`
+ layerCtx.fillText("▢", ((mousePos.x+mouseOffset)*pixelSize)-(pixelSize*0.25), ((mousePos.y+mouseOffset)*pixelSize)+(pixelSize*1.25), pixelSize*1.5)
+ }
+ // draw one transparent pixel in the center
+ if (settings.precision) {
+ layerCtx.fillText("o", mousePos.x*pixelSize, (mousePos.y*pixelSize)+pixelSize, pixelSize)
+ }
+ if (shaping) {
+ if (shaping === 1) { // Draw a white line from shapeStart.x to shapeStart.y
+ let coords = lineCoords(shapeStart.x,shapeStart.y,mousePos.x,mousePos.y);
+ coords.forEach((coord) => {
+ if (outOfBounds(coord[0],coord[1])) return;
+ drawSquare(layerCtx,mouseColor,coord[0],coord[1],undefined,mouseAlpha)
+ })
+ }
+ }
+}
\ No newline at end of file
diff --git a/mods/biology.js b/mods/biology.js
index e88cc1aa..32988991 100644
--- a/mods/biology.js
+++ b/mods/biology.js
@@ -75,22 +75,22 @@ renderPresets.FLESHBURN = function(pixel,ctx) {
var ratio = ((pixel.char/max*100)|0)/100;
if (ratio < 0.5) { return }
if (ratio > 1) { ratio = 1 }
- drawSquare(ctx,"#000000",pixel.x,pixel.y,undefined,Math.min(0.8,(ratio-0.5)*0.8));
+ drawSquare(ctx,"rgb(0,0,0)",pixel.x,pixel.y,undefined,Math.min(0.8,(ratio-0.5)*0.8));
},
renderPresets.NERVE = function(pixel,ctx) {
drawDefault(ctx,pixel)
if (pixel.darkcharge === true) {
- drawSquare(ctx,"#000000",pixel.x,pixel.y,undefined,Math.min(0.8,0.55));
+ drawSquare(ctx,"rgb(0,0,0)",pixel.x,pixel.y,undefined,Math.min(0.8,0.55));
}
if (pixel.darkchargeCD === true) {
- drawSquare(ctx,"#000000",pixel.x,pixel.y,undefined,Math.min(0.8,0.5));
+ drawSquare(ctx,"rgb(0,0,0)",pixel.x,pixel.y,undefined,Math.min(0.8,0.5));
}
if (pixel.lightcharge === true) {
- drawSquare(ctx,"#ffffff",pixel.x,pixel.y,undefined,Math.min(0.8,0.55));
+ drawSquare(ctx,"rgb(255,255,255)",pixel.x,pixel.y,undefined,Math.min(0.8,0.55));
}
if (pixel.lightchargeCD === true) {
- drawSquare(ctx,"#ffffff",pixel.x,pixel.y,undefined,Math.min(0.8,0.5));
+ drawSquare(ctx,"rgb(255,255,255)",pixel.x,pixel.y,undefined,Math.min(0.8,0.5));
}
},
diff --git a/mods/boompaste.js b/mods/boompaste.js
new file mode 100644
index 00000000..b2f8bd2f
--- /dev/null
+++ b/mods/boompaste.js
@@ -0,0 +1,76 @@
+activated_meltpasteBlacklist = ["activated_meltpaste"]
+let v = -1.797693134862315E+308;
+let w = v * 1.001;
+let x = 1.797693134862315E+308;
+let y = x * 1.001;
+elements.boompaste = {
+ temp: y,
+ color: "#008009",
+ behavior: behaviors.MOLTEN,
+ burn:300,
+ category: "Boom",
+ state: "solid",
+ burnTime: 10000,
+ reactions:{
+ "boompaste": { elem1:"boompaste" , elem2: "boompaste"},
+ "fire": { elem1: "boompaste" , elem2:"boompaste" },
+ "plasma": { elem1: "boompaste" , elem2:"boompaste" },
+ "flash":{ elem1: "boompaste" , elem2:"flash" },
+ "water":{ elem1: "flash" , elem2:"flash" },
+ },
+}
+
+//i stole this from the alkest mod (duh) please steal from me -g
+elements.meltpaste = {
+ density:y,
+ temp: y,
+ color: "#755858",
+ behavior: behaviors.POWDER,
+ burn:300,
+ category: "Boom",
+ state: "solid",
+ burnTime: 10000,
+ lowtemp:-1,
+ lowstate:"plasma",
+ tick: function(pixel) {
+ for(i = 0; i < adjacentCoords.length; i++) {
+ if(Math.random() < 0.1) {
+ var pX = pixel.x
+ var pY = pixel.y
+ var oX = adjacentCoords[i][0];
+ var oY = adjacentCoords[i][1];
+ var checkPosX = pX+oX;
+ var checkPosY = pY+oY;
+ if(!isEmpty(checkPosX,checkPosY,true)) {
+ var newPixel = pixelMap[checkPosX][checkPosY];
+ var newElement = newPixel.element;
+ if(!activated_meltpasteBlacklist.includes(newElement)) { //unless someone's willing to implement dragon parts
+ if(typeof(pixel[newElement]) === "undefined") {
+ pixel[newElement] = 0;
+ };
+ pixel[newElement]++;
+ deletePixel(checkPosX,checkPosY);
+ };
+ };
+ };
+ };
+ },
+}
+
+elements.gasoline = {
+ color: "#008000",
+ behavior: behaviors.LIQUID,
+ category: "Boom",
+ state: "liquid",
+ burn:300,
+ burnTime:999 ,
+}
+elements.afterburn = {
+ color: "#c8d600",
+ behavior: behaviors.LIQUID,
+ category: "Boom",
+ state: "liquid",
+ burn:y,
+ burnTime:30,
+ burnInto:["gasoline","afterburn"],
+}
diff --git a/mods/cubesstuff.js b/mods/cubesstuff.js
index 7bd31da7..baea58e7 100644
--- a/mods/cubesstuff.js
+++ b/mods/cubesstuff.js
@@ -1,3 +1,7 @@
+// TypeScript integration for Sandboxels modding
+// Enables function autocomplete & element definition hints
+///
+// Get the file here: https://github.com/Cube14yt/sandboxels-types
// Changelog
// Starts at version 3
@@ -21,8 +25,15 @@ Machines: Robot, Adjustable heater/cooler
Bug Fixes
Fixed compatibility issue with nousersthings.js
-*/
+V4
+Machines: Paper filter, Indestructable filter, and Note block
+Life: Cacao Plants (seed, stem, fruit)
+Tools: Polish
+Extras: 2 ways to make an element with no name
+Special: Black hole
+Building Materials: Roman concrete/cement
+*/
elements.button = {
@@ -567,10 +578,17 @@ keybinds["KeyT"] = function () {
tpsPrompt()
}
-function addRow() {
+function addRowWhenReady() {
const table = document.getElementById("controlsTable");
- const rowCount = table.rows.length;
+ if (!table) {
+ // Table not ready yet, try again in 100ms
+ setTimeout(addRowWhenReady, 100);
+ return;
+ }
+
+ // Table exists, add the row
+ const rowCount = table.rows.length;
const newRow = table.insertRow(rowCount - 1);
const cell1 = newRow.insertCell(0);
@@ -578,9 +596,13 @@ function addRow() {
cell1.textContent = "Change TPS";
cell2.innerHTML = "T";
+
+ console.log("Row added successfully!");
}
-addRow()
+// Start the process
+addRowWhenReady();
+
elements.randomizer = {
buttonColor: ["#ff0000", "#ff8800", "#ffff00", "#00ff00", "#00ffff", "#0000ff", "#ff00ff"],
@@ -1534,6 +1556,7 @@ function tryJump(headPixel) {
elements.robot_head = {
color: "#d9d9d9",
category: "machines",
+ state: "solid",
tick(pixel) {
const body = getPixel(pixel.x, pixel.y + 1);
@@ -1572,6 +1595,7 @@ elements.robot_head = {
elements.robot_body = {
color: "#b1b1b1",
category: "machines",
+ state: "solid",
tick(pixel) {
const head = getPixel(pixel.x, pixel.y - 1);
@@ -1597,6 +1621,7 @@ elements.robot_body = {
elements.robot = {
color: "#b1b1b1",
category: "machines",
+ state: "solid",
onSelect() {
promptChoose(
"Choose robot mode",
@@ -1652,6 +1677,7 @@ elements.broken_adjustable_heater = {
category: "extras",
insulate: true,
behavior: behaviors.WALL,
+
onSelect() {
promptInput(
"Select the temperature you want to adjust to",
@@ -1719,24 +1745,7 @@ elements.adjustable_heater = {
} else if (current_pixel.temp > adjusted_temp) {
current_pixel.temp = Math.max(current_pixel.temp - heatAmount, adjusted_temp);
}
-
- // Phase change check (forces melting/boiling/etc.)
- let elemDef = elements[current_pixel.element];
- if (elemDef) {
- // Too hot for current state → change to high state
- if (typeof elemDef.tempHigh === "number" &&
- current_pixel.temp >= elemDef.tempHigh &&
- elemDef.stateHigh) {
- changePixel(current_pixel, elemDef.stateHigh);
- }
-
- // Too cold for current state → change to low state
- if (typeof elemDef.tempLow === "number" &&
- current_pixel.temp <= elemDef.tempLow &&
- elemDef.stateLow) {
- changePixel(current_pixel, elemDef.stateLow);
- }
- }
+ pixelTempCheck(current_pixel)
}
}
}
@@ -1820,26 +1829,633 @@ elements.adjustable_cooler = {
current_pixel.temp = Math.min(current_pixel.temp + coolAmount, adjusted_cool_temp);
}
- // Phase change check (forces melting/freezing/etc.)
- let elemDef = elements[current_pixel.element];
- if (elemDef) {
- // Too hot → change to high state
- if (typeof elemDef.tempHigh === "number" &&
- current_pixel.temp >= elemDef.tempHigh &&
- elemDef.stateHigh) {
- changePixel(current_pixel, elemDef.stateHigh);
- }
-
- // Too cold → change to low state
- if (typeof elemDef.tempLow === "number" &&
- current_pixel.temp <= elemDef.tempLow &&
- elemDef.stateLow) {
- changePixel(current_pixel, elemDef.stateLow);
- }
- }
+ pixelTempCheck(current_pixel)
}
}
}
};
+let polishedList = new Set()
+elements.polish = {
+ category: "tools",
+ color: ["#a0dff0", "#c0e8f8", "#e0f5ff"],
+ tool(pixel) {
+ let element = pixel.element
+ if ((elements[pixel.element].colorPattern && !polishedList.has(`${pixel.x}, ${pixel.y}`)) || shiftDown) {
+ deletePixel(pixel.x, pixel.y)
+ createPixel(element, pixel.x, pixel.y)
+ polishedList.add(`${pixel.x}, ${pixel.y}`)
+ }
+ },
+ onUnselect() {
+ polishedList.clear()
+ }
+}
+
+elements[" "] = {
+ category: "extras",
+ onSelect() {
+ logMessage("This Element has weird properties since its a space ' '")
+ },
+ alias: "space"
+}
+
+elements.paper_filter = {
+ desc: "Filters solids from liquids",
+ color: "#ececec",
+ behavior: behaviors.WALL,
+ reactions: {
+ "light": { stain1: "#ebdfa7" },
+ "oxygen": { stain1: "#ebdfa7" }
+ },
+ tempHigh: 248,
+ stateHigh: ["fire", "fire", "fire", "fire", "fire", "ash"],
+ burn: 70,
+ burnTime: 300,
+ burnInto: ["fire", "fire", "fire", "fire", "fire", "ash"],
+ category: "machines",
+ density: 1201,
+ breakInto: "confetti",
+ breakIntoColor: ["#ffffff", "#e6e6e6", "#dbdbdb"],
+ tick(pixel) {
+ let upPixel = getPixel(pixel.x, pixel.y - 1)
+
+ if (upPixel && elements[upPixel.element].state == "liquid" && !pixel.con) {
+ deletePixel(pixel.x, pixel.y - 1)
+ pixel.con = upPixel
+ }
+
+ if (upPixel && (upPixel.element === "paper_filter" || upPixel.element === "indestructable_filter") && upPixel.con && !pixel.con) {
+ let liquid = upPixel.con
+ let viscMove = true
+
+ if (elements[liquid.element].viscosity) {
+ viscMove = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
+ }
+
+ if (viscMove) {
+ pixel.con = liquid
+ delete upPixel.con
+ }
+ }
+
+ if (isEmpty(pixel.x, pixel.y + 1) && !outOfBounds(pixel.x, pixel.y + 1) && pixel.con) {
+ let liquid = pixel.con
+ let viscExit = true
+
+ if (elements[liquid.element].viscosity) {
+ viscExit = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
+ }
+
+ if (viscExit) {
+ createPixel(liquid.element, pixel.x, pixel.y + 1)
+ delete pixel.con
+ }
+ }
+ }
+}
+
+elements.indestructable_filter = {
+ desc: "Filters solids from liquids",
+ color: "#aaaaaa",
+ behavior: behaviors.WALL,
+ category: "machines",
+ state: "solid",
+ movable: false,
+ tick(pixel) {
+ let upPixel = getPixel(pixel.x, pixel.y - 1)
+ let belowPixel = getPixel(pixel.x, pixel.y + 1)
+
+ if (upPixel && elements[upPixel.element].state == "liquid" && !pixel.con) {
+ deletePixel(pixel.x, pixel.y - 1)
+ pixel.con = upPixel
+ }
+
+ if (upPixel && (upPixel.element === "indestructable_filter" || upPixel.element === "paper_filter") && upPixel.con && !pixel.con) {
+ let liquid = upPixel.con
+ let viscMove = true
+
+ if (elements[liquid.element].viscosity) {
+ viscMove = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
+ }
+
+ if (viscMove) {
+ pixel.con = liquid
+ delete upPixel.con
+ }
+ }
+
+ if (isEmpty(pixel.x, pixel.y + 1) && !outOfBounds(pixel.x, pixel.y + 1) && pixel.con) {
+ let liquid = pixel.con
+ let viscExit = true
+
+ if (elements[liquid.element].viscosity) {
+ viscExit = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
+ }
+
+ if (viscExit) {
+ createPixel(liquid.element, pixel.x, pixel.y + 1)
+ delete pixel.con
+ }
+ }
+ }
+}
+
+let black_hole_expand = false
+elements.black_hole = {
+ color: "#111111",
+ hardness: 1,
+ category: "special",
+ properties: {
+ absorbed: 0
+ },
+ renderer: function (pixel, ctx) {
+ if (!viewInfo[view].colorEffects) { drawDefault(ctx, pixel); return }
+ renderPresets.HEATGLOW(pixel, ctx);
+ if (pixel.alpha === 0) return;
+
+ let edge = false;
+ pixel.edge = false;
+ pixel.color = "#111111";
+
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y + coords[1];
+ if (!outOfBounds(x, y)) {
+ let neighbor = getPixel(x, y);
+ if (!neighbor || elements[neighbor.element].movable !== elements[pixel.element].movable) {
+ edge = true;
+ break;
+ }
+ }
+ }
+ if (edge) { pixel.color = "#ffae00"; pixel.edge = true }
+ },
+ tick(pixel) {
+ // Glow effect
+ if (pixel.edge) {
+ pixel.glow = true;
+ if (enabledMods.includes("mods/glow.js")) {
+ pixel.emit = 10;
+ }
+ }
+ else {
+ pixel.glow = false;
+ if (enabledMods.includes("mods/glow.js")) {
+ pixel.emit = 0;
+ }
+ }
+
+ // Suction physics
+ let radius = 20; // how far the suction reaches
+ for (let dx = -radius; dx <= radius; dx++) {
+ for (let dy = -radius; dy <= radius; dy++) {
+ if (dx === 0 && dy === 0) continue;
+
+ let x = pixel.x + dx;
+ let y = pixel.y + dy;
+
+ if (!outOfBounds(x, y)) {
+ let other = getPixel(x, y);
+ if (other && other !== pixel) {
+ let elemDef = elements[other.element];
+
+ // Skip if indestructible
+ if (elemDef.hardness === 1) continue;
+
+ // Distance to black hole
+ let dist = Math.sqrt(dx * dx + dy * dy);
+
+ if (dist <= radius) {
+ // Suction chance: closer = stronger pull
+ let chance = 1 / dist;
+ if (Math.random() < chance) {
+ let stepX = Math.sign(pixel.x - x);
+ let stepY = Math.sign(pixel.y - y);
+
+ let newX = x + stepX;
+ let newY = y + stepY;
+
+ if (isEmpty(newX, newY) && !outOfBounds(newX, newY)) {
+ movePixel(other, newX, newY);
+ }
+ else if (dist <= 1.5) {
+ deletePixel(x, y); // absorb it
+ pixel.absorbed++
+ }
+ }
+ }
+ }
+ }
+ }
+ if (black_hole_expand) {
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var x = pixel.x + adjacentCoords[i][0];
+ var y = pixel.y + adjacentCoords[i][1];
+ if (pixel.absorbed >= 30 && isEmpty(x, y)) {
+ createPixel("black_hole", x, y)
+ pixel.absorbed = 0
+ }
+ }
+ }
+ }
+ },
+ forceSaveColor: true,
+ onSelect() {
+ promptChoose(
+ "Do you want the black hole to grow?",
+ ["Yes", "No"],
+ (choice) => {
+ if (!choice) {
+ choice = false
+ }
+ if (choice == "Yes") {
+ black_hole_expand = true
+ }
+ else {
+ black_hole_expand = false
+ }
+ }
+ )
+ }
+};
+
+elements.cacao_fruit = {
+ color: "#854700",
+ behavior: [
+ "XX|ST:cacao_stem|XX",
+ "ST:cacao_stem|XX|ST:cacao_stem",
+ "XX|ST:cacao_stem AND M1|XX"
+ ],
+ isFood: true,
+ burn: 10,
+ burnTime: 100,
+ burnInto: "ash",
+ breakInto: "cacao_bean",
+ category: "food",
+ state: "solid",
+ density: 1000
+}
+
+elements.cacao_bean = {
+ color: "#ffe7ba",
+ isFood: true,
+ behavior: [
+ "XX|XX|XX",
+ "XX|XX|XX",
+ "M2%10|M1|M2%10"
+ ],
+ tempHigh: 100,
+ stateHigh: "dried_cacao_bean",
+ onStateHigh(pixel) { releaseElement(pixel, "steam") },
+ state: "solid",
+ category: "food",
+ density: 1000
+}
+
+elements.dried_cacao_bean = {
+ color: "#61321e",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "sugar_water": { elem2: "melted_chocolate", tempMin: 65 },
+ "water": { elem2: "melted_chocolate", tempMin: 65 }
+ },
+ tempHigh: 400,
+ stateHigh: "ash",
+ isFood: true,
+ category: "food",
+ state: "solid",
+ density: 1000
+}
+
+elements.coffee_bean.reactions.sugar_water = { elem2: "coffee", tempMin: 80 }
+elements.coffee.reactions.sugar_water = { elem2: "coffee", tempMin: 70, chance: 0.2 }
+elements.coffee_ground.reactions.sugar_water = elements.coffee_ground.reactions.water
+
+elements._ = {
+ category: "extras",
+ onSelect() {
+ logMessage("Another way to make an element with no name \"_\"")
+ },
+ alias: ["underscore"]
+}
+
+elements.cacao_seed = {
+ color: "#8b3f00",
+ behavior: behaviors.STURDYPOWDER,
+ cooldown: defaultCooldown,
+ category: "life",
+ tempHigh: 400,
+ stateHigh: "fire",
+ tempLow: -2,
+ stateLow: "frozen_plant",
+ burn: 50,
+ burnTime: 20,
+ state: "solid",
+ tick(pixel) {
+ let belowPixel = getPixel(pixel.x, pixel.y + 1)
+ if ((!isEmpty(pixel.x, pixel.y + 1) && belowPixel) || outOfBounds(pixel.x, pixel.y + 1) && Math.random() <= 0.005) {
+ changePixel(pixel, "cacao_stem")
+ pixel.stage = 1
+ }
+ }
+}
+
+elements.cacao_stem = {
+ color: "#916a00",
+ renderer: renderPresets.WOODCHAR,
+ movable: false,
+ tempHigh: 100,
+ stateHigh: "wood",
+ tempLow: -30,
+ stateLow: "wood",
+ category: "life",
+ burn: 2,
+ burnTime: 300,
+ burnInto: ["sap", "ember", "charcoal", "smoke"],
+ state: "solid",
+ density: 1500,
+ hardness: 0.15,
+ breakInto: ["sap", "sawdust"],
+ seed: "cacao_seed",
+ forceSaveColor: true,
+ stateHighColorMultiplier: 0.95,
+ onPlace(pixel) {
+ pixel.stage = 1
+ },
+ hoverStat(pixel) {
+ if (pixel.stage) return pixel.stage;
+ else return 0;
+ },
+ tick(pixel) {
+ // 1 = trunk
+ // 2 = spread
+ // 3 = stop
+ if (pixel.stage === 1 && isEmpty(pixel.x, pixel.y - 1) && Math.random() <= 0.05) {
+ tryMove(pixel, pixel.x, pixel.y - 1, "cacao_stem")
+ let oldPixel = getPixel(pixel.x, pixel.y + 1)
+ delete oldPixel.stage
+ if (Math.random() <= 0.3) {
+ pixel.stage = 2
+ }
+ }
+ if (pixel.stage === 2) {
+ let rand = Math.random()
+ let nx;
+ if (rand < 0.4) {
+ nx = 1
+ }
+ else if (rand < 0.8) {
+ nx = -1
+ }
+ else nx = 0;
+ if (isEmpty(pixel.x + nx, pixel.y - 1) && Math.random() <= 0.05) {
+ createPixel(["cacao_stem", "plant"], pixel.x + nx, pixel.y - 1)
+ newPixel = getPixel(pixel.x + nx, pixel.y - 1)
+ if (Math.random() <= 0.2) {
+ newPixel.stage = 3
+ }
+ else newPixel.stage = 2;
+ }
+ if (!isEmpty(pixel.x + 1, pixel.y - 1) && !isEmpty(pixel.x, pixel.y - 1) && !isEmpty(pixel.x - 1, pixel.y - 1) && Math.random() <= 0.005) {
+ shuffleArray(adjacentCoordsShuffle)
+ for (var i = 0; i < adjacentCoordsShuffle.length; i++) {
+ var x = pixel.x + adjacentCoordsShuffle[i][0];
+ var y = pixel.y + adjacentCoordsShuffle[i][1];
+ if (isEmpty(x, y) && !pixel.fruitMade) {
+ createPixel("cacao_fruit", x, y)
+ pixel.fruitMade = true
+ pixel.fruitCoordsx = x
+ pixel.fruitCoordsy = y
+ break
+ }
+ }
+ }
+ }
+ if (pixel.fruitCoordsx && pixel.fruitCoordsy) {
+ if (getPixel(pixel.fruitCoordsx, pixel.fruitCoordsy) && getPixel(pixel.fruitCoordsx, pixel.fruitCoordsy).element === "cacao_fruit") return;
+ pixel.fruitMade = false
+ delete pixel.fruitCoordsx
+ delete pixel.fruitCoordsy
+ }
+ }
+}
+
+
+// --- audio setup ---
+const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+
+function playNote(frequency, duration = 1, type = "sine", volume = 0.1) {
+ if (!Number.isFinite(frequency)) {
+ console.error("Invalid frequency:", frequency);
+ return;
+ }
+
+ const osc = audioCtx.createOscillator();
+ const gain = audioCtx.createGain();
+
+ osc.type = type;
+ osc.frequency.value = frequency;
+
+ gain.gain.setValueAtTime(volume, audioCtx.currentTime);
+ osc.connect(gain);
+ gain.connect(audioCtx.destination);
+
+ gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
+
+ osc.start();
+ osc.stop(audioCtx.currentTime + duration);
+}
+
+
+const pianoFrequencies = {
+ "A0": 27.500, "A#0": 29.135, "BB0": 29.135, "B0": 30.868,
+ "C1": 32.703, "C#1": 34.648, "DB1": 34.648, "D1": 36.708,
+ "D#1": 38.891, "EB1": 38.891, "E1": 41.203, "F1": 43.654,
+ "F#1": 46.249, "GB1": 46.249, "G1": 48.999, "G#1": 51.913,
+ "AB1": 51.913, "A1": 55.000, "A#1": 58.270, "BB1": 58.270,
+ "B1": 61.735,
+
+ "C2": 65.406, "C#2": 69.296, "DB2": 69.296, "D2": 73.416,
+ "D#2": 77.782, "EB2": 77.782, "E2": 82.407, "F2": 87.307,
+ "F#2": 92.499, "GB2": 92.499, "G2": 97.999, "G#2": 103.826,
+ "AB2": 103.826, "A2": 110.000, "A#2": 116.541, "BB2": 116.541,
+ "B2": 123.471,
+
+ "C3": 130.813, "C#3": 138.591, "DB3": 138.591, "D3": 146.832,
+ "D#3": 155.563, "EB3": 155.563, "E3": 164.814, "F3": 174.614,
+ "F#3": 184.997, "GB3": 184.997, "G3": 195.998, "G#3": 207.652,
+ "AB3": 207.652, "A3": 220.000, "A#3": 233.082, "BB3": 233.082,
+ "B3": 246.942,
+
+ "C4": 261.626, "C#4": 277.183, "DB4": 277.183, "D4": 293.665,
+ "D#4": 311.127, "EB4": 311.127, "E4": 329.628, "F4": 349.228,
+ "F#4": 369.994, "GB4": 369.994, "G4": 391.995, "G#4": 415.305,
+ "AB4": 415.305, "A4": 440.000, "A#4": 466.164, "BB4": 466.164,
+ "B4": 493.883,
+
+ "C5": 523.251, "C#5": 554.365, "DB5": 554.365, "D5": 587.330,
+ "D#5": 622.254, "EB5": 622.254, "E5": 659.255, "F5": 698.456,
+ "F#5": 739.989, "GB5": 739.989, "G5": 783.991, "G#5": 830.609,
+ "AB5": 830.609, "A5": 880.000, "A#5": 932.328, "BB5": 932.328,
+ "B5": 987.767,
+
+ "C6": 1046.502, "C#6": 1108.731, "DB6": 1108.731, "D6": 1174.659,
+ "D#6": 1244.508, "EB6": 1244.508, "E6": 1318.510, "F6": 1396.913,
+ "F#6": 1479.978, "GB6": 1479.978, "G6": 1567.982, "G#6": 1661.219,
+ "AB6": 1661.219, "A6": 1760.000, "A#6": 1864.655, "BB6": 1864.655,
+ "B6": 1975.533,
+
+ "C7": 2093.005, "C#7": 2217.461, "DB7": 2217.461, "D7": 2349.318,
+ "D#7": 2489.016, "EB7": 2489.016, "E7": 2637.020, "F7": 2793.826,
+ "F#7": 2959.955, "GB7": 2959.955, "G7": 3135.963, "G#7": 3322.438,
+ "AB7": 3322.438, "A7": 3520.000, "A#7": 3729.310, "BB7": 3729.310,
+ "B7": 3951.066,
+
+ "C8": 4186.009
+};
+
+
+let note = 261.626; // default C4
+let notesToPlay = [];
+
+function flushNotes() {
+ if (notesToPlay.length === 0) return;
+
+
+ let baseVolume = 0.2;
+ let volume = baseVolume / Math.sqrt(notesToPlay.length);
+
+ for (let f of notesToPlay) {
+ playNote(f, 1, "sine", volume);
+ }
+
+ notesToPlay = [];
+}
+
+elements.note_block = {
+ color: "#965500",
+ behavior: behaviors.WALL,
+ onSelect() {
+ promptInput(
+ "Select the note this note block should be",
+ function (choice) {
+ if (!choice) {
+ if (!note) { note = 261.626; }
+ return;
+ }
+ let key = choice.toUpperCase();
+ if (key in pianoFrequencies) {
+ note = pianoFrequencies[key];
+ } else {
+ note = 261.626; // fallback = C4
+ }
+ },
+ "Note prompt"
+ );
+ },
+ onPlace(pixel) {
+ pixel.note = note;
+ },
+ tick(pixel) {
+ if (pixel.charge) {
+ notesToPlay.push(Number(pixel.note));
+ }
+ },
+ conduct: 1,
+ category: "machines"
+};
+
+runEveryTick(function () { flushNotes() });
+
+/*
+elements.uncook = {
+ color: ["#4dcdff", "#70ddff", "#bcddff", "#ffffff"],
+ category: "tools",
+ tool(pixel) {
+ if (!pixel || !pixel.element) return;
+
+ // 1) If the current element itself defines stateLow, use it (common case)
+ const cur = elements[pixel.element];
+ if (cur && cur.stateLow !== undefined) {
+ const low = cur.stateLow;
+ pixel.element = Array.isArray(low) ? low[Math.floor(Math.random() * low.length)] : low;
+ if (typeof pixel.temp === "number") pixel.temp = Math.max(0, pixel.temp - 1);
+ return; // done
+ }
+
+ // 2) Otherwise search for an element whose stateHigh === the current element
+ for (const key in elements) {
+ const el = elements[key];
+ if (!el) continue;
+ if (el.stateHigh === pixel.element) {
+ // 'key' is the low-state element name
+ changePixel(pixel, key)
+ if (typeof pixel.temp === "number") pixel.temp = Math.max(0, pixel.temp - 1);
+ return; // done
+ }
+ // If el.stateHigh can be an array of high-state names:
+ if (Array.isArray(el.stateHigh) && el.stateHigh.includes(pixel.element)) {
+ changePixel(pixel, key)
+ if (typeof pixel.temp === "number") pixel.temp = Math.max(0, pixel.temp - 1);
+ return;
+ }
+ }
+ }
+};
+*/
+
+elements.roman_cement = {
+ color: "#b8b8b8",
+ behavior: behaviors.LIQUID,
+ category: "liquids",
+ viscosity: 1000,
+ density: 1400,
+ state: "solid",
+ tempLow: -10,
+ stateLow: "roman_concrete",
+ tempHigh: 1550,
+ stateHigh: "magma",
+ tick(pixel) {
+ if (pixelTicks - pixel.start > 100 && Math.random() <= 0.1) {
+ changePixel(pixel, "roman_concrete")
+ }
+ }
+}
+
+elements.roman_concrete = {
+ color: "#ababab",
+ behavior: behaviors.SUPPORT,
+ tempHigh: 1500,
+ stateHigh: "magma",
+ category: "powders",
+ state: "solid",
+ density: 2400,
+ hardness: 0.5,
+ breakInto: "dust",
+ darkText: true
+}
+
+/**
+ *
+ * @param {string} element
+ * @param {object} reaction
+ * @returns {void}
+ */
+function doWaterReactions(element, reaction) {
+ if (!elements[element].reactions) {
+ elements[element].reactions = {}
+ }
+ elements[element].reactions.water = reaction
+ elements[element].reactions.salt_water = reaction
+ elements[element].reactions.pool_water = reaction
+ elements[element].reactions.sugar_water = reaction
+ elements[element].reactions.dirty_water = reaction
+ elements[element].reactions.selter = reaction
+ elements[element].reactions.primordial_soup = reaction
+ elements[element].reactions.nut_milk = reaction
+}
+
+doWaterReactions("slaked_lime", {elem1:"roman_cement", elem2: null, chance: 0.25})
diff --git a/mods/elementEraser.js b/mods/elementEraser.js
index c2c5ceef..37f1b183 100644
--- a/mods/elementEraser.js
+++ b/mods/elementEraser.js
@@ -4,9 +4,11 @@ let finalEraseElement = null;
elements.element_eraser = {
color: "#eeeeee",
onSelect: function() {
- var answer = prompt("Please input the element you wish to delete. It will not work if you enter multiple element types while paused.",(finalEraseElement||undefined));
- if (!answer) { return }
- finalEraseElement = mostSimilarElement(answer);
+ promptInput("Please input the element you wish to delete. It will not work if you enter multiple element types while paused.", (answer) => {
+ // var answer = prompt("Please input the element you wish to delete. It will not work if you enter multiple element types while paused.",(finalEraseElement||undefined));
+ if (!answer) { return }
+ finalEraseElement = mostSimilarElement(answer);
+ }, "Delete Element")
},
tool: function(pixel) {
if (pixel.element === finalEraseElement) {
@@ -21,9 +23,11 @@ let finalEraseElement2 = null;
elements.exclusive_element_eraser = {
color: "#eeeeee",
onSelect: function() {
- var answer = prompt("Please input the element you do not wish to delete. It will not work if you enter multiple element types while paused.",(finalEraseElement2||undefined));
- if (!answer2) { return }
- finalEraseElement2 = mostSimilarElement(answer2);
+ promptInput("Please input the element you do not wish to delete. It will not work if you enter multiple element types while paused.", (answer2) => {
+ // var answer2 = prompt("Please input the element you do not wish to delete. It will not work if you enter multiple element types while paused.",(finalEraseElement2||undefined));
+ if (!answer2) { return }
+ finalEraseElement2 = mostSimilarElement(answer2);
+ }, "Don't Delete")
},
tool: function(pixel) {
if (pixel.element != finalEraseElement2) {
diff --git a/mods/example_mod.js b/mods/example_mod.js
index d5a1b820..24e74974 100644
--- a/mods/example_mod.js
+++ b/mods/example_mod.js
@@ -1,25 +1,24 @@
-// This is how to add a new mod to the game.
-
+// To create a mod:
// Create a new Javascript file like this one.
// Add the file to the mods folder on GitHub, or host it somewhere else.
// https://github.com/R74nCom/sandboxels/tree/main/mods
-// For more help with modding, check the wiki: https://sandboxels.wiki.gg/wiki/Modding_tutorial
+// To learn about modding, check the wiki: https://sandboxels.wiki.gg/wiki/Modding
// Or join our Discord: https://r74n.com/discord/
-// To add it in the Mod Loader:
+// To add it in the Mod Manager:
// If it is in the mods folder, you can just use the name of the file. (example_mod.js)
// If it is hosted somewhere else, you can use the full URL, including the HTTPS://.
// Adding elements:
-elements.mayo = {
- color: "#ffffff",
+elements.mustard = {
+ color: "#ffff00",
behavior: behaviors.LIQUID,
category: "liquids",
- viscosity: 100000,
state: "liquid",
- density: 720
-};
+ density: 1100,
+ viscosity: 60000,
+}
// Changing existing elements:
elements.water.color = "#ff0000";
@@ -29,15 +28,20 @@ elements.water.behavior = behaviors.WALL;
// Be aware, things may break
delete elements.ketchup;
-// Adding behavior presets:
-behaviors.SELFDELETE = [
- "XX|XX|XX",
- "XX|DL|XX",
- "XX|XX|XX"
-];
+// Custom behaviors:
+elements.blue_sand = {
+ color: "#0000ff",
+ behavior: [
+ "XX|XX|XX",
+ "XX|XX|XX",
+ "M2|M1|M2"
+ ],
+ category: "land",
+ state: "solid"
+}
// Raw JavaScript behaviors:
-behaviors.mud.tick = function(pixel) {
+elements.mud.tick = function(pixel) {
if (tryMove(pixel, pixel.x, pixel.y+1)) {
console.log("Moved!");
}
@@ -57,28 +61,29 @@ elements.sand_exploder = {
category: "tools",
};
-// Add reactions to existing elements
-if (!elements.water.reactions) { // Include this block once
- elements.water.reactions = {} // This creates the property if it doesn't exist
+// Reactions:
+elements.sugar_stick = {
+ color: "#ffffff",
+ behavior: behaviors.STURDYPOWDER,
+ reactions: {
+ "water": { elem1:null, elem2:"sugar_water", chance:0.1 },
+ "salt_water": { elem1:null, elem2:"sugar_water", chance:0.1 }
+ },
+ state: "solid",
+ density: 1580
}
-elements.water.reactions.mayo = { "elem1":null, "elem2":"mayo_water" };
+
+// Add reactions to existing elements:
+// Include this block once to ensure the property exists
+if (!elements.water.reactions) elements.water.reactions = {};
+elements.water.reactions.mustard = { "elem1":null, "elem2":"mustard_water" };
elements.water.reactions.soap = { "elem1":null, "elem2":"soapy_water" };
-// Run after all mods are loaded, for cross-mod compatibility
-runAfterLoad(function() {
- // Your code here
- console.log("Hello World!");
-});
-
-// Run if another mod is active
-dependOn("mods/test.js", function(){
- console.log("Hello World!");
-})
-// More dependency info: See dependency_test.js
-
-// Creating eLists:
-eLists.CONDIMENT = ["ketchup","melted_cheese","mayo"];
-// Adding elements to eLists:
-eLists.CONDIMENT.push("honey");
-
-// Rendering: See 1.10example.js
\ No newline at end of file
+// Custom element renderers:
+elements.ball.renderer = function(pixel,ctx) {
+ // Draw three horizontal squares
+ drawSquare(ctx,"#00ff00",pixel.x-1,pixel.y);
+ drawSquare(ctx,"#00ff00",pixel.x,pixel.y);
+ drawSquare(ctx,"#00ff00",pixel.x+1,pixel.y);
+};
+// See 1.10example.js for more rendering examples.
\ No newline at end of file
diff --git a/mods/example_mod_old.js b/mods/example_mod_old.js
new file mode 100644
index 00000000..400345c0
--- /dev/null
+++ b/mods/example_mod_old.js
@@ -0,0 +1,84 @@
+// This is how to add a new mod to the game.
+
+// Create a new Javascript file like this one.
+// Add the file to the mods folder on GitHub, or host it somewhere else.
+// https://github.com/R74nCom/sandboxels/tree/main/mods
+
+// For more help with modding, check the wiki: https://sandboxels.wiki.gg/wiki/Modding_tutorial
+// Or join our Discord: https://r74n.com/discord/
+
+// To add it in the Mod Loader:
+// If it is in the mods folder, you can just use the name of the file. (example_mod.js)
+// If it is hosted somewhere else, you can use the full URL, including the HTTPS://.
+
+// Adding elements:
+elements.mayo = {
+ color: "#ffffff",
+ behavior: behaviors.LIQUID,
+ category: "liquids",
+ viscosity: 100000,
+ state: "liquid",
+ density: 720
+};
+
+// Changing existing elements:
+elements.water.color = "#ff0000";
+elements.water.behavior = behaviors.WALL;
+
+// Removing elements:
+// Be aware, things may break
+delete elements.ketchup;
+
+// Adding behavior presets:
+behaviors.SELFDELETE = [
+ "XX|XX|XX",
+ "XX|DL|XX",
+ "XX|XX|XX"
+];
+
+// Raw JavaScript behaviors:
+elements.mud.tick = function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) {
+ console.log("Moved!");
+ }
+ else {
+ console.log("Couldn't move!")
+ }
+};
+
+// Create a new tool:
+elements.sand_exploder = {
+ color: "#ff0000",
+ tool: function(pixel) {
+ if (pixel.element == "sand") {
+ pixel.element = "explosion"
+ }
+ },
+ category: "tools",
+};
+
+// Add reactions to existing elements
+if (!elements.water.reactions) { // Include this block once
+ elements.water.reactions = {} // This creates the property if it doesn't exist
+}
+elements.water.reactions.mayo = { "elem1":null, "elem2":"mayo_water" };
+elements.water.reactions.soap = { "elem1":null, "elem2":"soapy_water" };
+
+// Run after all mods are loaded, for cross-mod compatibility
+runAfterLoad(function() {
+ // Your code here
+ console.log("Hello World!");
+});
+
+// Run if another mod is active
+dependOn("mods/test.js", function(){
+ console.log("Hello World!");
+})
+// More dependency info: See dependency_test.js
+
+// Creating eLists:
+eLists.CONDIMENT = ["ketchup","melted_cheese","mayo"];
+// Adding elements to eLists:
+eLists.CONDIMENT.push("honey");
+
+// Rendering: See 1.10example.js
\ No newline at end of file
diff --git a/mods/graphite.js b/mods/graphite.js
new file mode 100644
index 00000000..ceb5ec6c
--- /dev/null
+++ b/mods/graphite.js
@@ -0,0 +1,460 @@
+elements.graphite = {
+ color: "#4d4f4f",
+ behavior: behaviors.POWDER,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.26,
+ tempHigh: 3600,
+ stateHigh: "carbon_gas",
+ flammable: false,
+ reactions: {
+ "oxygen": { elem1: "carbon_dioxide", elem2: null, tempMin: 700 },
+ "fire": { elem1: "carbon_monoxide", elem2: null, tempMin: 700 },
+ "fluorine": { elem1: "carbon_tetrafluoride", elem2: null },
+ "silicon_dioxide": { elem1: "silicon", elem2: "carbon_monoxide", tempMin: 1700 }
+ }
+};
+
+/* Carbon (solid) */
+elements.carbon = {
+ color: "#7a7d7d",
+ behavior: behaviors.POWDER,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.2,
+ tempHigh: 3600,
+ stateHigh: "carbon_gas",
+ flammable: false,
+ reactions: {
+ "oxygen": { elem1: "carbon_dioxide", elem2: null, tempMin: 700 },
+ "fire": { elem1: "carbon_monoxide", elem2: null, tempMin: 700 },
+ "fluorine": { elem1: "carbon_tetrafluoride", elem2: null },
+ "silicon_dioxide": { elem1: "silicon", elem2: "carbon_monoxide", tempMin: 1700 }
+ }
+};
+
+/* Carbon gas (vapor) */
+elements.carbon_gas = {
+ color: "#666666",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 0.0018,
+ reactions: {
+ "oxygen": { elem1: "carbon_monoxide", elem2: null },
+ "fluorine": { elem1: "carbon_tetrafluoride", elem2: null },
+ "hydrogen": { elem1: "hydrocarbon_gas", elem2: null, tempMin: 1200 },
+ "silicon": { elem1: "silicon_carbide", elem2: null, tempMin: 1400 }
+ }
+};
+
+/* Hydrocarbon gas (generic hydrocarbon product placeholder) */
+elements.hydrocarbon_gas = {
+ color: "#ffdca3",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 0.7,
+ reactions: {
+ "oxygen": { elem1: "carbon_dioxide", elem2: "water" },
+ "fire": { elem1: "carbon_dioxide", elem2: "water" },
+ "fluorine": { elem1: "carbon_tetrafluoride", elem2: "hydrogen_fluoride" },
+ "water": { elem1: "water", elem2: null }
+ }
+};
+
+/* Carbon monoxide */
+elements.carbon_monoxide = {
+ color: "#bfbfbf",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 1.145,
+ reactions: {
+ "oxygen": { elem1: "carbon_dioxide", elem2: null },
+ "fire": { elem1: "carbon_dioxide", elem2: null },
+ "iron_oxide": { elem1: "iron", elem2: "carbon_dioxide", tempMin: 800 },
+ "fluorine": { elem1: "carbonyl_fluoride", elem2: null }
+ }
+};
+
+/* Carbonyl fluoride (COF2) */
+elements.carbonyl_fluoride = {
+ color: "#cfeef0",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 2.5,
+ reactions: {
+ "water": { elem1: "carbon_dioxide", elem2: "hydrogen_fluoride" },
+ "fire": { elem1: "carbon_dioxide", elem2: "fluorine" },
+ "hydrofluoric_acid": { elem1: "hydrogen_fluoride", elem2: "carbon_dioxide" },
+ "oxygen": { elem1: "carbon_dioxide", elem2: "fluorine" }
+ }
+};
+
+/* Fluorine */
+elements.fluorine = {
+ color: "#b5e61d",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 1.696,
+ temp: 25,
+ flammable: false,
+ reactions: {
+ "graphite": { elem1: "carbon_tetrafluoride", elem2: null },
+ "carbon": { elem1: "carbon_tetrafluoride", elem2: null },
+ "hydrogen": { elem1: "hydrogen_fluoride", elem2: null },
+ "water": { elem1: "hydrogen_fluoride", elem2: "oxygen" },
+ "silicon": { elem1: "silicon_tetrafluoride", elem2: null }
+ }
+};
+
+/* Carbon tetrafluoride (CF4) */
+elements.carbon_tetrafluoride = {
+ color: "#ccffff",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 3.72,
+ flammable: false,
+ reactions: {
+ "fire": { elem1: "carbon_dioxide", elem2: "fluorine", tempMin: 2000 },
+ "silicon": { elem1: "silicon_tetrafluoride", elem2: "carbon", tempMin: 900 },
+ "molten_silicon": { elem1: "silicon_tetrafluoride", elem2: "carbon", tempMin: 900 },
+ "silicon_dioxide": { elem1: "silicon_tetrafluoride", elem2: "carbon_monoxide", tempMin: 1500 }
+ }
+};
+
+/* Hydrogen fluoride (gas) */
+elements.hydrogen_fluoride = {
+ color: "#e0ffff",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 0.98,
+ temp: 25,
+ flammable: false,
+ reactions: {
+ "water": { elem1: "hydrofluoric_acid", elem2: null },
+ "silicon_dioxide": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "calcium_carbonate": { elem1: "calcium_fluoride", elem2: "carbon_dioxide" },
+ "calcium_hydroxide": { elem1: "calcium_fluoride", elem2: "water" }
+ }
+};
+
+/* Hydrofluoric acid (aqueous HF) */
+elements.hydrofluoric_acid = {
+ color: "#66ccff",
+ behavior: behaviors.LIQUID,
+ category: "GraphiteMod",
+ state: "liquid",
+ density: 1.15,
+ tempLow: -83,
+ stain: "#99ddff",
+ reactions: {
+ "glass": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "sand": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "silicon_dioxide": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "calcium_carbonate": { elem1: "calcium_fluoride", elem2: "carbon_dioxide" },
+ "calcium_hydroxide": { elem1: "calcium_fluoride", elem2: "water" }
+ }
+};
+
+/* Silicon tetrafluoride */
+elements.silicon_tetrafluoride = {
+ color: "#e6ffff",
+ behavior: behaviors.GAS,
+ category: "GraphiteMod",
+ state: "gas",
+ density: 1.66,
+ flammable: false,
+ reactions: {
+ "water": { elem1: "hydrofluoric_acid", elem2: "silicon_dioxide" },
+ "sand": { elem1: "hydrofluoric_acid", elem2: "silicon_dioxide" },
+ "glass": { elem1: "hydrofluoric_acid", elem2: "silicon_dioxide" },
+ "calcium_hydroxide": { elem1: "calcium_fluoride", elem2: "hydrofluoric_acid" }
+ }
+};
+
+/* Silicon (solid) */
+elements.silicon = {
+ color: "#9a9a9a",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.33,
+ tempHigh: 1414,
+ stateHigh: "molten_silicon",
+ flammable: false,
+ reactions: {
+ "oxygen": { elem1: "silicon_dioxide", elem2: null, tempMin: 500 },
+ "fluorine": { elem1: "silicon_tetrafluoride", elem2: null },
+ "hydrofluoric_acid": { elem1: "silicon_tetrafluoride", elem2: null },
+ "carbon_tetrafluoride": { elem1: "silicon_tetrafluoride", elem2: "carbon", tempMin: 900 }
+ }
+};
+
+elements.molten_silicon = {
+ color: "#ffb366",
+ behavior: behaviors.LIQUID,
+ category: "GraphiteMod",
+ state: "liquid",
+ density: 2.5,
+ temp: 1414,
+ stateLow: "silicon",
+ reactions: {
+ "oxygen": { elem1: "silicon_dioxide", elem2: null },
+ "fluorine": { elem1: "silicon_tetrafluoride", elem2: null },
+ "carbon_tetrafluoride": { elem1: "silicon_tetrafluoride", elem2: "carbon" },
+ "graphite": { elem1: "silicon_carbide", elem2: null, tempMin: 1500 }
+ }
+};
+
+/* Silicon dioxide (quartz / sand) */
+elements.silicon_dioxide = {
+ color: "#f2f2f2",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.65,
+ tempHigh: 1710,
+ stateHigh: "molten_silicon_dioxide",
+ flammable: false,
+ reactions: {
+ "hydrofluoric_acid": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "hydrogen_fluoride": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "graphite": { elem1: "silicon", elem2: "carbon_monoxide", tempMin: 1700 },
+ "carbon": { elem1: "silicon", elem2: "carbon_monoxide", tempMin: 1700 }
+ }
+};
+
+elements.molten_silicon_dioxide = {
+ color: "#ffcc99",
+ behavior: behaviors.LIQUID,
+ category: "GraphiteMod",
+ state: "liquid",
+ density: 2.3,
+ temp: 1710,
+ stateLow: "silicon_dioxide",
+ flammable: false,
+ reactions: {
+ "hydrofluoric_acid": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "hydrogen_fluoride": { elem1: "silicon_tetrafluoride", elem2: "water" },
+ "graphite": { elem1: "silicon", elem2: "carbon_monoxide", tempMin: 1700 },
+ "carbon": { elem1: "silicon", elem2: "carbon_monoxide", tempMin: 1700 }
+ }
+};
+
+/* Calcium carbonate (limestone) */
+elements.calcium_carbonate = {
+ color: "#fffccc",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.71,
+ flammable: false,
+ reactions: {
+ "acid": { elem1: "carbon_dioxide", elem2: "water" },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: "carbon_dioxide" },
+ "hydrogen_fluoride": { elem1: "calcium_fluoride", elem2: "carbon_dioxide" },
+ "fire": { elem1: "calcium_oxide", elem2: "carbon_dioxide", tempMin: 850 }
+ }
+};
+
+/* Calcium oxide (quicklime) */
+elements.calcium_oxide = {
+ color: "#fafafa",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 3.34,
+ tempHigh: 2572,
+ stateHigh: "molten_calcium_oxide",
+ reactions: {
+ "water": { elem1: "calcium_hydroxide", elem2: null },
+ "carbon_dioxide": { elem1: "calcium_carbonate", elem2: null },
+ "hydrogen_fluoride": { elem1: "calcium_fluoride", elem2: "water" },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: "water" }
+ }
+};
+
+elements.molten_calcium_oxide = {
+ color: "#f0e6cc",
+ behavior: behaviors.LIQUID,
+ category: "GraphiteMod",
+ state: "liquid",
+ density: 3.0,
+ temp: 2572,
+ stateLow: "calcium_oxide",
+ reactions: {
+ "water": { elem1: "calcium_hydroxide", elem2: null },
+ "carbon_dioxide": { elem1: "calcium_carbonate", elem2: null },
+ "hydrogen_fluoride": { elem1: "calcium_fluoride", elem2: "water" },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: "water" }
+ }
+};
+
+/* Calcium hydroxide (slaked lime) */
+elements.calcium_hydroxide = {
+ color: "#f9fff9",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.21,
+ flammable: false,
+ reactions: {
+ "carbon_dioxide": { elem1: "calcium_carbonate", elem2: "water" },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: "water" },
+ "hydrogen_fluoride": { elem1: "calcium_fluoride", elem2: "water" },
+ "silicon_tetrafluoride": { elem1: "calcium_fluoride", elem2: "hydrofluoric_acid" }
+ }
+};
+
+/* Calcium fluoride (fluorspar) */
+elements.calcium_fluoride = {
+ color: "#ccccff",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 3.18,
+ flammable: false,
+ reactions: {
+ "acid": { elem1: "hydrofluoric_acid", elem2: "calcium_sulfate" },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: null },
+ "hydrogen_fluoride": { elem1: "calcium_fluoride", elem2: null },
+ "molten_silicon_dioxide": { elem1: "calcium_silicate", elem2: null }
+ }
+};
+
+/* Calcium silicate (simple placeholder for Ca-silicates) */
+elements.calcium_silicate = {
+ color: "#ddd8cc",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.9,
+ flammable: false,
+ reactions: {
+ "acid": { elem1: "calcium_fluoride", elem2: "silicon_tetrafluoride" },
+ "water": { elem1: "calcium_hydroxide", elem2: "silicon_dioxide" },
+ "fire": { elem1: "molten_calcium_silicate", elem2: null, tempMin: 1400 },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: "silicon_tetrafluoride" }
+ }
+};
+
+elements.molten_calcium_silicate = {
+ color: "#f0e6cc",
+ behavior: behaviors.LIQUID,
+ category: "GraphiteMod",
+ state: "liquid",
+ density: 2.9,
+ temp: 1400,
+ stateLow: "calcium_silicate",
+ flammable: false
+};
+
+/* Calcium sulfate (gypsum/anhydrite) */
+elements.calcium_sulfate = {
+ color: "#e6e6e6",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.96,
+ flammable: false,
+ reactions: {
+ "water": { elem1: "gypsum", elem2: null },
+ "carbon": { elem1: "calcium_sulfide", elem2: "carbon_dioxide", tempMin: 1200 },
+ "hydrofluoric_acid": { elem1: "calcium_fluoride", elem2: "acid" },
+ "hydrogen_fluoride": { elem1: "calcium_fluoride", elem2: "acid" }
+ }
+};
+
+/* Gypsum (hydrated CaSO4) */
+elements.gypsum = {
+ color: "#f3f3f3",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.32,
+ flammable: false,
+ reactions: {
+ "fire": { elem1: "calcium_sulfate", elem2: "water", tempMin: 250 },
+ "acid": { elem1: "calcium_sulfate", elem2: "acid" },
+ "carbon": { elem1: "calcium_sulfide", elem2: "carbon_dioxide", tempMin: 1200 },
+ "water": { elem1: "gypsum", elem2: null }
+ }
+};
+
+/* Calcium sulfide (product of high-T reduction) */
+elements.calcium_sulfide = {
+ color: "#cfa76f",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 2.8,
+ flammable: false,
+ reactions: {
+ "water": { elem1: "hydrogen_sulfide", elem2: null },
+ "acid": { elem1: "hydrogen_sulfide", elem2: "calcium_fluoride" },
+ "fire": { elem1: "calcium_sulfide", elem2: null },
+ "carbon_dioxide": { elem1: "calcium_carbonate", elem2: "sulfur_dioxide" }
+ }
+};
+
+
+elements.silicon_carbide = {
+ color: "#2e2e2e",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 3.21,
+ tempHigh: 2730,
+ stateHigh: "molten_silicon_carbide",
+ reactions: {
+ "oxygen": { elem1: "silicon_dioxide", elem2: "carbon_dioxide", tempMin: 1000 },
+ "fluorine": { elem1: "silicon_tetrafluoride", elem2: "carbon_tetrafluoride", tempMin: 500 },
+ "hydrofluoric_acid": { elem1: "silicon_tetrafluoride", elem2: "carbon_tetrafluoride" },
+ "hydrogen_fluoride": { elem1: "silicon_tetrafluoride", elem2: "carbon_tetrafluoride" }
+ }
+};
+
+elements.molten_silicon_carbide = {
+ color: "#443f3f",
+ behavior: behaviors.LIQUID,
+ category: "GraphiteMod",
+ state: "liquid",
+ density: 3.2,
+ temp: 2730,
+ stateLow: "silicon_carbide",
+ flammable: false
+};
+
+/* Paper with graphite (drawing) */
+elements.paper_with_graphite = {
+ color: "#888888",
+ behavior: behaviors.SOLID,
+ category: "GraphiteMod",
+ state: "solid",
+ density: 0.8,
+ flammable: true,
+ reactions: {
+ "fire": { elem1: "ash", elem2: "smoke" },
+ "oxygen": { elem1: "ash", elem2: "smoke", tempMin: 300 },
+ "water": { elem1: "paper", elem2: null },
+ "hydrofluoric_acid": { elem1: "ash", elem2: "acid" }
+ }
+};
+
+elements.eraser = {
+ color: "#ffffff",
+ tool: function(pixel) {
+ if (pixel.element == "paper_with_graphite") {
+ pixel.element = "paper"
+ pixel.color = "#ffffff"
+ }
+ },
+ category: "tools",
+};
+
diff --git a/mods/morechemistry.js b/mods/morechemistry.js
index 8576022b..25221c1b 100644
--- a/mods/morechemistry.js
+++ b/mods/morechemistry.js
@@ -1,19 +1,36 @@
/*
-Version 2.0.0
+Version 2.1.0
*/
-function multiChoice(text, handler, title) {
- let pause = false;
- if (promptState) { pause = promptState.wasPaused }
- else if (paused) { pause = true }
- promptState = {
- type: "confirm",
- text: text,
- handler: handler,
- title: title || "Are you sure?",
- wasPaused: pause
- }
- showPromptScreen();
- }
+
+function pixelToggle(pixel, multi = {r:1,g:1,b:1}){
+ if(pixel.toggle != undefined){
+ pixel.toggle = !pixel.toggle;
+ let rgb;
+ if(Array.isArray(elements[pixel.element].color)){
+ let elemColor = elements[pixel.element].color[Math.round(Math.random()*elements[pixel.element].color.length)];
+ rgb = hexToRGB(elemColor) || getRGB(elemColor);
+ } else {
+ let elemColor = elements[pixel.element].color;
+ rgb = hexToRGB(elemColor) || getRGB(elemColor);
+ }
+ let num = 5 - Math.round(Math.random()*10);
+ if(pixel.toggle){
+ for(let key in rgb){
+ rgb[key] += (100*multi[key]);
+ rgb[key] = Math.round(Math.max(Math.min(rgb[key], 255), 0));
+ }
+ pixel.color = `rgb(${rgb.r+num},${rgb.g+num},${rgb.b+num})`;
+ }
+ else {
+ pixel.color = `rgb(${rgb.r+num},${rgb.g+num},${rgb.b+num})`;
+ }
+ }
+}
+function getRGB(rgb){
+ let rgb2 = rgb.replace(")", "").replace("rgb(", "").replace(/,/g, "r").split("r")
+ return { r: parseInt(rgb2[0]), g: parseInt(rgb2[1]), b: parseInt(rgb2[2]) };
+}
+elements.cloner.keyInput = "str:clone", elements.ecloner.keyInput = "str:clone", elements.slow_cloner.keyInput = "str:clone", elements.floating_cloner.keyInput = "str:clone";
let xDown = false;
elements.copper_sulfate = {
behavior: behaviors.POWDER,
@@ -57,18 +74,23 @@ elements.copper_sulfate = {
tick: function(pixel){
if(pixelTicks-pixel.start == 2 && xDown){
pixel.anhydrous = true;
- }
- let colour;
- let num = Math.round(Math.random()*2);
- if(pixel.anhydrous && !["rgb(235,247,250)","rgb(242,248,250)"].includes(pixel.color)){
- pixel.color = ["rgb(235,247,250)","rgb(242,248,250)"][num];
- } else if (!pixel.anhydrous && !['rgb(67,145,253)', 'rgb(0,76,254)'].includes(pixel.color)){
- pixel.color = ['rgb(67,145,253)', 'rgb(0,76,254)'][num];
+ let rgb = {r: 235, g: 247, b: 250};
+ let num = 6 - (Math.round(Math.random()*12));
+ for(let key in rgb){
+ rgb[key] += num;
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
}
let multi = (pixel.temp-70)/100;
multi = (multi < 0) ? 0 : ((multi > 1) ? 1 : multi);
if(Math.random() < 0.05*multi){
pixel.anhydrous = true;
+ let rgb = {r: 235, g: 247, b: 250};
+ let num = 6 - (Math.round(Math.random()*12));
+ for(let key in rgb){
+ rgb[key] += num;
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
}
if(pixel.anhydrous){
let neighbors = [];
@@ -78,12 +100,26 @@ elements.copper_sulfate = {
}
if(neighbors.includes("air") && pixel.temp < 50 && Math.random() < 0.00035){
pixel.anhydrous = false;
+ let rgb = (Math.random() > 0.5) ? {r: 67, g: 145, b: 253} : {r: 0, g: 76, b: 254};
+ let num = 6 - (Math.round(Math.random()*12));
+ for(let key in rgb){
+ rgb[key] += num;
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
+
} else if (neighbors.includes("steam") || neighbors.includes("water") || neighbors.includes("salt_water") || neighbors.includes("sugar_water") || neighbors.includes("dirty_water") || neighbors.includes("seltzer") || neighbors.includes("pool_water") || neighbors.includes("slush")){
pixel.anhydrous = false;
+ let rgb = (Math.random() > 0.5) ? {r: 67, g: 145, b: 253} : {r: 0, g: 76, b: 254};
+ let num = 6 - (Math.round(Math.random()*12));
+ for(let key in rgb){
+ rgb[key] += num;
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
}
}
}
}
+elements.water.ignore = ["copper_sulphate"], elements.steam.ignore = ["copper_sulphate"], elements.pool_water.ignore = ["copper_sulphate", 'pool_ice'], elements.salt_water.ignore = ["copper_sulphate", 'salt_ice'], elements.sugar_water.ignore = ["copper_sulphate", 'sugar_ice'], elements.seltzer.ignore = ["copper_sulphate", 'seltzer_ice'],
document.addEventListener("keydown", (e)=>{xDown = (e.key.toLowerCase() == "x") ? true : xDown;});
document.addEventListener("keyup", (e)=>{xDown = (e.key.toLowerCase() == "x") ? false : xDown;});
@@ -94,18 +130,20 @@ elements.toggle_cloner = {
color: "#333300",
name: "ToggleableCloner",
keyInput: "chance",
+ insulate: 1,
properties: {
clone: null,
toggle: false,
chance: 0.0166666667,
clickCd: 0,
},
- ignore: ["cloner", "toggle_cloner", "floating_cloner", "clone_powder", "slow_cloner", "ecloner", "destroyable_cloner", "destroyable_clone_powder", "ewall", "wall"],
+ hardness: 1,
+ ignore: ["drag","unknown", "cloner", "toggle_cloner", "floating_cloner", "clone_powder", "slow_cloner", "ecloner", "destroyable_cloner", "destroyable_clone_powder", "ewall", "wall"],
onClicked: function(pixel,element){
if(pixel.clone == null && pixel.clickCd == 0 && dragStart == null){
- pixel.clone = (element == "unknown" || elements.toggle_cloner.ignore.includes(element)) ? pixel.clone : element;
- } else if (pixel.clickCd == 0) {
+ pixel.clone = (elements.toggle_cloner.ignore.includes(element)) ? pixel.clone : element;
+ } else if (pixel.clickCd == 0 && !shiftDown) {
pixel.toggle = !pixel.toggle;
if(pixel.toggle){
let rgb = hexToRGB(elements.toggle_cloner.active);
@@ -125,14 +163,16 @@ elements.toggle_cloner = {
pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
}
}
+ if(shiftDown && !elements.toggle_cloner.ignore.includes(element)){
+ pixel.clone = element;
+ }
if(pixel.clickCd == 0 && dragStart == null){
pixel.clickCd = 20;
- console.log(element);
};
},
onSelect: function(){
- logMessage("Click on the pixel while adjacent to a clonable pixel to set clone, then click on it to toggle on or off.");
+ logMessage("Place cloner, select element to clone, click on the pixel to set the clone element, then click on it to toggle on or off. Hold shift when clicking to change the element to the selected element.");
},
tick: function(pixel){
if(pixel.clickCd > 0){pixel.clickCd--;}
@@ -141,6 +181,7 @@ elements.toggle_cloner = {
let x = pixel.x+coords[0], y = pixel.y+coords[1];
if(isEmpty(x,y) && !outOfBounds(x,y)){
createPixel(pixel.clone, x, y);
+ pixelMap[x][y].temp = pixel.temp;
}
}
}
@@ -154,6 +195,48 @@ elements.toggle_cloner = {
}
};
+elements.multi_toggle_cloner = {
+ category: "machines",
+ color: "#283300",
+ keyInput: "chance",
+ ignore: ["unknown", "cloner", "toggle_cloner", "floating_cloner", "clone_powder", "slow_cloner", "ecloner", "destroyable_cloner", "destroyable_clone_powder", "ewall", "wall"],
+ properties: {
+ cloneElems: [],
+ toggle: false,
+ clickCd: 0,
+ chance: 0.45,
+ },
+ hardness: 1,
+ insulate: 1,
+ onClicked: function(pixel, element){
+ if(pixel.clickCd == 0 && !shiftDown && dragStart == null){
+ pixelToggle(pixel, {r:1.5,g:1.5,b:0});
+ pixel.clickCd = 20;
+ }
+ if(shiftDown && !elements.multi_toggle_cloner.ignore.includes(element)){
+ if(pixel.cloneElems.includes(element)){
+ pixel.cloneElems.splice(pixel.cloneElems.indexOf(element), 1);
+ } else {
+ pixel.cloneElems.push(element);
+ }
+ }
+ },
+ tick: function(pixel){
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random() < pixel.chance && pixel.toggle && JSON.stringify(pixel.cloneElems) != "[]"){
+ elem = pixel.cloneElems[Math.round(Math.random()*pixel.cloneElems.length)];
+ createPixel(elem, x, y);
+ pixelMap[x][y].temp = pixel.temp;
+ }
+ }
+ pixel.clickCd -= (pixel.clickCd == 0) ? 0 : 1;
+ },
+ onSelect: function(){
+ logMessage("Place cloner, then add elements to the clone list by selecting the element and hold down shift while clicking in it, then click on it to toggle on or off. Shift clicking with an element already found in the list will remove it.");
+ }
+}
+
elements.toggle = {
category: "machines",
active: "#b8b8b8",
@@ -163,6 +246,7 @@ elements.toggle = {
toggle: false,
clickCd: 0,
},
+ hardness: 1,
onClicked: function(pixel){
if(pixel.clickCd == 0 && dragStart == null){
pixel.toggle = !pixel.toggle;
@@ -198,7 +282,37 @@ elements.toggle = {
}
}
-
+elements.e_temper = {
+ category: "machines",
+ color: "#ffb300",
+ conduct: 1,
+ targetTemp: 25,
+ hardness: 1,
+ onSelect: function(){
+ promptInput("Enter the target temperature:", (In)=>{
+ this.targetTemp = parseInt(In) || this.targetTemp;
+ }, "Temperature Selector", this.targetTemp);
+ },
+ properties: {
+ targetTemp: null
+ },
+ keyInput: "targetTemp",
+ tick: function(pixel){
+ if(pixel.targetTemp == null){
+ pixel.targetTemp = elements.e_temper.targetTemp;
+ }
+
+ doElectricity(pixel, 1);
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2 != null && pixel.charge > 0){
+ let difference = pixel.targetTemp-p2.temp;
+ p2.temp += difference/4;
+ }
+ }
+ }
+}
elements.toggle_temper = {
active: "#ff7b00",
@@ -207,6 +321,7 @@ elements.toggle_temper = {
category: "machines",
targetTemp: 25,
keyInput: "targetTemp",
+ hardness: 1,
properties: {
toggle: false,
clickCd: 0,
@@ -260,12 +375,16 @@ elements.multitool = {
category: "tools",
input: 0,
onSelect: function(){
- promptInput("Multitool for morechemistry.js, changes key values for different elements added in morechemistry.js, chance for toggleable cloner, and targetTemp for toggleable temper.", (In)=>{
- this.input = parseFloat(In) || 0;
+ promptInput("Multitool for morechemistry.js, changes key values for different elements added in morechemistry.js, chance for toggleable cloner, targetTemp for toggleable temper, clone for other cloners, and channel for portals.", (In)=>{
+ this.input = In;
}, "Multitool Input", this.input);
},
tool: function(pixel){
- pixel[elements[pixel.element].keyInput] = this.input;
+ if(elements[pixel.element].keyInput != undefined){
+ let type = (elements[pixel.element].keyInput.startsWith("int:")) ? "int" : (elements[pixel.element].keyInput.startsWith("str:")) ? "string" : "int";
+ let In = elements[pixel.element].keyInput.slice(elements[pixel.element].keyInput.indexOf(":")+1, elements[pixel.element].keyInput.length);
+ pixel[In] = (type == "int") ? parseFloat(this.input) : this.input;
+ }
},
canPlace: false,
}
@@ -295,6 +414,21 @@ class rangeTool {
}
}
+elements.button = {
+ category: "machines",
+ color: "#c7c7c7",
+ hardness: 1,
+ onClicked: function(pixel){
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p = getPixel(x,y);
+ if(p != null && elements[p.element].conduct){
+ p.charge = 1;
+ }
+ }
+ }
+}
+
elements.toggle_mixer = new rangeTool("#212420", (pixel)=>{
let range = mouseRange(pixel.x, pixel.y, pixel.range);
let pixels = [];
@@ -343,6 +477,7 @@ elements.toggle_mixer = new rangeTool("#212420", (pixel)=>{
};
});
elements.toggle_mixer.inactive = "#212420", elements.toggle_mixer.active = "#93a390", elements.toggle_mixer.movable = false, elements.toggle_mixer.keyInput = "chance";
+elements.toggle_mixer.hardness = 1;
elements.toggle_smasher = new rangeTool("#2e2726", (pixel)=>{
let range = mouseRange(pixel.x, pixel.y, pixel.range);
@@ -380,3 +515,446 @@ elements.toggle_smasher = new rangeTool("#2e2726", (pixel)=>{
};
});
elements.toggle_smasher.inactive = "#2e2726", elements.toggle_smasher.active = "#bf9e9b", elements.toggle_smasher.movable = false, elements.toggle_smasher.keyInput = "chance";
+elements.toggle_smasher.hardness = 1;
+
+elements.target_toggle_smasher = new rangeTool("#332422", (pixel)=>{
+ let range = mouseRange(pixel.x, pixel.y, pixel.range);
+ for(let coords of range){
+ let p2 = getPixel(coords[0], coords[1]);
+ if(p2 != null && pixel.toggle && Math.random() < pixel.chance && elements[p2.element].breakInto != undefined && pixel.targetElems.includes(p2.element)){
+ let elem = (Array.isArray(elements[p2.element].breakInto)) ? elements[p2.element].breakInto[Math.round(Math.random()*elements[p2.element].breakInto.length)] : elements[p2.element].breakInto;
+ if(elem != undefined){
+ changePixel(p2, elem);
+ }
+ }
+ }
+ if(pixel.clickCd > 0){pixel.clickCd--;}
+}, {range: null, toggle: false, clickCd: 0, chance: 0.35, targetElems: []}, ()=>{
+ promptInput("Enter the range for this tool: ", (range)=>{
+ console.log(range);
+ elements.target_toggle_smasher.range = parseInt(range);
+ logMessage("Place smasher, then add elements to the target list by selecting the element and hold down shift while clicking on the pixel, then click on it to toggle on or off. Shift clicking with an element already found in the list will remove it.");
+ }, "Enter range", elements.target_toggle_smasher.range);
+}, (pixel, elem)=>{
+ if(pixel.clickCd == 0 && dragStart == null && !shiftDown){
+ pixel.toggle = !pixel.toggle;
+ pixel.clickCd = 20;
+ if(pixel.toggle){
+ let rgb = hexToRGB(elements.target_toggle_smasher.active);
+ let num = 5 - (Math.random()*10);
+ for(let key in rgb){
+ rgb[key] += num;
+ rgb[key] = Math.round(Math.max(Math.min(rgb[key], 255), 0));
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
+ } else {
+ let rgb = hexToRGB(elements.target_toggle_smasher.inactive);
+ let num = 5 - (Math.random()*10);
+ for(let key in rgb){
+ rgb[key] += num;
+ rgb[key] = Math.round(Math.max(Math.min(rgb[key], 255), 0));
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
+ }
+ };
+ if(shiftDown && elements[elem].breakInto != undefined){
+ if(pixel.targetElems.includes(elem)){
+ pixel.targetElems.splice(pixel.targetElems.indexOf(elem), 1);
+ } else {
+ pixel.targetElems.push(elem);
+ }
+ }
+});
+elements.target_toggle_smasher.inactive = "#332422", elements.target_toggle_smasher.active = "#b57a72", elements.target_toggle_smasher.movable = false, elements.target_toggle_smasher.keyInput = "chance";
+elements.target_toggle_smasher.hardness = 1;
+
+elements.target_toggle_mixer = new rangeTool("#1f291b", (pixel)=>{
+
+ let range = mouseRange(pixel.x, pixel.y, pixel.range);
+ let pixels = [];
+ for(let coords of range){
+ let p2 = getPixel(coords[0], coords[1]);
+ if(p2 != null && pixel.toggle){
+ pixels.push(p2);
+ }
+ }
+ for(let p of pixels){
+ if(Math.random() < pixel.chance){
+ let p2 = pixels[Math.round(Math.random()*pixels.length)];
+ if(p != undefined && p2 != undefined && elements[p.element].movable && elements[p2.element].movable && pixel.targetElems.includes(p.element) && pixel.targetElems.includes(p2.element)){
+ swapPixels(p, p2);
+ if(elements[p.element].onMix != undefined){
+ elements[p.element].onMix(p);
+ }
+ if(elements[p2.element].onMix != undefined){
+ elements[p2.element].onMix(p2);
+ }
+ }
+ }
+ }
+ if(pixel.clickCd > 0){pixel.clickCd--;}
+}, {range: null, toggle: false, clickCd: 0, chance: 0.35, targetElems: []}, ()=>{
+ promptInput("Enter the range for this tool: ", (range)=>{
+ console.log(range);
+ elements.target_toggle_mixer.range = parseInt(range);
+ logMessage("Place mixer, then add elements to the target list by selecting the element and hold down shift while clicking on the pixel, then click on it to toggle on or off. Shift clicking with an element already found in the list will remove it.");
+ }, "Enter range", elements.target_toggle_mixer.range);
+}, (pixel, elem)=>{
+ if(pixel.clickCd == 0 && dragStart == null && !shiftDown){
+ pixel.toggle = !pixel.toggle;
+ pixel.clickCd = 20;
+ if(pixel.toggle){
+ let rgb = hexToRGB(elements.target_toggle_mixer.active);
+ let num = 5 - (Math.random()*10);
+ for(let key in rgb){
+ rgb[key] += num;
+ rgb[key] = Math.round(Math.max(Math.min(rgb[key], 255), 0));
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
+ } else {
+ let rgb = hexToRGB(elements.target_toggle_mixer.inactive);
+ let num = 5 - (Math.random()*10);
+ for(let key in rgb){
+ rgb[key] += num;
+ rgb[key] = Math.round(Math.max(Math.min(rgb[key], 255), 0));
+ }
+ pixel.color = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
+ }
+ };
+ if(shiftDown && elements[elem].movable){
+ if(pixel.targetElems.includes(elem)){
+ pixel.targetElems.splice(pixel.targetElems.indexOf(elem), 1);
+ } else {
+ pixel.targetElems.push(elem);
+ }
+ }
+});
+elements.target_toggle_mixer.inactive = "#1f291b", elements.target_toggle_mixer.active = "#8cbf7a", elements.target_toggle_mixer.movable = false, elements.target_toggle_mixer.keyInput = "chance";
+elements.target_toggle_mixer.hardness = 1;
+elements.target_sensor = {
+ color: "#afb08b",
+ conduct: 1,
+ category: "machines",
+ properties: {
+ targetElems: [],
+ clickCd: 0,
+ },
+ hardness: 1,
+ onClicked: function(pixel, element){
+ if(shiftDown && element != "unknown" && pixel.clickCd == 0){
+ if(pixel.targetElems.includes(element)){
+ pixel.targetElems.splice(pixel.targetElems.indexOf(element), 1);
+ pixel.clickCd = 20;
+ } else {
+ pixel.targetElems.push(element);
+ pixel.clickCd = 20;
+ }
+ }
+ },
+ tick: function(pixel){
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p = getPixel(x,y);
+ if(p != null && pixel.targetElems.includes(p.element)){
+ pixel.charge = 1;
+ doElectricity(pixel,1);
+ }
+ }
+ pixel.clickCd -= (pixel.clickCd > 0) ? 1 : 0;
+ }
+}
+
+Pixel.prototype.inRange = function(range){
+ res = false;
+ for(let coords of range){
+ if(this.x == coords[0] && this.y == coords[1]){
+ res = true;
+ }
+ }
+ return res;
+}
+elements.acid.ignore = elements.acid.ignore.concat(["nitric_acid", "aqua_regia", "chloroauric_acid", "nitrogen_dioxide", "nitric_acid_ice", "nitrogen_dioxide_ice", "acid", "chloroauric_acid", "magnesium_chloride", "magnesium_carbonate", "magnesium_hydroxide", "magnesium", "gallium", "gallium_chloride", "salt", "aluminum", "aluminum_chloride", "target_portal_in"]);
+elements.nitric_acid = {
+ alias: "HNO₃",
+ 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: elements.acid.ignore,
+ state: "liquid",
+ color: ["#f5e7e1", "#f7e8e1", "#f7ebe6"],
+ tempLow: -42,
+ stateLow: "nitric_acid_ice",
+ reactions: {
+ acid: {elem1: null, elem2: "aqua_regia"},
+ },
+ density: 1510,
+ category: "liquids",
+ tick: function(pixel){
+ for(let coords of squareCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2 != null && ["light", "liquid_light", "laser"].includes(p2.element) || Math.random()<(pixel.temp-68)/53){
+ let elems = ["nitrogen_dioxide","water", "oxygen"];
+ let elem = elems[Math.round(Math.random()*elems.length)];
+ while (elem == undefined){
+ elem = elems[Math.round(Math.random()*elems.length)];
+ }
+ changePixel(pixel, elem);
+ }
+ }
+ }
+}
+elements.nitrogen_dioxide = {
+ alias: "NO₂",
+ color: ["#6e361f", "#7d3d22", "#873f20", "#9c4935"],
+ behavior: behaviors.GAS,
+ state: "gas",
+ reactions: {
+ water: {elem1: null, elem2: "nitric_acid"},
+ },
+ category: "gases",
+ stateHigh: ["nitrogen", "oxygen"],
+ tempHigh: 150,
+ stateLow: "nitrogen_dioxide_ice",
+ tempLow: -11,
+};
+
+elements.nitrogen_dioxide_ice = {
+ color: ["#4f1607", "#4d1709", "#541606", "#471407"],
+ behavior: behaviors.WALL,
+ state: "solid",
+ category: "states",
+ stateHigh: "nitrogen_dioxide",
+ tempHigh: -10,
+};
+
+elements.nitric_acid_ice = {
+ behavior: behaviors.WALL,
+ color: ["#f5e7e4", "#f5efed", "#fcfafa"],
+ state: "solid",
+ category: "states",
+ stateHigh: "nitric_acid",
+ tempHigh: -41
+};
+
+elements.aqua_regia = {
+ alias: "3HCl•HNO₃",
+ color:["#ffc766", "#f5c36e", "#f7c163", "#ffcd75"],
+ 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: elements.acid.ignore,
+ category: "liquids",
+ state: "liquid",
+ density: 1210,
+ reactions: {
+ gold: {elem1: "chloroauric_acid", elem2: null, chance: 0.15},
+ gold_coin: {elem1: "chloroauric_acid", elem2: null, chance: 0.15},
+ blue_gold: {elem1: ["chloroauric_acid", "gallium_chloride"], elem2: null, chance: 0.15},
+ purple_gold: {elem1: ["chloroauric_acid", "chloroauric_acid", "chloroauric_acid", "aluminum_chloride"], elem2: null, chance: 0.15},
+ }
+};
+elements.chloroauric_acid = {
+ color: ["#f7bb2f", "#f5bb33", "#f5b727", "#e8ae25"],
+ alias: "H(AuCl₄)",
+ behavior: behaviors.POWDER,
+ category: "powders",
+ state: "solid",
+ density: 3900,
+ reactions: {
+ potassium: {elem1: "gold_coin", elem2: "potassium_salt", func: function(pixel){for(let coords of squareCoords){let x=pixel.x+coords[0],y=pixel.y+coords[1]; if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random()<0.25){createPixel("hydrogen", x, y);}}}},
+ sodium: {elem1: "gold_coin", elem2: "salt", func: function(pixel){for(let coords of squareCoords){let x=pixel.x+coords[0],y=pixel.y+coords[1]; if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random()<0.25){createPixel("hydrogen", x, y);}}}},
+ caustic_potash: {elem1: "gold_coin", elem2: "potassium_salt", func: function(pixel){for(let coords of squareCoords){let x=pixel.x+coords[0],y=pixel.y+coords[1]; if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random()<0.25){createPixel("water", x, y);}}}},
+ lye: {elem1: "gold_coin", elem2: "salt", func: function(pixel){for(let coords of squareCoords){let x=pixel.x+coords[0],y=pixel.y+coords[1]; if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random()<0.25){createPixel("water", x, y);}}}},
+ magnesium: {elem1: "gold_coin", elem2: "magnesium_chloride", func: function(pixel){for(let coords of squareCoords){let x=pixel.x+coords[0],y=pixel.y+coords[1]; if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random()<0.25){createPixel("hydrogen", x, y);}}}},
+ metal_scrap: {elem1: "gold_coin", elem2: "slag", func: function(pixel){for(let coords of squareCoords){let x=pixel.x+coords[0],y=pixel.y+coords[1]; if(isEmpty(x,y) && !outOfBounds(x,y) && Math.random()<0.25){createPixel("hydrogen", x, y);}}}},
+ }
+};
+elements.magnesium_chloride = {
+ alias: "MgCl₂",
+ category: "salts",
+ behavior: behaviors.POWDER,
+ state: "solid",
+ color: ["#f2f2f2", "#f5f5f5", "#ebebeb", "#e6e6e6"],
+ density: 2320,
+ reactions: {
+ baking_soda: {elem1: "magnesium_carbonate", elem2: "salt"},
+ lye: {elem1: "magnesium_hydroxide", elem2: "salt"},
+ caustic_potash: {elem1: "magnesium_hydroxide", elem2: "potassium_salt"},
+ ash: {elem1: "magnesium_carbonate", elem2: ["dust","dust",null,"potassium_salt", "charcoal"]}
+ }
+}
+elements.calcium_chloride = {
+ alias: "CaCl₂",
+ category: "salts",
+ density: 2150,
+ behavior: behaviors.POWDER,
+ state: "solid",
+ color: ["#f2f2f2", "#f5f5f5", "#ebebeb", "#e6e6e6"],
+ density: 2320,
+ reactions: {
+ baking_soda: {elem1: "limestone", elem2: "salt"},
+ lye: {elem1: "slaked_lime", elem2: "salt"},
+ caustic_potash: {elem1: "slaked_lime", elem2: "potassium_salt"},
+ ash: {elem1: "limestone", elem2: ["dust","dust",null,"potassium_salt", "charcoal"]},
+ epsom_salt: {elem1: "hardened_gypsum", elem2: "magnesium_chloride"},
+ carbon_dioxide: {elem1: "limestone", elem2: "chlorine", chance: 0.001, tempMin: 60}
+ }
+}
+elements.sodium.reactions.carbon_dioxide = {elem1: "baking_soda", elem2: null}, elements.magnesium.reactions.carbon_dioxide = {elem1: "magnesium_carbonate", elem2:null};
+elements.acid.reactions.magnesium = {elem1: "hydrogen", elem2: "magnesium_chloride"};
+elements.magnesium_carbonate = {
+ alias: "MgCO₃",
+ category: "salts",
+ behavior: behaviors.POWDER,
+ state: "solid",
+ color: ["#f2f2f2", "#f5f5f5", "#ebebeb", "#e6e6e6"],
+ density: 2960,
+ reactions: {
+ acid: {elem1: "magnesium_chloride", elem2: ["carbon_dioxide", "foam", "seltzer", "seltzer"]}
+ }
+}
+elements.magnesium_hydroxide = {
+ alias: "Mg(OH)₂",
+ category: "salts",
+ behavior: behaviors.POWDER,
+ state: "solid",
+ color: ["#f2f2f2", "#f5f5f5", "#ebebeb", "#e6e6e6"],
+ density: 2340,
+ reactions: {
+ acid: {elem1: "magnesium_chloride", elem2: "water"}
+ }
+}
+elements.hardened_gypsum = {
+ alias: "CaSO₄•2H₂O",
+ color: ["#f2f2f2", "#f5f5f5", "#ebebeb", "#e6e6e6"],
+ category: "solids",
+ state: "solid",
+ behavior: behaviors.WALL,
+ density: 2320,
+ breakInto: "gypsum",
+}
+elements.gypsum = {
+ alias: "CaSO₄•2H₂O",
+ color: ["#d1d1d1", "#d6d6d6", "#cccbca", "#cfcdca", "#bfbebb"],
+ category: "powders",
+ state: "solid",
+ behavior: behaviors.STURDYPOWDER,
+ density: 2420,
+ tick: function(pixel){
+ let chance = (pixel.temp-18)/100*(pixel.temp/40)*((pixelTicks-pixel.start)/250);
+ if(Math.random(){
+ elements.target_portal_in.channel = parseInt(input);
+ }, "Portal Channel", elements.target_portal_in.channel)
+ },
+ tick: function(pixel){
+ pixel.clickCd -= (pixel.clickCd == 0) ? 0 : 1;
+ if(pixel.channel == null){
+ pixel.channel = elements.target_portal_in.channel;
+ }
+ if(pixel.out == null){
+ for(p2 of currentPixels){
+ if(p2.element == "portal_out" && p2.channel == pixel.channel){
+ let adjacent = this.checkAdjacent(p2);
+ if(adjacent != false){
+ pixel.out = p2;
+ break;
+ }
+ }
+ }
+ }
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ if(!isEmpty(x,y) && !outOfBounds(x,y) && elements[pixelMap[x][y].element].movable && pixel.out != undefined){
+ let pixel2 = getPixel(x,y);
+ let spots = this.checkAdjacent(pixel.out);
+ if(spots != false && Array.isArray(spots)){
+ let num = Math.round(Math.random()*spots.length);
+ while(spots[num] == undefined){
+ num = Math.round(Math.random()*spots.length);
+ }
+ if(pixel.targetElems.includes(pixel2.element)){
+ movePixel(pixel2, spots[num][0], spots[num][1]);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/mods/noita.js b/mods/noita.js
new file mode 100644
index 00000000..06893e6d
--- /dev/null
+++ b/mods/noita.js
@@ -0,0 +1,4895 @@
+function isASecond(number) {
+ if (number % 30 === 0 || number % 29 === 0 || number % 31 === 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+doNHeat = function(pixel) {
+ // Check right and bottom adjacent pixels
+ for (var i = 0; i < biCoords.length; i++) {
+ var x = pixel.x+biCoords[i][0];
+ var y = pixel.y+biCoords[i][1];
+ if (!isEmpty(x,y,true)) {
+ var newPixel = pixelMap[x][y];
+ // Skip if both temperatures are the same
+ if (pixel.temp === newPixel.temp || elements[newPixel.element].insulate === true) {
+ continue;
+ }
+ // Set both pixel temperatures to their average
+ var avg = (pixel.temp + newPixel.temp)/2;
+ pixel.temp = avg;
+ newPixel.temp = avg;
+ pixelTempCheck(pixel);
+ pixelTempCheck(newPixel);
+ }
+ }
+}
+
+doNBurning = function(pixel) {
+ if (pixel.NBurning) { // Burning
+ if (pixel.NBurnStart === undefined) { pixel.NBurnStart = pixelTicks }
+ var info = elements[pixel.element];
+ if (pixel.temp < -50) {
+ pixel.NBurning = undefined;
+ pixel.NBurnStart = undefined;
+ return;
+ }
+ for (var i = 0; i < adjacentCoords.length; i++) { // Burn adjacent pixels
+ var x = pixel.x+adjacentCoords[i][0];
+ var y = pixel.y+adjacentCoords[i][1];
+ if (!isEmpty(x,y,true)) {
+ var newPixel = pixelMap[x][y]
+ if (elements[newPixel.element].burnable === true && elements[newPixel.element].nburnTime === true && Math.random() > 0.8) {
+ newPixel.NBurning = true
+ }
+ else if (elements[newPixel.element].burnableFast === true && Math.random() > 0.25) {
+ changePixel(newPixel,"noita_fire")
+ newPixel.NBurning = true
+ }
+ }
+ }
+
+ if ((pixelTicks - pixel.NBurnStart > (info.nburnTime || 200)) && Math.floor(Math.random()*100)<(info.nburn || 10) && !(info.nburnTime === undefined && info.hardness >= 1)) {
+ if (elements[pixel.element].nburnInto !== undefined) {
+ if (Math.random() > 0.5) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else {
+ changePixel(pixel,elements[pixel.element].nburnInto);
+ }
+ }
+ else {
+ changePixel(pixel,"noita_fire");
+ pixel.NBurning = true;
+ }
+ }
+ else if (Math.floor(Math.random()*100)<10 && info.id !== elements.noita_fire.id) { // Spawn fire
+ if (isEmpty(pixel.x,pixel.y-1)) {
+ createPixel(("noita_fire"),pixel.x,pixel.y-1);
+ pixelMap[pixel.x][pixel.y-1].temp = pixel.temp//+(pixelTicks - (pixel.burnStart || 0));
+ pixelMap[pixel.x][pixel.y-1].NBurning = true
+ }
+ // same for below if top is blocked
+ else if (isEmpty(pixel.x,pixel.y+1)) {
+ createPixel(("noita_fire"),pixel.x,pixel.y+1);
+ pixelMap[pixel.x][pixel.y+1].temp = pixel.temp//+(pixelTicks - (pixel.burnStart || 0));
+ pixelMap[pixel.x][pixel.y+1].NBurning = true
+ }
+ }
+
+ }
+}
+
+NExplode = function(x,y,radius,damage,fire="noita_fire") {
+ // if fire contains , split it into an array
+ if (fire.indexOf(",") !== -1) {
+ 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++) {
+ if (isEmpty(coords[i].x,coords[i].y)) {
+ // 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 (pixel.hp) { // lower hp
+ DoDamage(pixel,"explosion",damage)
+ var damaged = true
+ }
+ if (info.hardness && damaged != true) { // lower damage depending on hardness(0-1)
+ if (info.hardness < 1) {
+ // more hardness = less damage, logarithmic
+ damage *= Math.pow((1-info.hardness),info.hardness);
+ }
+ else { damage = 0; }
+ }
+ if (damage > 0.9 && damaged != true) {
+ if (Array.isArray(fire)) {
+ var newfire = fire[Math.floor(Math.random() * fire.length)];
+ }
+ else {
+ var newfire = fire;
+ }
+ changePixel(pixel,newfire);
+ continue;
+ }
+ else if (damage > 0.25 && damaged != true) {
+ if (isBreakable(pixel)) {
+ breakPixel(pixel);
+ continue;
+ }
+ else {
+ if (Array.isArray(fire)) {
+ var newfire = fire[Math.floor(Math.random() * fire.length)];
+ }
+ else {
+ var newfire = fire;
+ }
+ if (elements[pixel.element].onBreak !== undefined) {
+ elements[pixel.element].onBreak(pixel);
+ }
+ changePixel(pixel,newfire);
+ continue;
+ }
+ }
+ }
+ }
+}
+
+DoDamage = function(pixel,type,damage,damageMultiplier={ "melee": 1, "projectile": 1, "explosion": 1, "fire": 1, "electricity": 1, "drill": 1, "slice": 1, "ice": 1, "healing": 1, "radioactive": 1, "poison": 1, "curse": 1, "holy": 1, "material": 1 }) {
+ if (pixel.immunities[type] != true) {
+ pixel.hp = (pixel.hp - (damage * damageMultiplier[type]))
+ }
+}
+
+DoNoitaCreature = function(pixel) {
+ if (!pixel.stains) {
+ pixel.stains = []
+ }
+ if (pixel.stains.wet && isASecond(pixelTicks)) {
+ if ((pixel.stains.wet[1] + pixel.stains.wet[0]) < pixelTicks) {
+ delete pixel.stains.wet
+ }
+ }
+ if (pixel.stains.bloody && isASecond(pixelTicks)) {
+ if ((pixel.stains.bloody[1] + pixel.stains.bloody[0]) < pixelTicks) {
+ delete pixel.stains.bloody
+ }
+ }
+ if (pixel.stains.onFire && isASecond(pixelTicks)) {
+ if (pixel.stains.wet || pixel.stains.bloody) {
+ if (pixel.stains.onFire) {
+ delete pixel.onFire
+ }
+ if (pixel.stains.wet[1]) {
+ pixel.stains.wet[1] -= 10
+ }
+ else if (pixel.stains.bloody[1]) {
+ pixel.stains.bloody[1] -= 10
+ }
+ }
+ DoDamage(pixel,"fire",(Math.ceil(pixel.maxhp / 50)))
+ pixel.panic++
+ if ((pixel.stains.onFire[1] + pixel.stains.onFire[0]) < pixelTicks) {
+ delete pixel.stains.onFire
+ }
+ }
+ if (pixel.stains.poisoned && isASecond(pixelTicks)) {
+ DoDamage(pixel,"poison",(Math.ceil(pixel.maxhp / 50)))
+ pixel.panic++
+ if ((pixel.stains.poisoned[1] + pixel.stains.poisoned[0]) < pixelTicks) {
+ delete pixel.stains.poisoned
+ }
+ }
+ if (pixel.stains.teleportitis && isASecond(pixelTicks)) {
+ var x = Math.floor(Math.random()*(width))+1;
+ var y = Math.floor(Math.random()*(height))+1;
+ if (isEmpty(x,y)) {
+ tryMove(pixel,x,y)
+ }
+ pixel.panic++
+ if ((pixel.stains.teleportitis[1] + pixel.stains.teleportitis[0]) < pixelTicks) {
+ delete pixel.stains.teleportitis
+ }
+ }
+ if (!pixel.immunities) {
+ pixel.immunities = { "melee": false, "projectile": false, "explosion": false, "fire": false, "electricity": false, "drill": false, "slice": false, "ice": false, "healing": false, "radioactive": false, "poison": false, "curse": false, "holy": false, "material": false }
+ }
+}
+
+DoNoitaHumanoid = function(pixel) {
+ if (!pixel.stains) {
+ pixel.stains = []
+ }
+ if (pixel.stains.wet && isASecond(pixelTicks)) {
+ if ((pixel.stains.wet[1] + pixel.stains.wet[0]) < pixelTicks) {
+ delete pixel.stains.wet
+ }
+ }
+ if (pixel.stains.bloody && isASecond(pixelTicks)) {
+ if ((pixel.stains.bloody[1] + pixel.stains.bloody[0]) < pixelTicks) {
+ delete pixel.stains.bloody
+ }
+ }
+ if (pixel.stains.onFire && isASecond(pixelTicks)) {
+ if (pixel.stains.wet || pixel.stains.bloody) {
+ if (pixel.stains.onFire) {
+ delete pixel.onFire
+ }
+ if (pixel.stains.wet[1]) {
+ pixel.stains.wet[1] -= 10
+ }
+ else if (pixel.stains.bloody[1]) {
+ pixel.stains.bloody[1] -= 10
+ }
+ }
+ DoDamage(pixel,"fire",(Math.ceil(pixel.maxhp / 50)))
+ pixel.panic++
+ if ((pixel.stains.onFire[1] + pixel.stains.onFire[0]) < pixelTicks) {
+ delete pixel.stains.onFire
+ }
+ }
+ if (pixel.stains.poisoned && isASecond(pixelTicks)) {
+ DoDamage(pixel,"poison",(Math.ceil(pixel.maxhp / 50)))
+ pixel.panic++
+ if ((pixel.stains.poisoned[1] + pixel.stains.poisoned[0]) < pixelTicks) {
+ delete pixel.stains.poisoned
+ }
+ }
+ if (pixel.stains.teleportitis && isASecond(pixelTicks)) {
+ var x = Math.floor(Math.random()*(width))+1;
+ var y = Math.floor(Math.random()*(height))+1;
+ if (isEmpty(x,y) && isEmpty(x,y-1)) {
+ tryMove(pixel,x,y)
+ if (pixel.head)
+ tryMove(pixel.head,x,y-1)
+ }
+ pixel.panic++
+ if ((pixel.stains.teleportitis[1] + pixel.stains.teleportitis[0]) < pixelTicks) {
+ delete pixel.stains.teleportitis
+ }
+ }
+ if (!pixel.immunities) {
+ pixel.immunities = { "melee": false, "projectile": false, "explosion": false, "fire": false, "electricity": false, "drill": false, "slice": false, "ice": false, "healing": false, "radioactive": false, "poison": false, "curse": false, "holy": false, "material": false }
+ }
+}
+
+DoNoitaStaining = function(pixel,damagePixel) {
+ if (elements[damagePixel.element].id === elements.noita_acid.id) {
+ DoDamage(pixel,"material",750)
+ }
+ else if (elements[damagePixel.element].id === elements.lava.id) {
+ DoDamage(pixel,"material",450)
+ if (!pixel.stains.onFire) {
+ pixel.stains.onFire = [pixelTicks,1000]
+ }
+ }
+ else if (elements[damagePixel.element].id === elements.noita_fire.id) {
+ if (!pixel.stains.onFire) {
+ pixel.stains.onFire = [pixelTicks,1000]
+ }
+ }
+ else if (elements[damagePixel.element].id === elements.noita_poison.id) {
+ if (!pixel.stains.poisoned) {
+ pixel.stains.poisoned = [pixelTicks,1000]
+ }
+ }
+ else if ((elements[damagePixel.element].id === elements.noita_mud.id || elements[damagePixel.element].id === elements.noita_water.id || elements[damagePixel.element].id === elements.brine.id)) {
+ for (i = 0; i < pixel.stains.length; i++) {
+ if (pixel.stains[i] != pixel.stains.wet) {
+ delete pixel.stains[i]
+ }
+ }
+ if (!pixel.stains.wet) {
+ pixel.stains.wet = [pixelTicks,1000]
+ }
+ }
+ else if (elements[damagePixel.element].id === elements.noita_blood.id) {
+ if (!pixel.stains.bloody) {
+ pixel.stains.bloody = [pixelTicks,1000]
+ }
+ }
+ else if (elements[damagePixel.element].id === elements.healthium.id) {
+ pixel.hp += 100
+ if (!pixel.stains.regeneration) {
+ pixel.stains.regeneration = [pixelTicks,1000]
+ }
+ }
+ else if (elements[damagePixel.element].id === elements.teleportatium.id || elements[damagePixel.element].id === elements.unstable_teleportatium.id) {
+ if (!pixel.stains.teleportitis) {
+ pixel.stains.teleportitis = [pixelTicks,1000]
+ }
+ }
+ if (elements[damagePixel.element].state === "liquid") {
+ for (i = 0; i < pixel.stains.length; i++) {
+ if (pixel.stains[i] == pixel.stains.onFire) {
+ delete pixel.stains[i]
+ }
+ }
+ }
+}
+
+requiresAir = function(pixel) {
+ if (!isEmpty(pixel.x,pixel.y-1) && !isEmpty(pixel.x,pixel.y+1) && !isEmpty(pixel.x-1,pixel.y) && !isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.85) {
+ var neighbors = getNeighbors(pixel)
+ for (i = 0; i < neighbors.length; i++) {
+ if (elements[neighbors[i].element].living) {
+ var organism = true
+ }
+ }
+ if (!organism) {
+ changePixel(pixel,"soil")
+ }
+ }
+}
+
+textures.BRICKWORK = [ // bricky squary minecraftey
+"ssssssssgsgwgsssgsssssswggggssss",
+"gggsgggsgsgwgswwsgwwwwswggggswgg",
+"sggsgggsggwwgswgswggggsgggggsgss",
+"gwgsgggsgggggswwswggggssssgssgsw",
+"gwggssssssssssssswggggswwwwwsgsw",
+"wwgswwwwwgggggggswggggswwwwgsggw",
+"gggswwwwwgggggggswggggsgwwwgsggg",
+"sssssgssssssssssswggggsssssswsss",
+"gggwgsggggggggggswggggsggggggggg",
+"gggggsgwwgggggggsgggggsgggssssss",
+"wggggsgwwggggggggsssssgwggsggggg",
+"wggggsggggggggggsgggggsgggsggggg",
+"wggggsggggggggggsgwgggsgggsggggg",
+"wgssssssgssssssssgggggsgggsggggg",
+"wgsgggggswggggggssssssgssggwwwww",
+"ggsgggggsggwwggggsggggggsggggggg",
+"sssssssssggwwggggsggggggsssgssss",
+"wwwwswwwsggggggggswwggggwggswwsw",
+"wwwwswwwsgggggsssgsssssssssswwsw",
+"wwwwsgggsggggswwwwsgggggggggsssw",
+"wwwwsgggsggggswwwwsggwwgggggggsw",
+"wwwwsggssssssswwwwsggwwgggggggsw",
+"ssssgssswggggswwwwsgggggggggggss",
+"wggggggsgggggsssssssssssssssssss",
+"gggggggsgggggsgwwwwwwwgsggggswgs",
+"gggggggsgggggswggggggggsggggsggs",
+"gggggggsggggsswggggggggsggggsggs",
+"ggggggggsssssswggggggggsggggssss",
+"gggggggswwwggswggggggggswgggswws",
+"ggwgwwgsgssggswggggggggsssssswws",
+"ggggwwgsgsgwgswgggggggsgwwwgswws",
+"gggggggsgsgwgsggggggggswggggswws",
+]
+
+textures.ALTGROUND = [ // groundy and dirt alt
+"Sgsssgssggssggg",
+"ggsssgggggsggss",
+"ggssSgggsggggsS",
+"ssggggsggggsggg",
+"sSggsgggssggggs",
+"ggggggggsggssgg",
+"ssgggssggggsSgg",
+"ssgsgsSggsggggg",
+"sSggggggggggssg",
+"ggggssgsgssgsgg",
+"ggsgsggggsggggg",
+"gggggggggggggsg",
+"ssgggsgsssgsggg",
+"sggsgggsssggggs",
+"ggggssgssSgssgs",
+]
+
+textures.GROUND = [ // groundy and dirt
+ "sggggggggs",
+ "ggsgssgggg",
+ "ggggssgggg",
+ "ssggggggsg",
+ "ssgssggggg",
+ "gggssggggg",
+ "ggggggsggg",
+ "gssggggggg",
+ "gssggggggg",
+ "gggggggggs",
+]
+
+textures.WOOD = [ // planks
+ "gsgsgggggggggggggggggggggggggggggggggggggg",
+ "gsgggggggggggggggggggggggggggggggggggggggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSsSSSSSSSSSSS",
+ "gggggggggggggggggggggggggggsggsggggggggggg",
+ "gggggggggggggggggggggggggggggssggggggggggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "SSSSSSSSSSSSSSSSSssSSSSSSSSSSSSSSSSSSSSSSS",
+ "gggggggggggggggggssggggggggggggggggggggggg",
+ "ggggggggggggggggggsggggggggggggggggggggggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "SSsSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS",
+ "sgsggggggggggggggggggggggggggggggggggggggg",
+ "ggsggggggggggggggggggsgggggggggggggggggggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "ggggggggggggggggggsggggggggggggggggggsgggg",
+ "ggggggggggggggggggsggggggggggggggggggsgggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "SSSSSSSSSsSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS",
+ "gggggggggsgggggggggggggggggggggggggggggggg",
+ "gggggggggsgggggggggggggggggggggggggggggggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "sssSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS",
+ "gsgggggggggggggggggggggggggggggggggggggggg",
+ "gsgggggggggggggggggggggggggggggggggggggggg",
+ "ssssssssssssssssssssssssssssssssssssssssss",
+ "SsSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS",
+]
+
+textures.STEEL = [ // boxy panels
+ "ggwwgggggGgggwgsgggw",
+ "wwgsgggggGgggggsgggw",
+ "wgwggggggGgggggsgggg",
+ "swwggggggGggwwgsgggg",
+ "swwggggggGgggwgsgwgg",
+ "wggggwgggGgggwgsgwgg",
+ "wggggggggGggwwwsgwgg",
+ "gggwgggggGggwwwsgwgg",
+ "gwwwgggggGggwswswwwg",
+ "gwgggggggGgwwwwswggg",
+ "gggggggGgGggwgssgssg",
+ "ggggggsggGggwgwsgssgg",
+ "gggggggggGggwgwsgggg",
+ "sssssssssgggggwsssss",
+ "gggggggggggggswggggg",
+ "wgggggggggggwwwggggg",
+ "ggGGGGGGgggwwGGggggg",
+ "gsgggggGgggwsgGggggg",
+ "gsgggGgGggwgssgggggg",
+ "gsgggggGggwwwggwgwgg",
+ "gsgsgggGgwwgwggwwwgg",
+ "gsgggggGgggwsggwwwgg",
+ "gssssssgggwwggwgwggg",
+ "ggggggggwwwwggwgwggg",
+ "gggggswwwsgggggggggg",
+ "GGGGGGGGGGggwwggGGGG",
+ "gggggggggGgwwwgsggww",
+]
+
+textures.STATICSHINE = [ // diagonalish stripes
+ "gwgssgGs",
+ "sgwgssgG",
+ "Gsgwgssg",
+ "gGsgwgss",
+ "sgGsgwgs",
+ "ssgGsgwg",
+ "gssgGsgw",
+ "wgssgGsg",
+]
+
+elements.ground = {
+ color: ["#464128","#464128","#5f5731","#464128"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#464128",
+ "s": "#5f5731",
+ },
+ grain:0.25,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ breakInto: "noita_sand",
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+elements.noita_rock = {
+ color: ["#27282d","#27282d","#3e4555","#27282d"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#27282d",
+ "s": "#3e4555",
+ },
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.99 && (pixel.start + 25) < pixelTicks) {
+ createPixel("moss",pixel.x+1,pixel.y)
+ pixelMap[pixel.x+1][pixel.y].settled = true
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.99 && (pixel.start + 25) < pixelTicks) {
+ createPixel("moss",pixel.x-1,pixel.y)
+ pixelMap[pixel.x-1][pixel.y].settled = true
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.99 && (pixel.start + 25) < pixelTicks) {
+ createPixel("moss",pixel.x,pixel.y+1)
+ pixelMap[pixel.x][pixel.y+1].settled = true
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.99 && (pixel.start + 25) < pixelTicks) {
+ createPixel("moss",pixel.x,pixel.y-1)
+ pixelMap[pixel.x][pixel.y-1].settled = true
+ }
+ doDefaults(pixel);
+ },
+ movable: false,
+ grain:0.25,
+ name: "rock",
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+elements.volcanic_rock = {
+ color: ["#441e1f","#441e1f","#5f2621","#441e1f"],
+ colorPattern: textures.ALTGROUND,
+ colorKey: {
+ "g": "#441e1f",
+ "s": "#5f2621",
+ "S": "#52201c",
+ },
+ grain:0.25,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+elements.fools_gold = {
+ color: ["#ffef42","#ffef42","#ffff86","#ffef42"],
+ name: "fool's gold",
+ colorPattern: textures.BRICKWORK,
+ colorKey: {
+ "g": "#ffef42",
+ "s": "#ffb81b",
+ "S": "#bb8632",
+ "w": "#ffff86"
+ },
+ grain:0.1,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+elements.glowing_matter = {
+ color: ["#234630","#234630","#3b6e53","#234630"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#234630",
+ "s": "#3b6e53",
+ },
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.9 && (pixel.start + 25) < pixelTicks) {
+ createPixel("green_slime",pixel.x+1,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.9 && (pixel.start + 25) < pixelTicks) {
+ createPixel("green_slime",pixel.x-1,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.9 && (pixel.start + 25) < pixelTicks) {
+ createPixel("green_slime",pixel.x,pixel.y+1)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.9 && (pixel.start + 25) < pixelTicks) {
+ createPixel("green_slime",pixel.x,pixel.y-1)
+ }
+ doDefaults(pixel);
+ },
+ movable: false,
+ grain:0.25,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+elements.poisonous_rock = {
+ color: ["#662e83","#662e83","#8b45ac","#662e83"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#662e83",
+ "s": "#8b45ac",
+ },
+ grain:0.25,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+elements.grey_rock = {
+ color: ["#4e4e4e","#545454","#616161","#464646"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#4e4e4e",
+ "s": "#616161",
+ },
+ grain:0.3,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 10000,
+ hardness: 0.5,
+ corrodible: true,
+ static: true,
+ earth: true,
+ meltableLava: true,
+}
+
+
+elements.dense_rock = {
+ color: ["#37221d","#37221d","#623b32","#37221d"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#37221d",
+ "s": "#623b32",
+ },
+ grain:0.25,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "lava",
+ category: "land",
+ state: "solid",
+ density: 2550,
+ hardness: 0.9,
+ static: true,
+ earth: true,
+}
+
+elements.extremely_dense_rock = {
+ color: ["#251511","#251511","#40231c","#251511"],
+ colorPattern: textures.GROUND,
+ colorKey: {
+ "g": "#251511",
+ "s": "#40231c",
+ },
+ grain:0.25,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ category: "land",
+ state: "solid",
+ density: 2550,
+ hardness: 0.995,
+ static: true,
+ earth: true,
+}
+
+elements.brickwork = {
+ color: ["#514a31","#514a31","#403a29","#514a31"],
+ colorPattern: textures.BRICKWORK,
+ colorKey: {
+ "g": "#514a31",
+ "s": "#403a29",
+ "S": "#59533b",
+ "w": "#59533b",
+ },
+ grain:0.15,
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ category: "solids",
+ state: "solid",
+ density: 2550,
+ hardness: 0.95,
+ static: true,
+ earth: true,
+ corrodible: true
+}
+
+elements.noita_wood = {
+ color: ["#433821","#564832","#322b18","#473c23","#473c23","#473c23","#473c23","#564832","#433821"],
+ colorPattern: textures.WOOD,
+ colorKey: {
+ "g": "#473c23",
+ "s": "#322b18",
+ "S": "#564832",
+ },
+ renderer: function(pixel,ctx) {
+ if (!viewInfo[view].colorEffects) { drawDefault(ctx,pixel); return }
+ if (pixel.alpha === 0) return;
+ let edge1 = false;
+ let edge2 = false;
+ let edge3 = false;
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y;
+ if (isEmpty(x,y) || (!outOfBounds(x,y) && elements[pixelMap[x][y].element].movable !== elements[pixel.element].movable)) {
+ edge1 = true;
+ break;
+ }
+ }
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y;
+ if ((isEmpty(x-1,y) || isEmpty(x+1,y)) || (!outOfBounds(x-1,y) && elements[pixelMap[x-1][y].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x+1,y) && elements[pixelMap[x+1][y].element].movable !== elements[pixel.element].movable)) {
+ edge2 = true;
+ break;
+ }
+ }
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y;
+ if (isEmpty(x-2,y) || isEmpty(x+2,y) || (!outOfBounds(x-2,y) && elements[pixelMap[x-2][y].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x+2,y) && elements[pixelMap[x+2][y].element].movable !== elements[pixel.element].movable)) {
+ edge3 = true;
+ break;
+ }
+ }
+ if (edge1) { drawSquare(ctx,"#302917",pixel.x,pixel.y) }
+ else if (edge2) { drawSquare(ctx,"#433821",pixel.x,pixel.y) }
+ else if (edge3) { drawSquare(ctx,"#302917",pixel.x,pixel.y) }
+ else { drawSquare(ctx,pixel.color,pixel.x,pixel.y) }
+ },
+ grain:0.5,
+ name: "wood",
+ behavior: behaviors.WALL,
+ movable: false,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category: "solids",
+ burn: 5,
+ burnTime: 300,
+ burnInto: ["ember","charcoal","noita_fire"],
+ burnable: true,
+ nburnTime: 300,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ },
+ state: "solid",
+ hardness: 0.2,
+ breakInto: "sawdust",
+ forceSaveColor: true,
+ corrodible: true,
+ static: true,
+}
+
+elements.noita_sand = {
+ color: ["#c4b999","#c0b287","#baa565","#b59843","#c7c1ad"],
+ name: "sand",
+ behavior: behaviors.POWDER,
+ tempHigh: 1500,
+ stateHigh: "lava",
+ reactions: {
+ "mystery_fungus": { elem2:"mystery_fungus", chance:0.45 },
+ },
+ category: "powders",
+ state: "solid",
+ density: 6000,
+ hardness: 0.2,
+ corrodible: true,
+ sandGround: true,
+ meltableLavaFast: true,
+}
+
+elements.noita_water = {
+ color: "#366158",
+ name: "water",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].fire === true)) {
+ changePixel(pixel,"noita_steam")
+ }
+ else if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].id === elements.lava.id) {
+ changePixel(pixel,"noita_steam")
+ changePixel(pixelMap[x][y],"noita_rock")
+ }
+ }
+ }
+ },
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: 0,
+ stateLow: "noita_ice",
+ category: "liquids",
+ reactions: {
+ "fire": { elem1: "noita_steam" },
+ "noita_fire": { elem1: "noita_steam" },
+ },
+ state: "liquid",
+ density: 4000,
+ conduct: 0.02,
+ stain: -0.5,
+ extinguish: true,
+ corrodible: true,
+ water: true,
+ freezable: true,
+}
+
+elements.peat = {
+ color: ["#6e8c3b","#617d3c"],
+ behavior: behaviors.LIQUID,
+ burnable: true,
+ nburnTime: 35,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ doDefaults(pixel)
+ },
+ viscosity: 100,
+ tempHigh: 150,
+ stateHigh: "noita_fire",
+ category: "liquids",
+ reactions: {
+ },
+ state: "liquid",
+ density: 3400,
+ extinguish: true,
+ corrodible: true,
+ impure: true,
+ plant: true,
+}
+
+elements.swamp = {
+ color: ["#2f2f0a","#272707"],
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].fire === true)) {
+ changePixel(pixel,"noita_steam")
+ }
+ else if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].id === elements.lava.id) {
+ changePixel(pixel,"noita_steam")
+ changePixel(pixelMap[x][y],"noita_rock")
+ }
+ }
+ }
+ },
+ viscosity: 100,
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: 0,
+ stateLow: "noita_ice",
+ category: "liquids",
+ reactions: {
+ "fire": { elem1: "noita_steam" },
+ "noita_fire": { elem1: "noita_steam" },
+ "toxic_sludge": { elem2:"swamp_water", chance:0.15 },
+ "noita_water": { elem2:"swamp_water", chance:0.01 },
+ },
+ state: "liquid",
+ density: 3500,
+ conduct: 0.02,
+ stain: -0.5,
+ meltableWater: true,
+ extinguish: true,
+ corrodible: true,
+ water: true,
+ freezable: true,
+ soluble: true,
+ impure: true,
+}
+
+elements.swamp_water = {
+ color: "#2e542c",
+ name: "swamp",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].fire === true)) {
+ changePixel(pixel,"noita_steam")
+ }
+ else if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].id === elements.lava.id) {
+ changePixel(pixel,"noita_steam")
+ changePixel(pixelMap[x][y],"noita_rock")
+ }
+ }
+ }
+ if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.94 && (pixel.start + 100) < pixelTicks) {
+ changePixel(pixel, "peat")
+ }
+ },
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: 0,
+ stateLow: "noita_ice",
+ category: "liquids",
+ reactions: {
+ "fire": { elem1: "noita_steam" },
+ "noita_fire": { elem1: "noita_steam" },
+ "toxic_sludge": { elem2:"swamp_water", chance:0.17 },
+ },
+ state: "liquid",
+ density: 3400,
+ conduct: 0.02,
+ stain: -0.5,
+ extinguish: true,
+ corrodible: true,
+ water: true,
+ impure: true,
+}
+
+elements.noita_steam = {
+ color: ["#61617d","#61617d","#47475c","#47475c","#61617d"],
+ name: "steam",
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (Math.random() > 0.95 && Math.random() > 0.95 && (pixel.start + 500) < pixelTicks) {
+ changePixel(pixel,"noita_water")
+ }
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].static === true && Math.random() > 0.97) {
+ changePixel(pixel,"noita_water")
+ }
+ }
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempLow: 10,
+ stateLow: "noita_water",
+ category: "gases",
+ state: "gas",
+ density: 0.6,
+ conduct: 0.002,
+ stain: -0.05,
+ alias: "water vapor",
+ extinguish: true
+}
+
+elements.noita_ice = {
+ color: ["#4c8fb0","#4c8fb0","#4c8fb0","#55a7bf","#80b6d1","#55a7bf","#4c8fb0"],
+ name: "ice",
+ behavior: behaviors.WALL,
+ tempHigh: 25,
+ stateHigh: "noita_water",
+ category: "solids",
+ state: "solid",
+ density: 917,
+ breakInto: "noita_snow",
+ corrodible: true,
+ static: true,
+ meltableWater: true,
+ frozen: true,
+}
+
+elements.noita_snow = {
+ color: ["#a6c2d8","#81b0d2"],
+ name: "snow",
+ behavior: behaviors.POWDER,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].fire === true) {
+ changePixel(pixel,"noita_steam")
+ }
+ }
+ }
+ },
+ reactions: {
+ "fire": { elem1: "noita_steam" },
+ },
+ tempHigh: 25,
+ tempLow: -100,
+ stateLow: "noita_packed_snow",
+ stateHigh: "noita_water",
+ category: "land",
+ state: "solid",
+ density: 100,
+ corrodible: true,
+ static: true,
+ frozen: true,
+ meltableWater: true,
+}
+
+elements.noita_packed_snow = {
+ color: ["#a6c2d8","#a6c2d8","#81b0d2","#a6c2d8"],
+ name: "packed_snow",
+ behavior: behaviors.WALL,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].fire === true) {
+ changePixel(pixel,"noita_steam")
+ }
+ }
+ }
+ },
+ reactions: {
+ "fire": { elem1: "noita_steam" },
+ },
+ tempHigh: 25,
+ tempLow: -200,
+ stateLow: "noita_ice",
+ stateHigh: "noita_water",
+ breakInto: "noita_snow",
+ category: "land",
+ state: "solid",
+ density: 400,
+ static: true,
+ frozen: true,
+ meltableWater: true,
+}
+
+elements.noita_poison = {
+ color: "#cb42ff",
+ name: "poison",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ createPixel("noita_poison_gas",pixel.x+1,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ createPixel("noita_poison_gas",pixel.x-1,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ createPixel("noita_poison_gas",pixel.x,pixel.y+1)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ createPixel("noita_poison_gas",pixel.x,pixel.y-1)
+ }
+ doDefaults(pixel);
+ },
+ tempHigh: 150,
+ stateHigh: "noita_poison_gas",
+ tempLow: 0,
+ stateLow: "noita_poison_ice",
+ category: "liquids",
+ reactions: {
+ "noita_blood": { elem1: "pink_slime", elem2: "noita_smoke", chance:0.10 },
+ "noita_meat": { elem2: "noita_rotten_meat", chance:0.50 },
+ "noita_poison": { elem2: "poisonous_rock", elem1: "noita_poison_gas", chance:0.70 },
+ },
+ state: "liquid",
+ density: 3000,
+ conduct: 0.8,
+ corrodible: true,
+ water: true,
+ impure: true,
+ soluble: true,
+}
+
+elements.noita_poison_gas = {
+ color: ["#59147d","#59147d","#59147d","#410b5c","#410b5c"],
+ name: "poison_gas",
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (Math.random() > 0.9 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ "noita_blood": { elem1: "pink_slime", elem2: "noita_smoke", chance:0.10 },
+ },
+ tempLow: 10,
+ stateLow: "noita_poison",
+ category: "gases",
+ state: "gas",
+ density: 2000,
+ burnableFast: true,
+}
+
+elements.noita_poison_ice = {
+ color: ["#4c8fb0","#4c8fb0","#4c8fb0","#55a7bf","#80b6d1","#55a7bf","#4c8fb0"],
+ name: "ice",
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 25,
+ stateHigh: "noita_poison",
+ category: "solids",
+ state: "solid",
+ density: 10000,
+ corrodible: true,
+ static: true,
+ meltablePoison: true,
+ frozen: true,
+}
+
+elements.urine = {
+ color: "#ffeb00",
+ behavior: behaviors.LIQUID,
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: 0,
+ stateLow: "noita_ice",
+ category: "liquids",
+ reactions: {
+ "noita_snow": { elem1: "noita_water", elem2: "noita_steam", chance:0.20 },
+ "lava": { elem1: "noita_steam", elem2: "fools_gold", chance:0.70 },
+ },
+ state: "liquid",
+ density: 4000,
+ conduct: 0.02,
+ stain: -0.5,
+ extinguish: true,
+ corrodible: true,
+ soluble: true,
+}
+
+elements.brine = {
+ color: "#2e744b",
+ behavior: behaviors.LIQUID,
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: 0,
+ stateLow: "noita_ice",
+ category: "liquids",
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].fire === true) {
+ if (Math.random() > 0.5) {
+ changePixel(pixel,"noita_steam")
+ }
+ else {
+ changePixel(pixel,"noita_salt")
+ }
+ }
+ }
+ }
+ },
+ reactions: {
+ "lava": { elem1: "noita_steam", elem2: "glowing_matter", chance:0.20 },
+ "toxic_sludge": { elem2: "noita_water", chance:0.20 },
+ },
+ state: "liquid",
+ density: 4000,
+ conduct: 0.02,
+ stain: -0.5,
+ extinguish: true,
+ corrodible: true,
+ freezable: true,
+ water: true,
+}
+
+elements.pink_slime = {
+ color: ["#bb2f83","#942769"],
+ name: "slime",
+ behavior: behaviors.LIQUID,
+ viscosity: 1000,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ "noita_water": { elem1: "slime_mist", chance:0.10 },
+ "whiskey": { elem1: "noita_smoke", chance:0.30 },
+ "lava": { elem1: "static_hell_slime", elem2: "static_hell_slime", chance:0.70 },
+ },
+ state: "liquid",
+ density: 5000,
+ conduct: 0.02,
+ stain: -0.5,
+ isFood: true,
+ corrodible: true,
+ meltableLava: true,
+ slime: true,
+}
+
+elements.green_slime = {
+ color: ["#6d8b3b","#607c3b"],
+ name: "slime",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ viscosity: 1000,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ "lava": { elem1: "fungal_gas", elem1: "green_fungus", chance:0.70 },
+ },
+ state: "liquid",
+ density: 5000,
+ conduct: 0.02,
+ stain: -0.5,
+ isFood: true,
+ corrodible: true,
+ meltableLava: true,
+ slime: true,
+}
+
+elements.yellow_slime = {
+ color: ["#bec538","#92982c"],
+ name: "slime",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.95 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ viscosity: 1000,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ "lava": { elem1: "fungal_gas", elem1: "yellow_fungus", chance:0.70 },
+ },
+ state: "liquid",
+ density: 5000,
+ conduct: 0.02,
+ stain: -0.5,
+ isFood: true,
+ corrodible: true,
+ meltableLava: true,
+ slime: true,
+}
+
+elements.hell_slime = {
+ color: ["#714242","#784747"],
+ behavior: behaviors.LIQUID,
+ viscosity: 1000,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ },
+ state: "liquid",
+ density: 4000,
+ conduct: 0.02,
+ stain: -0.5,
+ isFood: true,
+ earth: true,
+ static: true,
+ slime: true,
+ corrodible: true,
+}
+
+elements.static_hell_slime = {
+ color: ["#714242","#784747"],
+ name: "hell_slime",
+ behavior: behaviors.WALL,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ },
+ state: "liquid",
+ density: 5000,
+ conduct: 0.02,
+ stain: -0.5,
+ isFood: true,
+ static: true,
+ slime: true,
+ corrodible: true,
+}
+
+elements.pus = {
+ color: ["#8d504b","#8f6046","#8d5249","#7d5044","#915449"],
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].fungus === true) && Math.random() > 0.60) {
+ changePixel(pixel,"weird_fungus")
+ changePixel(pixelMap[x][y],"weird_fungus")
+ }
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].sandMetal === true || elements[pixelMap[x][y].element].gold === true) && Math.random() > 0.80) {
+ changePixel(pixelMap[x][y],"noita_smoke")
+ }
+ }
+ }
+ },
+ viscosity: 1000,
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ "noita_water": { elem2: "pus", chance:0.80 },
+ "toxic_sludge": { elem2: "pus", chance:0.80 },
+ "noita_aluminium": { elem2: "noita_smoke", chance:0.10 },
+ "noita_grass": { elem2: "noita_smoke", chance:0.80 },
+ },
+ state: "liquid",
+ density: 1243.4,
+ conduct: 0.02,
+ stain: -0.5,
+ isFood: true,
+ corrodible: true,
+ impure: true,
+ water: true,
+}
+
+elements.noita_oil = {
+ color: "#3d3628",
+ name: "oil",
+ behavior: behaviors.LIQUID,
+ burnable: true,
+ nburnTime: 500,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ },
+ tempHigh: 1000,
+ category: "liquids",
+ reactions: {
+ "noita_meat": { func:function(pixel1,pixel2){ if (pixel1.NBurning === true && Math.random()> 0.9) {changePixel(pixel2,"lightly_cooked_meat");} } },
+ "lightly_cooked_meat": { func:function(pixel1,pixel2){ if (pixel1.NBurning === true && ((pixel1.NBurnStart - pixelTicks) < -100) && Math.random()> 0.8) {changePixel(pixel2,"noita_cooked_meat");} } },
+ "noita_cooked_meat": { func:function(pixel1,pixel2){ if (pixel1.NBurning === true && ((pixel1.NBurnStart - pixelTicks) < -225) && Math.random()> 0.9) {changePixel(pixel2,"fully_cooked_meat");} } },
+ "fully_cooked_meat": { func:function(pixel1,pixel2){ if (pixel1.NBurning === true && ((pixel1.NBurnStart - pixelTicks) < -450) && Math.random()> 0.95) {changePixel(pixel2,"burned_meat");} } },
+ },
+ state: "liquid",
+ density: 1000,
+ corrodible: true,
+ impure: true,
+}
+
+elements.noita_gold = {
+ color: ["#ffd785","#f9bb50","#e18c68","#ffd785","#f9bb50","#e18c68","#ffffb5","#ffd785","#f9bb50","#e18c68","#ffffb5","#ffffff"],
+ name: "gold",
+ behavior: behaviors.POWDER,
+ tempHigh: 1500,
+ stateHigh: "noita_molten_gold",
+ reactions: {
+ "flummoxium": { elem1:"levitatium", elem2:"levitatium", chance:0.45 },
+ "diminution": { elem1:"noita_silver" },
+ },
+ category: "powders",
+ state: "solid",
+ density: 8000,
+ conduct: 0.8,
+ hardness: 0.25,
+ sandMetal: true,
+ corrodible: true,
+ meltableMetal: true,
+}
+
+elements.noita_molten_gold = {
+ color: ["#ffd785","#f9bb50","#e18c68","#ffd785","#f9bb50","#e18c68","#ffffb5","#ffd785","#f9bb50","#e18c68","#ffffb5","#ffffff"],
+ name: "molten_gold",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "noita_gold",
+ reactions: {
+ },
+ density: 3000,
+ conduct: 0.8,
+ corrodible: true,
+ molten: true,
+}
+
+elements.metal_dust = {
+ color: ["#606d70","#3e4555","#758582","#bec8c1"],
+ behavior: behaviors.POWDER,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh:"molten_metal",
+ category: "powders",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.25,
+ sandMetal: true,
+ corrodible: true,
+ meltableMetal: true,
+}
+
+elements.molten_metal = {
+ color: ["#7d8a8d","#dbe5de","#5b6272","#92a29f"],
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "metal_dust",
+ reactions: {
+ },
+ density: 3000,
+ conduct: 0.8,
+ corrodible: true,
+ molten: true,
+}
+
+elements.noita_brass = {
+ color: ["#c7632e","#ae4a54","#d68b67","#f5dc99","#c7632e","#ae4a54","#d68b67","#f5dc99","#ffffff"],
+ name:"brass",
+ behavior: behaviors.POWDER,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].fungus === true)) {
+ changePixel(pixel,"funky_cloud")
+ changePixel(pixelMap[x][y],"funky_cloud")
+ }
+ }
+ }
+ },
+ reactions: {
+ "noita_diamond": { elem1:"purifying_powder", elem2:"purifying_powder", chance:0.5, },
+ "unstable_teleportatium": { elem2:"noita_smoke", elem1:"metal_dust", chance:0.50 },
+ "pus": { elem1:"noita_smoke", chance:0.20 },
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_brass",
+ category: "powders",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.275,
+ sandMetal: true,
+ corrodible: true,
+ meltableMetal: true,
+}
+
+elements.noita_molten_brass = {
+ color: ["#ffffc1","#ff937c","#ffac56","#ffd48f","#ffffc1","#ff937c","#ffac56","#ffd48f","#ffffff"],
+ name: "molten_brass",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "noita_brass",
+ reactions: {
+ },
+ density: 3000,
+ conduct: 0.8,
+ corrodible: true,
+ molten: true,
+}
+
+elements.noita_copper = {
+ color: ["#58444d","#915861","#b2947a","#cfbf9d"],
+ name:"copper",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "teleportatium": { elem1:"noita_brass", elem2:"noita_smoke", chance:0.5, },
+ "polymorphine": { elem1:"polymorphine_cloud", elem2:"polymorphine_cloud", chance:0.5, },
+ "flummoxium": { elem1:"levitatium", elem2:"levitatium", chance:0.45, },
+ "pus": { elem1:"noita_smoke", chance:0.20 },
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_copper",
+ category: "powders",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.3,
+ sandMetal: true,
+ corrodible: true,
+ meltableMetal: true,
+}
+
+elements.noita_molten_copper = {
+ color: ["#ad8d75","#ffffc5","#e6a189","#ffdda2"],
+ name: "molten_copper",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "noita_copper",
+ reactions: {
+ },
+ density: 3000,
+ conduct: 0.8,
+ corrodible: true,
+ molten: true,
+}
+
+elements.noita_silver = {
+ color: ["#94938f","#f9f9f2","#c1c0bb","#ffffff"],
+ name:"silver",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "polymorphine": { elem1:"noita_copper", elem2:"noita_smoke", chance:0.5, },
+ "teleportatium": { elem1:"teleportatium_cloud", elem2:"teleportatium_cloud", chance:0.1, },
+ "pus": { elem1:"noita_smoke", chance:0.20 },
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_silver",
+ category: "powders",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.25,
+ sandMetal: true,
+ corrodible: true,
+ meltableMetal: true,
+}
+
+elements.noita_molten_silver = {
+ color: ["#e0dbca","#b3ae9e","#ffffff"],
+ name: "molten_silver",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "noita_silver",
+ reactions: {
+ },
+ density: 3000,
+ conduct: 0.8,
+ corrodible: true,
+ molten: true,
+}
+
+elements.noita_steel = {
+ color: ["#907e55","#4c4137","#695b4b","#695b4b","#695b4b","#6e5f4e","#5d5043","#84744e","#6e5f4e","#6e5f4e","#6e5f4e","#6e5f4e","#5d5043","#84744e","#4c4137","#907e55"],
+ colorPattern: textures.STEEL,
+ colorKey: {
+ "g": "#6e5f4e",
+ "s": "#5d5043",
+ "G": "#84744e",
+ "w": "#695b4b"
+ },
+ renderer: function(pixel,ctx) {
+ if (!viewInfo[view].colorEffects) { drawDefault(ctx,pixel); return }
+ if (pixel.alpha === 0) return;
+ let edge1 = false;
+ let edge2 = false;
+ let edge3 = false;
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y + coords[1];
+ if (isEmpty(x,y) || (!outOfBounds(x,y) && elements[pixelMap[x][y].element].movable !== elements[pixel.element].movable)) {
+ edge1 = true;
+ break;
+ }
+ }
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y + coords[1];
+ if (isEmpty(x-1,y) || isEmpty(x,y-1) || isEmpty(x+1,y) || isEmpty(x,y+1) || (!outOfBounds(x-1,y) && elements[pixelMap[x-1][y].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x+1,y) && elements[pixelMap[x+1][y].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x,y-1) && elements[pixelMap[x][y-1].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x,y+1) && elements[pixelMap[x][y+1].element].movable !== elements[pixel.element].movable)) {
+ edge2 = true;
+ break;
+ }
+ }
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coords = adjacentCoords[i];
+ var x = pixel.x + coords[0];
+ var y = pixel.y + coords[1];
+ if (isEmpty(x-2,y) || isEmpty(x,y-2) || isEmpty(x+2,y) || isEmpty(x,y+2) || (!outOfBounds(x-2,y) && elements[pixelMap[x-2][y].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x+2,y) && elements[pixelMap[x+2][y].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x,y-2) && elements[pixelMap[x][y-2].element].movable !== elements[pixel.element].movable) || (!outOfBounds(x,y+2) && elements[pixelMap[x][y+2].element].movable !== elements[pixel.element].movable)) {
+ edge3 = true;
+ break;
+ }
+ }
+ if (edge1) { drawSquare(ctx,"#4c4137",pixel.x,pixel.y) }
+ else if (edge2) { drawSquare(ctx,"#6e5f4e",pixel.x,pixel.y) }
+ else if (edge3) { drawSquare(ctx,"#907e55",pixel.x,pixel.y) }
+ else { drawSquare(ctx,pixel.color,pixel.x,pixel.y) }
+ },
+ grain: 0.1,
+ name:"steel",
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh:"molten_metal",
+ category: "solids",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.8,
+ static: true,
+ meltableMetalGeneric: true,
+ corrodible: true,
+ rust: true,
+}
+
+elements.noita_prop_steel = {
+ color: ["#c1c8be","#606d70","#3e4555","#758582","#bec8c1","#25333b"],
+ colorPattern: textures.STATICSHINE,
+ colorKey: {
+ "g": "#606d70",
+ "s": "#3e4555",
+ "G": "#758582",
+ "w": "#bec8c1"
+ },
+ renderer: function(pixel,ctx) {
+ if (!viewInfo[view].colorEffects) { drawDefault(ctx,pixel); return }
+ if (pixel.alpha === 0) return;
+ let edge1 = false;
+ let edge2 = false;
+ let edge3 = false;
+ if ((isEmpty(pixel.x-1,pixel.y) || isEmpty(pixel.x,pixel.y-1)) && !isEmpty(pixel.x,pixel.y+1,true) && !isEmpty(pixel.x+1,pixel.y,true)) {
+ edge1 = true;
+ }
+ else if ((isEmpty(pixel.x+1,pixel.y) || isEmpty(pixel.x,pixel.y+1)) && !isEmpty(pixel.x,pixel.y-1,true) && !isEmpty(pixel.x-1,pixel.y,true)) {
+ edge2 = true;
+ }
+ else if ((isEmpty(pixel.x+1,pixel.y-1) || isEmpty(pixel.x-1,pixel.y+1)) && isEmpty(pixel.x-1,pixel.y-1) && isEmpty(pixel.x+1,pixel.y+1)) {
+ edge3 = true;
+ }
+ if (edge1) { drawSquare(ctx,"#c1c8be",pixel.x,pixel.y) }
+ else if (edge2) { drawSquare(ctx,"#25333b",pixel.x,pixel.y) }
+ else if (edge3) { drawSquare(ctx,"#4f5eab",pixel.x,pixel.y) }
+ else { drawSquare(ctx,pixel.color,pixel.x,pixel.y) }
+ },
+ name:"steel",
+ behavior: behaviors.STURDYPOWDER,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_prop_steel",
+ category: "solids",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.8,
+ meltableMetal: true,
+ corrodible: true,
+ rust: true,
+}
+
+elements.noita_steel_sand = {
+ color: ["#3e4555","#758582","#606d70","#bec8c1"],
+ name:"steel",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "polymorphine": { elem1:"noita_copper", elem2:"noita_smoke", chance:0.5, },
+ "teleportatium": { elem1:"teleportatium_cloud", elem2:"teleportatium_cloud", chance:0.1, },
+ "pus": { elem1:"noita_smoke", chance:0.20 },
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_steel",
+ category: "powders",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.8,
+ sandMetal: true,
+ corrodible: true,
+}
+
+elements.noita_molten_prop_steel = {
+ color: ["#b5b698","#ffffe9","#938e7d","#caceaa"],
+ name: "molten metal",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "noita_steel_sand",
+ reactions: {
+ },
+ density: 2000,
+ conduct: 0.8,
+ corrodible: true,
+ nmolten: true,
+}
+
+elements.noita_molten_steel = {
+ color: ["#7a6d60","#867868","#a1916b","#7a6d60"],
+ name: "molten steel",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "metal_dust",
+ reactions: {
+ },
+ density: 5000,
+ conduct: 0.8,
+ corrodible: true,
+ moltenMetal: true,
+ gold: true
+}
+
+elements.noita_aluminium = {
+ color: ["#c1c8be","#606d70","#3e4555","#758582","#bec8c1","#25333b"],
+ colorPattern: textures.STATICSHINE,
+ colorKey: {
+ "g": "#606d70",
+ "s": "#3e4555",
+ "G": "#758582",
+ "w": "#bec8c1"
+ },
+ name:"aluminium",
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_prop_steel",
+ category: "solids",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.8,
+ earth: true,
+ meltableMetal: true,
+ corrodible: true,
+ rustOxide: true,
+}
+
+elements.aluminium_oxide = {
+ color: ["#d1d1d2","#c5c1b8","#bdb59c","#ccc49f"],
+ name:"aluminium",
+ behavior: behaviors.WALL,
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_prop_steel",
+ category: "solids",
+ density: 8000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.8,
+ earth: true,
+ meltableMetal: true,
+ corrodible: true,
+ rustOxide: true,
+}
+
+elements.noita_diamond = {
+ color: ["#97ebff","#97ebff","#ffffff","#c4ffff","#78b7d5","#78b7d5"],
+ name:"diamond",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "noita_brass": { elem1:"purifying_powder", elem2:"purifying_powder", chance:0.5, },
+ "chaotic_polymorphine": { elem1:"silver", elem2:"smoke", chance:0.5, },
+ "noita_honey": { elem2:"ambrosia", elem1:"noita_poison", chance:0.5, },
+ "flummoxium": { elem1:"levitatium", elem2:"levitatium", chance:0.45, },
+ "diminution": { elem1:"toxic_sludge" },
+ },
+ category: "powders",
+ state: "solid",
+ density: 8000,
+ hardness: 0.99,
+ sandMetal: true,
+}
+
+elements.noita_glass = {
+ color: ["#76bed1","#6aabc3","#83dbe2"],
+ renderer: renderPresets.BORDER,
+ name:"glass",
+ behavior: behaviors.WALL,
+ reactions: {
+ "concentrated_mana": { elem1:"noita_steam", chance:0.25 },
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_glass",
+ category: "solids",
+ density: 6000,
+ state: "solid",
+ hardness: 0.2,
+ meltableMetal: true,
+ static: true,
+ earth: true,
+}
+
+elements.glass_broken = {
+ color: ["#74bed0","#74bed0","#82dbe2","#69aac2"],
+ name:"glass",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "concentrated_mana": { elem1:"noita_steam", chance:0.25 },
+ },
+ tempHigh: 1500,
+ stateHigh:"noita_molten_glass",
+ category: "powders",
+ density: 6000,
+ state: "solid",
+ conduct: 0.8,
+ hardness: 0.1,
+ sandOther: true,
+ meltableMetal: true,
+ earth: true
+}
+
+elements.noita_molten_glass = {
+ color: ["#d7ffff","#d7ffff","#bef4eb"],
+ name: "molten_glass",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempLow: 10,
+ stateLow: "noita_glass",
+ reactions: {
+ },
+ density: 5000,
+ conduct: 0.8,
+ molten: true,
+ meltableLava: true,
+ earth: true
+}
+
+elements.lava = {
+ color: "#ff8100",
+ behavior: behaviors.LIQUID,
+ onCollide: function(pixel1,pixel2) {
+ if (elements[pixel2.element].burnable === true && Math.random() < 0.08) {
+ changePixel(pixel2,"noita_fire")
+ pixel2.NBurning = true
+ }
+ else if (elements[pixel2.element].burnableFast === true && Math.random() < 0.8) {
+ changePixel(pixel2,"noita_fire")
+ pixel2.NBurning = true
+ }
+ else if (elements[pixel2.element].meltableLava === true && Math.random() < 0.03) {
+ changePixel(pixel2,"noita_fire")
+ pixel2.NBurning = true
+ changePixel(pixel1,"noita_smoke")
+ }
+ else if (elements[pixel2.element].meltableLavaFast === true && Math.random() < 0.8) {
+ changePixel(pixel2,"lava")
+ changePixel(pixel1,"noita_smoke")
+ }
+ else if (elements[pixel2.element].meltableMetal === true && Math.random() < 0.8) {
+ changePixel(pixel2,elements[pixel2.element].stateHigh)
+ }
+ },
+ reactions: {
+ "freezing_liquid": { elem1: "dense_rock", elem2: "freezing_vapour", chance:0.80 },
+ "frozen_steel": { elem1: "volcanic_rock", elem2: "noita_steel", chance:0.80 },
+ "noita_poison": { elem1: "poisonous_rock", elem2: "noita_poison_gas", chance:0.70 },
+ "brine": { elem1: "glowing_matter", elem2: "noita_steam", chance:0.80 },
+ "urine": { elem1: "fools_gold", elem2: "noita_steam", chance:0.70 },
+ "noita_water": { elem1: "noita_rock", elem2: "noita_steam", chance:0.80 },
+ "noita_mud": { elem1: "ground", elem2: "noita_steam", chance:0.80 },
+ "noita_blood": { elem1: "volcanic_rock", elem2: "noita_steam", chance:0.70 },
+ "noita_gunpowder": { elem2: "noita_fire", chance:0.70 },
+ "teleportatium": { elem2:"teleportatium_cloud", chance:0.80 },
+ },
+ tempLow: 10,
+ stateLow: "noita_rock",
+ viscosity: 100,
+ category: "liquids",
+ state: "liquid",
+ density: 6000,
+}
+
+elements.noita_fire = {
+ color: "#ff9700",
+ name: "fire",
+ tick: function(pixel){
+ if (!pixel.NBurning) {pixel.NBurning = true}
+ if (pixel.start === pixelTicks) {return}
+ let move1Spots = adjacentCoords.slice(0);
+ let moved = false;
+ for (var i = 0; i < move1Spots.length; i++) {
+ const j = Math.random()*move1Spots.length | 0;
+ const coords = move1Spots[j];
+ const x = pixel.x+coords[0];
+ const y = pixel.y+coords[1];
+ if (tryMove(pixel, x, y)) { moved = true; break; }
+ move1Spots.splice(j, 1);
+ }
+ if (moved === false) {
+ let move2Spots = diagonalCoords.slice(0);
+ for (var i = 0; i < move2Spots.length; i++) {
+ const j = Math.random()*move2Spots.length | 0;
+ const coords = move2Spots[j];
+ if (tryMove(pixel, pixel.x+coords[0], pixel.y+coords[1])) { break; }
+ move2Spots.splice(j, 1);
+ }
+ }
+ if (pixel.del !== true) {
+ doNHeat(pixel);
+ doAirDensity(pixel);
+ doNBurning(pixel);
+ if (settings.burn===0 && (pixelTicks-pixel.start > 70) && Math.random() < 0.1) {
+ changePixel(pixel,"noita_smoke")
+ }
+ }
+ },
+ onCollide: function(pixel1,pixel2) {
+ if (elements[pixel2.element].burnable === true) {
+ pixel2.NBurning = true
+ }
+ else if (elements[pixel2.element].burnableFast === true) {
+ changePixel(pixel2,"noita_fire")
+ }
+ if (pixel2.hp && !pixel2.stains.onFire) {
+ pixel2.stains.onFire = [pixelTicks,1000]
+ }
+ },
+ reactions: {
+ },
+ NBurning: true,
+ nburnTime: 15,
+ nburnInto: "noita_smoke",
+ tempLow:10,
+ stateLow: "noita_smoke",
+ category: "energy",
+ state: "gas",
+ density: 0.1,
+ noMix: true,
+ fire: true,
+ hot: true,
+}
+
+elements.spark = {
+ color: "#ffee00",
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ category: "energy",
+ temp: 40,
+ tempLow: -270,
+ stateLow: ["liquid_light",null],
+ state: "gas",
+ density: 1000,
+ hidden: true,
+ noMix: true,
+ fire: true,
+ hot: true,
+}
+
+elements.electric_spark = {
+ color: "#3dffff",
+ behavior: behaviors.GAS,
+ charge: 3,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.80 && (pixel.start + 3) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ category: "energy",
+ temp: 40,
+ tempLow: -270,
+ stateLow: ["liquid_light",null],
+ state: "gas",
+ density: 1000,
+ hidden: true,
+ noMix: true,
+ fire: true,
+ hot: true,
+}
+
+elements.noita_smoke = {
+ color: ["#414141","#414141","#313131","#313131","#414141",],
+ name: "smoke",
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (Math.random() > 0.9 && (pixel.start + 175) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ category: "gases",
+ state: "gas",
+ density: 0.1,
+ stain: 0.075,
+ noMix: true
+}
+
+elements.freezing_liquid = {
+ color: ["#6681e5","#607ad7","#7290ff",],
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.80 && (pixel.start + 200) < pixelTicks) {
+ changePixel(pixel,"freezing_vapour")
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.80 && (pixel.start + 200) < pixelTicks) {
+ changePixel(pixel,"freezing_vapour")
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.80 && (pixel.start + 200) < pixelTicks) {
+ changePixel(pixel,"freezing_vapour")
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.80 && (pixel.start + 200) < pixelTicks) {
+ changePixel(pixel,"freezing_vapour")
+ }
+ doDefaults(pixel);
+ },
+ onCollide: function(pixel1,pixel2) {
+ if (elements[pixel2.element].freezable === true) {
+ changePixel(pixel2,"noita_ice")
+ }
+ },
+ tempHigh: 150,
+ stateHigh: "freezing_vapour",
+ tempLow: -10,
+ stateLow: "ice_cold",
+ category: "liquids",
+ reactions: {
+ "worm_blood": { elem1: "worm_blood", chance:0.20 },
+ },
+ state: "liquid",
+ density: 3000,
+ conduct: 0.02,
+ stain: -0.5,
+ extinguish: true,
+ corrodible: true,
+ impure: true
+}
+
+elements.freezing_vapour = {
+ color: ["#63a6de","#63a6de","#5691c4","#5691c4","#63a6de",],
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.80 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.80 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.80 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.80 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ category: "gases",
+ tempLow: -10,
+ stateLow: "freezing_liquid",
+ state: "gas",
+ density: 2,
+}
+
+elements.ice_cold = {
+ color: ["#8a9bdd","#8a9bdd","#788bd5","#788bd5","#a0b0e5","#a0b0e5","#8a9bdd"],
+ name: "ice",
+ behavior: behaviors.WALL,
+ tempHigh: 25,
+ stateHigh: "freezing_liquid",
+ category: "solids",
+ state: "solid",
+ density: 917,
+ corrodible: true,
+ static: true,
+}
+
+elements.funky_cloud = {
+ color: ["#ff68b1","#f75998","#ff5ea1","#c3487c","#b44373",],
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ category: "gases",
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: -45,
+ state: "gas",
+ density: 2,
+ alias: "gas"
+}
+
+elements.fungal_gas = {
+ color: ["#710c55","#710c55","#710c55","#57053c","#57053c",],
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ burnableFast: true,
+ category: "gases",
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: -45,
+ burn: 100,
+ burnTime: 1,
+ fireColor: ["#00ffff","#00ffdd"],
+ state: "gas",
+ density: 2,
+ alias: "gas",
+ fungus: true,
+}
+
+elements.weird_fungus = {
+ color: ["#ff70bf","#ff6bb6","#ff7acf"],
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ if (pixel.start === pixelTicks) {return}
+ if (pixel.settled != true) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ if (Math.random() < 0.5) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x-1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ } else if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ }
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel(pixel.element,pixel.x,pixel.y-1)
+ }
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel(pixel.element,pixel.x,pixel.y+1)
+ }
+ }
+ if (pixel.settled == true) {
+ if (isEmpty(pixel.x, pixel.y-1) && isEmpty(pixel.x-1, pixel.y) && isEmpty(pixel.x+1, pixel.y)) {
+ tryMove(pixel, pixel.x, pixel.y+1)
+ }
+ if (!isEmpty(pixel.x, pixel.y-1, true) && !outOfBounds(pixel.x, pixel.y-1, true)) {
+ if (elements[pixelMap[pixel.x][pixel.y-1].element].movable === true && (!pixelMap[pixel.x][pixel.y-1].settled || pixelMap[pixel.x][pixel.y-1].settled != true)) {
+ pixel.settled = false
+ }
+ }
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel(pixel.element,pixel.x,pixel.y-1)
+ pixelMap[pixel.x][pixel.y-1].settled = true
+ }
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel(pixel.element,pixel.x,pixel.y+1)
+ pixelMap[pixel.x][pixel.y+1].settled = true
+ }
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ impure: true,
+ earth: true,
+ fungus: true,
+ plant: true,
+}
+
+elements.green_fungus = {
+ color: ["#89ff64","#96ff63"],
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ if (pixel.start === pixelTicks) {return}
+ if (pixel.settled != true) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ if (Math.random() < 0.5) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x-1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ } else if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ }
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel(pixel.element,pixel.x,pixel.y-1)
+ }
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel(pixel.element,pixel.x,pixel.y+1)
+ }
+ }
+ if (pixel.settled == true) {
+ if (isEmpty(pixel.x, pixel.y-1) && isEmpty(pixel.x-1, pixel.y) && isEmpty(pixel.x+1, pixel.y)) {
+ tryMove(pixel, pixel.x, pixel.y+1)
+ }
+ if (!isEmpty(pixel.x, pixel.y-1, true) && !outOfBounds(pixel.x, pixel.y-1, true)) {
+ if (elements[pixelMap[pixel.x][pixel.y-1].element].movable === true && (!pixelMap[pixel.x][pixel.y-1].settled || pixelMap[pixel.x][pixel.y-1].settled != true)) {
+ pixel.settled = false
+ }
+ }
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel(pixel.element,pixel.x,pixel.y-1)
+ pixelMap[pixel.x][pixel.y-1].settled = true
+ }
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel(pixel.element,pixel.x,pixel.y+1)
+ pixelMap[pixel.x][pixel.y+1].settled = true
+ }
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ impure: true,
+ earth: true,
+ fungus: true,
+ plant: true,
+}
+
+elements.yellow_fungus = {
+ color: ["#ffff59","#ffff51"],
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ if (pixel.start === pixelTicks) {return}
+ if (pixel.settled != true) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ if (Math.random() < 0.5) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x-1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ } else if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ }
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel(pixel.element,pixel.x,pixel.y-1)
+ }
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel(pixel.element,pixel.x,pixel.y+1)
+ }
+ }
+ if (pixel.settled == true) {
+ if (isEmpty(pixel.x, pixel.y-1) && isEmpty(pixel.x-1, pixel.y) && isEmpty(pixel.x+1, pixel.y)) {
+ tryMove(pixel, pixel.x, pixel.y+1)
+ }
+ if (!isEmpty(pixel.x, pixel.y-1, true) && !outOfBounds(pixel.x, pixel.y-1, true)) {
+ if (elements[pixelMap[pixel.x][pixel.y-1].element].movable === true && (!pixelMap[pixel.x][pixel.y-1].settled || pixelMap[pixel.x][pixel.y-1].settled != true)) {
+ pixel.settled = false
+ }
+ }
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel(pixel.element,pixel.x,pixel.y-1)
+ pixelMap[pixel.x][pixel.y-1].settled = true
+ }
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel(pixel.element,pixel.x,pixel.y+1)
+ pixelMap[pixel.x][pixel.y+1].settled = true
+ }
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ impure: true,
+ earth: true,
+ fungus: true,
+ plant: true,
+}
+
+elements.corpse_fungus = {
+ color: ["#933051","#a2355a","#bf3f6a"],
+ name: "weird_fungus",
+ behavior: behaviors.POWDER,
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ },
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"solids",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ earth: true,
+ fungus: true,
+}
+
+elements.noita_grass = {
+ color: ["#739c45","#84b53c"],
+ name:"grass",
+ behavior: behaviors.POWDER,
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ requiresAir(pixel);
+ doDefaults(pixel);
+ },
+ reactions: {
+ "pus": { elem1:"noita_smoke", chance:0.80 },
+ "healthium": { elem1:"holy_grass", elem2: null, chance:0.80 },
+ },
+ tempHigh: 1000,
+ stateHigh: "dry_grass",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ impure: true,
+ plant: true,
+}
+
+elements.holy_grass = {
+ color: ["#aeff73","#bfff6a"],
+ name:"divine_ground",
+ behavior: behaviors.POWDER,
+ burnable: true,
+ nburnTime: 30,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ requiresAir(pixel);
+ doDefaults(pixel);
+ },
+ reactions: {
+ "urine": { elem1:"noita_grass", elem2:"healium", chance:0.80 },
+ },
+ tempHigh: 1000,
+ stateHigh: "dry_grass",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ plant: true,
+}
+
+elements.dry_grass = {
+ color: ["#877836","#6b6638"],
+ name:"grass",
+ behavior: behaviors.POWDER,
+ burnable: true,
+ nburnTime: 20,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ requiresAir(pixel);
+ doDefaults(pixel);
+ },
+ reactions: {
+ "pus": { elem1:"noita_smoke", chance:0.80 },
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ impure: true,
+ plant: true,
+}
+
+elements.frozen_grass = {
+ color: ["#2a3c48","#36434a"],
+ name:"ice",
+ behavior: behaviors.POWDER,
+ burnable: true,
+ nburnTime: 30,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ },
+ reactions: {
+ "pus": { elem1:"noita_smoke", chance:0.80 },
+ },
+ tempHigh: 750,
+ stateHigh: "noita_grass",
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true,
+ impure: true,
+ plant: true,
+}
+
+elements.plant_material = {
+ color: ["#84b53c","#739c45"],
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ if (pixel.start === pixelTicks) {return}
+ if (pixel.settled != true) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ if (Math.random() < 0.5) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x-1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ } else if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ }
+ }
+ if (pixel.settled == true) {
+ if (isEmpty(pixel.x, pixel.y-1) && isEmpty(pixel.x-1, pixel.y) && isEmpty(pixel.x+1, pixel.y)) {
+ tryMove(pixel, pixel.x, pixel.y+1)
+ }
+ if (!isEmpty(pixel.x, pixel.y-1, true) && !outOfBounds(pixel.x, pixel.y-1, true)) {
+ if (elements[pixelMap[pixel.x][pixel.y-1].element].movable === true && (!pixelMap[pixel.x][pixel.y-1].settled || pixelMap[pixel.x][pixel.y-1].settled != true)) {
+ pixel.settled = false
+ }
+ }
+ }
+ requiresAir(pixel);
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"powders",
+ state: "solid",
+ density: 3400,
+ corrodible: true,
+ plant: true,
+}
+
+elements.moss = {
+ color: ["#739c45","#84b53c"],
+ burnable: true,
+ nburnTime: 25,
+ tick: function(pixel) {
+ doNHeat(pixel)
+ doNBurning(pixel)
+ if (pixel.start === pixelTicks) {return}
+ if (pixel.settled != true) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ if (Math.random() < 0.5) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x-1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ } else if (!tryMove(pixel, pixel.x-1, pixel.y+1)) {
+ if (!tryMove(pixel, pixel.x+1, pixel.y+1) && Math.random() > 0.95) {
+ pixel.settled = true
+ }
+ }
+ }
+ }
+ if (pixel.settled == true) {
+ if (isEmpty(pixel.x, pixel.y-1) && isEmpty(pixel.x-1, pixel.y) && isEmpty(pixel.x+1, pixel.y)) {
+ tryMove(pixel, pixel.x, pixel.y+1)
+ }
+ if (!isEmpty(pixel.x, pixel.y-1, true) && !outOfBounds(pixel.x, pixel.y-1, true)) {
+ if (elements[pixelMap[pixel.x][pixel.y-1].element].movable === true && (!pixelMap[pixel.x][pixel.y-1].settled || pixelMap[pixel.x][pixel.y-1].settled != true)) {
+ pixel.settled = false
+ }
+ }
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ },
+ tempHigh: 1500,
+ stateHigh: "noita_fire",
+ category:"powders",
+ state: "solid",
+ density: 3400,
+ corrodible: true,
+ impure: true,
+ plant: true,
+}
+
+elements.noita_salt = {
+ color: ["#a7b6c4","#9cc1ba","#adb0ae","#c4b5c4","#a2b6c3","#9daabc","#c4c4b1"],
+ behavior: behaviors.POWDER,
+ reactions: {
+ "noita_water": { elem1: null, elem2:"brine", chance:0.05 },
+ "chilly_water": { elem1: null, elem2:"brine", chance:0.05 },
+ "diminution": { elem1: "noita_smoke" }
+ },
+ tempHigh: 1500,
+ category:"powders",
+ state: "solid",
+ density: 6000,
+ corrodible: true
+}
+
+elements.noita_honey = {
+ color: ["#e8bd5a","#eac947","#e8bd5a","#eac947","#f0d99a"],
+ name: "honey",
+ behavior: behaviors.POWDER,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ "noita_fire": { elem1: "lava", elem2: "noita_smoke" },
+ "noita_diamond": { elem1: "ambrosia", elem2: "noita_poison", chance:0.50 },
+ },
+ state: "liquid",
+ density: 10000,
+ stain: -0.5,
+ isFood: true,
+ corrodible: true,
+ meltableLavaFast: true,
+}
+
+elements.ambrosia = {
+ color: "#ffcc34",
+ behavior: behaviors.LIQUID,
+ viscosity: 100,
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: 0,
+ category: "liquids",
+ reactions: {
+ "diminution": { elem1: "noita_acid", elem2: "noita_smoke" },
+ },
+ state: "liquid",
+ density: 5120,
+ conduct: 0.8,
+ stain: -0.5,
+ water: true,
+ impure: true,
+}
+
+elements.frog.breakInto = ["slime","frog_meat"]
+
+elements.frog_meat = {
+ color: ["#cc4c4c","#b2588b","#c996e6","#cd7d8a","#c4a4a9","#8f4d53"],
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"frog_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_blood")
+ }
+ },
+ burnable: true,
+ reactions: {
+ "whiskey": { elem2:"berserkium", chance:0.1 }
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true
+}
+
+elements.ambiguous_meat = {
+ color: ["#cc4c4c","#b2588b","#c996e6","#cd7d8a","#c4a4a9","#8f4d53"],
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"ambiguous_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_blood")
+ }
+ },
+ burnable: true,
+ reactions: {
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+
+elements.worm_meat = {
+ color: ["#6fa0c3","#6599bf","#b9d3dd","#94b9d0","#aac9d8","#5582a1"],
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"worm_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"worm_blood")
+ }
+ },
+ burnable: true,
+ reactions: {
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+
+elements.helpless_meat = {
+ color: ["#cc4c4c","#b2588b","#c996e6","#cd7d8a","#c4a4a9","#8f4d53"],
+ name: "meat of an innocent creature",
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"helpless_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_blood")
+ }
+ },
+ burnable: true,
+ reactions: {
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+ desc: "You monster. How dare you."
+}
+
+elements.noita_meat = {
+ color: ["#cc4c4c","#b2588b","#c996e6","#cd7d8a","#c4a4a9","#8f4d53"],
+ name: "meat",
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"noita_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_blood")
+ }
+ },
+ burnable: true,
+ reactions: {
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+
+elements.lightly_cooked_meat = {
+ color: ["#b8a26e","#a67971","#e2dbb4","#c3af96","#c6beb4","#88785e"],
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"lightly_cooked_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_oil")
+ }
+ },
+ burnable: true,
+ reactions: {
+ "noita_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"lightly_cooked_meat");} } },
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+elements.noita_cooked_meat = {
+ color: ["#a17858","#8e5f65","#cbb18d","#ac8779","#ab9b95","#715d52"],
+ name: "cooked meat",
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"noita_cooked_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_oil")
+ }
+ },
+ burnable: true,
+ reactions: {
+ "noita_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"noita_cooked_meat");} } },
+ "lightly_cooked_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"noita_cooked_meat");} } },
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+
+elements.fully_cooked_meat = {
+ color: ["#6f533d","#624246","#a37e4a","#7d5a4d","#7b6962","#4e4039"],
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"fully_cooked_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_oil")
+ }
+ },
+ burnable: true,
+ reactions: {
+ "noita_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"fully_cooked_meat");} } },
+ "lightly_cooked_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"fully_cooked_meat");} } },
+ "noita_cooked_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"fully_cooked_meat");} } },
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+
+elements.burned_meat = {
+ color: ["#403a35","#3c3435","#5b5246","#4a423f","#4e4a48","#302d2b"],
+ behavior: behaviors.STURDYPOWDER,
+ onBreak: function(pixel) {
+ if (Math.random() > 0.95) {
+ changePixel(pixel,"burned_meat")
+ }
+ else if (Math.random() > 0.90) {
+ changePixel(pixel,"noita_oil")
+ }
+ },
+ burnable: true,
+ reactions: {
+ "noita_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"lightly_cooked_meat");} } },
+ "lightly_cooked_meat": { func:function(pixel1,pixel2){ if ( Math.random()> 0.9) {changePixel(pixel2,"noita_cooked_meat");} } },
+ "noita_cooked_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.9) {changePixel(pixel2,"fully_cooked_meat");} } },
+ "fully_cooked_meat": { func:function(pixel1,pixel2){ if (Math.random()> 0.995) {changePixel(pixel2,"burned_meat");} } },
+ },
+ meat: true,
+ tempHigh: 200,
+ stateHigh: "cooked_meat",
+ category:"food",
+ burn:15,
+ burnTime:200,
+ burnInto:"cooked_meat",
+ state: "solid",
+ density: 6000,
+ conduct: 0.2,
+ isFood: true,
+ corrodible: true,
+}
+
+elements.acid.impure = true
+elements.dirty_water.impure = true
+elements.alcohol.impure = true
+elements.blood.impure = true
+elements.cement.impure = true
+elements.melted_wax.impure = true
+elements.slime.impure = true
+elements.glue.impure = true
+elements.seeds.impure = true
+elements.potato_seed.impure = true
+elements.grass_seed.impure = true
+elements.wheat_seed.impure = true
+elements.pumpkin_seed.impure = true
+elements.corn_seed.impure = true
+elements.mushroom_spore.impure = true
+elements.grass.impure = true
+elements.mushroom_stalk.impure = true
+elements.mushroom_cap.impure = true
+elements.mushroom_gill.impure = true
+elements.hyphae.impure = true
+
+elements.meat.meat = true
+elements.rotten_meat.meat = true
+elements.cured_meat.meat = true
+elements.cooked_meat.meat = true
+
+elements.purifying_powder = {
+ color: ["#a7b6c4","#a9c4c3","#c4b5c4","#b1c4c4","#a2b4b0","#bec4b6","#ababb2"],
+ behavior: behaviors.POWDER,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ elements.purifying_powder.tool(pixelMap[x][y]);
+ }
+ }
+ },
+ tool: function(impure) {
+ if (elements[impure.element].impure === true) {
+ changePixel(impure, "noita_water")
+ }
+ },
+ canPlace: true,
+ reactions: {
+ },
+ category: "powders",
+ state: "solid",
+ density: 6000,
+ hardness: 0.99,
+ corrodible: true
+}
+
+elements.alchemic_precursor = {
+ color: ["#0843ec","#2b52e4","#2568db","#2250df","#1542e4"],
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ elements.alchemic_precursor.tool(pixelMap[x][y]);
+ }
+ }
+ },
+ tool: function(meat) {
+ if (elements[meat.element].meat === true) {
+ changePixel(meat, "draught_of_midas")
+ }
+ },
+ canPlace: true,
+ tempLow: -10,
+ burn: 100,
+ burnTime: 3,
+ fireColor: ["#80acf0","#96cdfe","#bee6d4"],
+ category: "liquids",
+ reactions: {
+ "magma": { elem1:"gas_of_midas" },
+ },
+ state: "liquid",
+ density: 3500,
+ conduct: 0.02,
+ stain: -0.5,
+ extinguish: true
+}
+
+elements.noita_acid = {
+ name: "acid",
+ color: "#00ff3c",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var x = pixel.x+adjacentCoords[i][0];
+ var y = pixel.y+adjacentCoords[i][1];
+ if (!isEmpty(x,y,true)) {
+ var newPixel = pixelMap[x][y];
+ if ((elements[newPixel.element].corrodible !== true || elements.acid.ignore.indexOf(newPixel.element) !== -1 && elements.noita_acid.ignore.indexOf(newPixel.element) !== -1)) {
+ }
+ else {
+ changePixel(newPixel,"flammable_gas");
+ }
+ }
+ }
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.92 && (pixel.start + 225) < pixelTicks) {
+ changePixel(pixel,"flammable_gas")
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.92 && (pixel.start + 225) < pixelTicks) {
+ changePixel(pixel,"flammable_gas")
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.92 && (pixel.start + 225) < pixelTicks) {
+ changePixel(pixel,"flammable_gas")
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.92 && (pixel.start + 225) < pixelTicks) {
+ changePixel(pixel,"flammable_gas")
+ }
+ doDefaults(pixel);
+ },
+ ignore:["noita_acid","acid"],
+ reactions: {
+ "flammable_gas": {elem1:"flammable_gas",elem2:null, chance:0.12}
+ },
+ category: "liquids",
+ tempHigh: 150,
+ stateHigh: "flammable_gas",
+ tempLow: -58.88,
+ burn: 30,
+ burnTime: 1,
+ state: "liquid",
+ density: 2900,
+ stain: -0.1,
+ impure: true,
+}
+
+elements.flammable_gas = {
+ color: ["#357d22","#357d22","#357d22","#357d22","#285e1a",],
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 225) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ burnableFast: true,
+ category: "gases",
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: -45,
+ burn: 100,
+ burnTime: 1,
+ fireColor: ["#00ffff","#00ffdd"],
+ state: "gas",
+ density: 2,
+ alias: "gas"
+}
+
+elements.draught_of_midas = {
+ color: ["#ffea47","#ffde5a","#ffea47","#ffde5a","#fffa9a","#ffea47","#ffde5a",],
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+3);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ elements.draught_of_midas.tool(pixelMap[x][y]);
+ }
+ }
+ },
+ tool: function(pixel) {
+ if (elements[pixel.element].id === elements.midas_touch.id) { return; }
+ if (elements[pixel.element].id === elements.draught_of_midas.id) { return; }
+ if (elements[pixel.element].id === elements.gas_of_midas.id) { return; }
+ if (elements.midas_touch.reactions[pixel.element]) { return; }
+ if (elements.draught_of_midas.reactions[pixel.element]) { return; }
+ if (elements.gas_of_midas.reactions[pixel.element]) { return; }
+ if (Math.random() < (elements[pixel.element].hardness || 0.25)) { return; }
+ if (elements[pixel.element].state === "gas" && elements[pixel.element].id !== elements.mud.id && elements[pixel.element].id !== elements.noita_mud.id) {
+ changePixel(pixel,"gold_coin");
+ pixel.color = pixelColorPick(pixel,["#ffdf5e","#ffe682"]);
+ }
+ else if (elements[pixel.element].movable && elements[pixel.element].id !== elements.mud.id && elements[pixel.element].id !== elements.noita_mud.id) {
+ changePixel(pixel,"gold_coin");
+ }
+ else if (elements[pixel.element].id === elements.alchemic_precursor.id) {
+ changePixel(pixel, "draught_of_midas");
+ }
+ else if (elements[pixel.element].id !== elements.mud.id && elements[pixel.element].id !== elements.noita_mud.id) {
+ changePixel(pixel,"gold_coin");
+ }
+ },
+ canPlace: true,
+ reactions: {
+ "gold":{}, "gold_coin":{}, "rose_gold":{}, "blue_gold":{}, "purple_gold":{}, "electrum":{},
+ "molten_gold":{}, "pipe":{},
+ "paper": { stain2:"#54803d" },
+ "head": { elem2:"gold" },
+ "body": { elem2:"gold" },
+ "copper": { elem2:"rose_gold" },
+ "gallium": { elem2:"blue_gold" },
+ "molten_gallium": { elem2:"blue_gold" },
+ "aluminum": { elem2:"purple_gold" },
+ "silver": { elem2:"electrum" }
+ },
+ density: 997,
+ state: "liquid",
+ category:"liquids",
+}
+
+elements.gas_of_midas = {
+ color: ["#ffea47","#ffde5a","#ffea47","#ffde5a","#fffa9a","#ffea47","#ffde5a",],
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && elements[pixelMap[x][y].element].id !== elements.gold.id && elements[pixelMap[x][y].element].id !== elements.gold_coin.id && elements[pixelMap[x][y].element].id !== elements.midas_touch.id && elements[pixelMap[x][y].element].id !== elements.draught_of_midas.id && elements[pixelMap[x][y].element].id !== elements.gas_of_midas.id) {
+ elements.draught_of_midas.tool(pixelMap[x][y]);
+ changePixel(pixel,"gold_coin")
+ }
+ }
+ }
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 204) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 204) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 204) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 204) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ },
+ tool: function(pixel) {
+ if (elements[pixel.element].id === elements.midas_touch.id) { return; }
+ if (elements[pixel.element].id === elements.draught_of_midas.id) { return; }
+ if (elements[pixel.element].id === elements.gas_of_midas.id) { return; }
+ if (elements.midas_touch.reactions[pixel.element]) { return; }
+ if (elements.draught_of_midas.reactions[pixel.element]) { return; }
+ if (elements.gas_of_midas.reactions[pixel.element]) { return; }
+ if (Math.random() < (elements[pixel.element].hardness || 0.25)) { return; }
+ if (elements[pixel.element].state === "gas" && elements[pixel.element].id !== elements.mud.id && elements[pixel.element].id !== elements.noita_mud.id && Math.random() > 0.90) {
+ changePixel(pixel,"gold_coin");
+ pixel.color = pixelColorPick(pixel,["#ffdf5e","#ffe682"]);
+ }
+ else if (elements[pixel.element].movable && elements[pixel.element].id !== elements.mud.id && elements[pixel.element].id !== elements.noita_mud.id && Math.random() > 0.90) {
+ changePixel(pixel,"gold_coin");
+ }
+ else if (elements[pixel.element].id !== elements.mud.id && elements[pixel.element].id !== elements.noita_mud.id && Math.random() > 0.90) {
+ changePixel(pixel,"gold_coin");
+ }
+ },
+ canPlace: true,
+ reactions: {
+ "gold":{}, "gold_coin":{}, "rose_gold":{}, "blue_gold":{}, "purple_gold":{}, "electrum":{},
+ "molten_gold":{}, "pipe":{},
+ "paper": { stain2:"#54803d" },
+ "head": { elem2:"gold" },
+ "body": { elem2:"gold" },
+ "copper": { elem2:"rose_gold" },
+ "gallium": { elem2:"blue_gold" },
+ "molten_gallium": { elem2:"blue_gold" },
+ "aluminum": { elem2:"purple_gold" },
+ "silver": { elem2:"electrum" }
+ },
+ tempLow: -50,
+ stateLow: "draught_of_midas",
+ density: 997,
+ state: "gas",
+ category:"liquids",
+}
+
+elements.noita_blood = {
+ color: "#820000",
+ name: "blood",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ },
+ viscosity: 10,
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: -50,
+ category:"liquids",
+ state: "liquid",
+ density: 1060,
+ stain: 0.05,
+ impure: true,
+ blood: true,
+}
+
+elements.worm_blood = {
+ color: ["#a0a72f","#92982c","#bec538"],
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "freezing_liquid": { elem2: "worm_blood", chance:0.20 },
+ "worm_pheremone": { elem1: "flummoxium", elem2: "flummoxium", chance:0.15 },
+ },
+ viscosity: 10,
+ tempHigh: 150,
+ stateHigh: "noita_steam",
+ tempLow: -10,
+ category:"liquids",
+ state: "liquid",
+ density: 1060,
+ stain: 0.05,
+ impure: true,
+ blood: true,
+}
+
+elements.soil = {
+ color: ["#272618","#232018","#27282d","#36311e"],
+ behavior: behaviors.POWDER,
+ reactions: {
+ },
+ tick: function(pixel) {
+ if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.98 && (pixel.start + 100) < pixelTicks) {
+ changePixel(pixel, "noita_grass")
+ }
+ },
+ tempHigh: 1500,
+ tempLow: -50,
+ stateLow: "permafrost",
+ category:"land",
+ state: "solid",
+ density: 1220,
+ corrodible: true
+}
+
+elements.noita_mud = {
+ color: ["#464128","#686841","#5f5731","#3b3325"],
+ name: "mud",
+ behavior: behaviors.POWDER,
+ reactions: {
+ "toxic_sludge": { elem2:"swamp_water", chance:0.15 },
+ },
+ tempHigh: 1500,
+ stateHigh: "molten_soil",
+ onStateHigh: function(pixel) {
+ releaseElement(pixel,"noita_steam");
+ },
+ tempLow: -50,
+ stateLow: "permafrost",
+ category: "land",
+ state: "solid",
+ density: 2000,
+ stain: 0.025,
+ impure: true,
+ corrodible: true
+}
+
+elements.whiskey = {
+ color: "#e87106",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.96 && (pixel.start + 25) < pixelTicks) {
+ createPixel("whiskey_fumes",pixel.x+1,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.96 && (pixel.start + 25) < pixelTicks) {
+ createPixel("whiskey_fumes",pixel.x-1,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.96 && (pixel.start + 25) < pixelTicks) {
+ createPixel("whiskey_fumes",pixel.x,pixel.y+1)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.96 && (pixel.start + 25) < pixelTicks) {
+ createPixel("whiskey_fumes",pixel.x,pixel.y-1)
+ }
+ doDefaults(pixel);
+ },
+ reactions: {
+ "frog_meat": { elem1:"berserkium", chance:0.1 }
+ },
+ tempHigh: 150,
+ stateHigh: "whiskey_fumes",
+ tempLow: -100,
+ burn: 100,
+ burnTime: 3,
+ fireColor: ["#80acf0","#96cdfe","#bee6d4"],
+ category: "liquids",
+ state: "liquid",
+ density: 785.1,
+ stain: -0.25,
+ isFood: true,
+ darkText: true,
+ alias: "alcohol",
+ impure: true,
+}
+
+elements.whiskey_fumes = {
+ color: ["#994d0a","#994d0a","#994d0a","#994d0a","#7f4004",],
+ behavior: behaviors.GAS,
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.75 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.75 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.75 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.75 && (pixel.start + 25) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doNHeat(pixel)
+ doNBurning(pixel)
+ doDefaults(pixel);
+ },
+ burnable: true,
+ nburnTime: 25,
+ category: "gases",
+ tempHigh: 1000,
+ stateHigh: "noita_fire",
+ tempLow: -45,
+ burn: 100,
+ burnTime: 1,
+ fireColor: ["#00ffff","#00ffdd"],
+ state: "gas",
+ density: 2,
+ alias: "gas"
+}
+
+elements.beer = {
+ color: "#bb7e03",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ },
+ tempHigh: 150,
+ tempLow: -100,
+ burn: 100,
+ burnTime: 3,
+ fireColor: ["#80acf0","#96cdfe","#bee6d4"],
+ category: "liquids",
+ state: "liquid",
+ density: 785.1,
+ stain: -0.25,
+ isFood: true,
+ darkText: true,
+ alias: "alcohol",
+ impure: true
+}
+
+elements.concentrated_mana = {
+ color: "#0cffff",
+ behavior: behaviors.LIQUID,
+ onCollide: function(pixel1,pixel2) {
+ if (elements[pixel2.element].meltableMetal === true && Math.random() < 0.25) {
+ changePixel(pixel2,"noita_steam")
+ }
+ },
+ reactions: {
+ "noita_water": { elem2:"concentrated_mana", chance:0.25 },
+ "noita_gold": { elem2:"noita_steam", chance:0.25 },
+ "noita_glass": { elem2:"noita_steam", chance:0.25 },
+ "glass_broken": { elem2:"noita_steam", chance:0.25 },
+ "teleportatium": { elem2:"noita_fire", chance:0.10 },
+ "unstable_teleportatium": { elem2:"noita_fire", chance:0.10 },
+ "diminution": { elem1:"noita_steam", elem2:"noita_steam", chance:0.60 },
+ },
+ tempHigh: 150,
+ tempLow: -100,
+ category: "liquids",
+ state: "liquid",
+ density: 2412,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.berserkium = {
+ color: "#ff989b",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "flummoxium": { elem1:"pheremone", elem2:"pheremone", chance:0.25 }
+ },
+ tempHigh: 150,
+ tempLow: -113.88,
+ category: "liquids",
+ state: "liquid",
+ density: 2412,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.flummoxium = {
+ color: ["#8c83c2","#ed7cc2","#8ce4bb","#f4dd5a","#f47c61"],
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "berserkium": { elem1:"pheremone", elem2:"pheremone", chance:0.25 },
+ "noita_brass": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "noita_copper": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "noita_diamond": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "noita_gold": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "metal_dust": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "noita_silver": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "noita_steel": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ "toxic_gold": { elem1:"levitatium", elem2:"levitatium", chance:0.25 },
+ },
+ tempHigh: 150,
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1200,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.diminution = {
+ color: ["#0cce2c","#0fdb2f","#19e738",],
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].fungus === true)) {
+ changePixel(pixelMap[x][y],"noita_sand")
+ }
+ }
+ }
+ },
+ reactions: {
+ "berserkium": { elem2:"noita_water", chance:0.60 },
+ "mycelium": { elem2:"soil" },
+ "levitatium": { elem1:"toxic_sludge", elem2:"toxic_sludge", chance:0.60 },
+ "ambrosia": { elem1:"noita_smoke", elem2:"noita_acid", chance:0.80 },
+ "noita_gold": { elem2:"noita_silver" },
+ "noita_molten_gold": { elem2:"noita_molten_silver" },
+ "noita_diamond": { elem1:"noita_steam", elem2:"toxic_sludge" },
+ "noita_salt": { elem2:"noita_smoke" },
+ "flammable_gas": { elem2:"diminution" },
+ },
+ tempHigh: 150,
+ stateHigh: "diminution_cloud",
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1872,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.diminution_cloud = {
+ color: ["#1cf53b","#0fdc2f","#12e932","#0f961f","#15a425"],
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ behavior: behaviors.GAS,
+ tempLow: -10,
+ stateLow: "diminution",
+ category: "gases",
+ state: "gas",
+ density: 1000,
+ isFood: true,
+ darkText: true,
+}
+
+elements.healthium = {
+ color: "#d8ffba",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "noita_grass": { elem2:"holy_grass", elem1: null, chance:0.80 },
+ "purifying_powder": { elem1:"noita_gunpowder", elem2:"noita_gunpowder", chance:0.80 },
+ "lava": { elem1:"healium", chance:0.70 },
+ },
+ tempHigh: 150,
+ stateHigh: "healium",
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1872,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ water: true,
+}
+
+elements.healium = {
+ color: ["#adff99","#adff99","#adff99","#98e786","#98e786"],
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ behavior: behaviors.GAS,
+ tempLow: -10,
+ stateLow: "healthium",
+ category: "gases",
+ state: "gas",
+ density: 1000,
+ isFood: true,
+ darkText: true,
+}
+
+elements.teleportatium = {
+ color: "#aaffff",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "noita_copper": { elem1:"noita_smoke", elem2:"noita_brass", chance:0.50 },
+ "noita_silver": { elem1:"teleportatium_cloud", elem2:"teleportatium_cloud", chance:0.1, },
+ "whiskey": { elem1:"unstable_teleportatium", chance:0.21 },
+ "concentrated_mana": { elem1:"noita_fire", chance:0.10 },
+ "lava": { elem1:"freezing_vapour", chance:0.70 },
+ },
+ tempHigh: 150,
+ stateHigh: "teleportatium_cloud",
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1872,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.teleportatium_cloud = {
+ color: ["#74bcda","#74bcda","#74bcda","#63a2b9","#63a2b9"],
+ tick: function(pixel) {
+ if (isEmpty(pixel.x+1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x-1,pixel.y) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y+1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ else if (isEmpty(pixel.x,pixel.y-1) && Math.random() > 0.70 && (pixel.start + 125) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ doDefaults(pixel);
+ },
+ behavior: behaviors.GAS,
+ tempLow: -10,
+ category: "gases",
+ state: "gas",
+ density: 2000,
+ isFood: true,
+ darkText: true,
+}
+
+elements.unstable_teleportatium = {
+ color: "#3fffff",
+ behavior: behaviors.LIQUID,
+ tick: function(pixel) {
+ var coords = rectCoords(pixel.x-1,pixel.y-1,pixel.x+1,pixel.y+1);
+ for (var i = 0; i < coords.length; i++) {
+ var x = coords[i].x;
+ var y = coords[i].y;
+ if (!isEmpty(x,y,true)) {
+ if (!outOfBounds(x,y) && (elements[pixelMap[x][y].element].slime === true)) {
+ changePixel(pixel,"teleportatium")
+ changePixel(pixelMap[x][y],"teleportatium")
+ }
+ }
+ }
+ },
+ reactions: {
+ "noita_brass": { elem1:"noita_smoke", elem2:"metal_dust", chance:0.50 },
+ "flummoxium": { elem1:"noita_smoke", elem2:"guiding_powder" },
+ "concentrated_mana": { elem1:"noita_fire", chance:0.10 },
+ "lava": { elem1:"freezing_vapour", chance:0.70 },
+ },
+ tempHigh: 150,
+ stateHigh: "teleportatium_cloud",
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1872,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.toxic_sludge = {
+ color: "#cbff11",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "brine": { elem1:"noita_water", chance:0.20 },
+ "water": { elem1:"noita_water", chance:0.13 },
+ "noita_water": { elem1:"noita_water", chance:0.13 },
+ "noita_mud": { elem1:"swamp_water", chance:0.15 },
+ },
+ viscosity: 5,
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1872,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true,
+ corrodible: true,
+ soluble: true,
+}
+
+elements.levitatium = {
+ color: "#f5f5f5",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "diminution": { elem1:"toxic_sludge", elem2:"toxic_sludge", chance:0.25 },
+ "acceleratium": { elem1:"hastium", elem2:"hastium", chance:0.25 },
+ },
+ tempHigh: 150,
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 1200,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ impure: true
+}
+
+elements.pheremone = {
+ color: "#ff4072",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ },
+ tempHigh: 150,
+ tempLow: -10,
+ category: "liquids",
+ state: "liquid",
+ density: 3513,
+ stain: -0.05,
+ isFood: true,
+ darkText: true,
+ water: true,
+ impure: true
+}
+
+// substances above
+// creatures below
+
+elements.noita = {
+ color: ["#2b2429","#151515"],
+ category: "life",
+ properties: {
+ dead: false,
+ dir: 1,
+ panic: 0
+ },
+ onPlace: function(pixel) {
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel("noita_body", pixel.x, pixel.y+1);
+ var color = pixel.color;
+ changePixel(pixel,"noita_head");
+ pixel.color = color;
+ }
+ else if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel("noita_head", pixel.x, pixel.y-1);
+ pixelMap[pixel.x][pixel.y-1].color = pixel.color;
+ changePixel(pixel,"noita_body");
+ }
+ else {
+ deletePixel(pixel.x, pixel.y);
+ }
+ },
+ reactions: {
+ },
+ related: ["noita_body","noita_head"],
+ cooldown: defaultCooldown,
+ forceSaveColor: true,
+ blood: "noita_blood",
+ living: true,
+}
+
+elements.noita_body = {
+ color: ["#996e98","#6a406a","#d69f34","#996e98","#6a406a"],
+ category: "life",
+ hidden: true,
+ density: 6000,
+ state: "solid",
+ conduct: .05,
+ tempHigh: 150,
+ stateHigh: "cooked_meat",
+ tempLow: -30,
+ stateLow: "noita_meat",
+ burn: 10,
+ burnTime: 250,
+ burnInto: "cooked_meat",
+ breakInto: "noita_meat",
+ forceSaveColor: true,
+ pickElement: "noita",
+ reactions: {
+ },
+ properties: {
+ maxhp: 10000,
+ hp: 10000,
+ 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 === "noita_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.hp < 1) {
+ pixel.element = "noita_meat"
+ if (pixel.head) {
+ pixel.head.element = "noita_meat"
+ }
+ return
+ }
+
+ // Find the head
+ if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "noita_head") {
+ pixel.head = pixelMap[pixel.x][pixel.y-1];
+ if (pixel.head.hp < 1) { // If head is dead, kill body
+ pixel.hp = pixel.head.hp;
+ }
+ else if (pixel.head.panic > 0) {
+ pixel.panic = pixel.head.panic;
+ delete pixel.head.panic;
+ }
+ }
+ else { pixel.head = null }
+ if (pixel.head && Math.random() < 0.25) {
+ let y = Math.random() < 0.5 ? 0 : -1;
+ for (let x = 1; x < 10; x++) {
+ let x2 = pixel.x+(x*pixel.dir);
+ let y2 = pixel.y+y;
+ if (!isEmpty(x2,y2,true)) {
+ let seenPixel = pixelMap[x2][y2];
+ if (elements.human.reactions[seenPixel.element] && elements.human.reactions[seenPixel.element].attr1 && elements.human.reactions[seenPixel.element].attr1.panic) {
+ pixel.panic += elements.human.reactions[seenPixel.element].attr1.panic;
+ pixel.dir *= -1;
+ break;
+ }
+ else if (seenPixel.dead || seenPixel.temp > 200) {
+ pixel.panic += 5;
+ pixel.dir *= -1;
+ if (seenPixel.panic) delete seenPixel.panic;
+ break;
+ }
+ }
+ }
+ }
+ if (pixel.burning) {
+ pixel.panic += 0.1;
+ if (head && pixelTicks-pixel.burnStart > 240) {
+ pixel.color = head.color;
+ }
+ }
+ if (pixel.charge) {
+ pixel.panic += 1;
+ }
+ else if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ if (pixel.panic < 0) { pixel.panic = 0; }
+ else if (pixel.panic > 50) { pixel.panic = 50; }
+ }
+
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ // create blood if decapitated 10% chance
+ if (Math.random() < 0.1 && !pixel.charge) {
+ createPixel("noita_blood", pixel.x, pixel.y-1);
+ // set dead to true 15% chance
+ if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ }
+ }
+ }
+ else if (pixel.head === null) { return }
+ else if (Math.random() < 0.1*(isEmpty(pixel.x, pixel.y+1) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,0],
+ [1*pixel.dir,-1],
+ ];
+ let moved = false;
+ // 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)) {
+ var origx = pixel.x+move[0];
+ var origy = pixel.y+move[1];
+ if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1]) && pixel.x===origx && pixel.y===origy) {
+ movePixel(pixel.head, pixel.head.x+move[0], pixel.head.y+move[1]);
+ moved = true;
+ break;
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.10 || !moved) {
+ pixel.dir *= -1;
+ }
+
+ }
+ if (pixel.temp > 150 && Math.random() > 0.75) {
+ DoDamage(pixel,"fire",10)
+ pixel.panic++
+ }
+ if (pixel.temp < -25) {
+ DoDamage(pixel,"ice",10)
+ pixel.panic++
+ }
+ DoNoitaHumanoid(pixel)
+ },
+ onCollide: function(pixel,damagePixel) {
+ DoNoitaStaining(pixel,damagePixel)
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ },
+ blood: "noita_blood",
+ living: true,
+}
+
+elements.noita_head = {
+ color: ["#996e98","#6a406a","#996e98","#6a406a","#2b2429","#151515","#2b2429","#151515","#2b2429","#151515","#2b2429","#151515","#2b2429","#151515","#2b2429","#151515"],
+ category: "life",
+ hidden: true,
+ density: 6000,
+ state: "solid",
+ conduct: .05,
+ tempHigh: 150,
+ stateHigh: "noita_cooked_meat",
+ tempLow: -30,
+ stateLow: "noita_meat",
+ burn: 10,
+ burnTime: 250,
+ burnInto: "cooked_meat",
+ breakInto: "noita_meat",
+ forceSaveColor: true,
+ pickElement: "noita",
+ reactions: {
+ },
+ properties: {
+ hp: 10000,
+ maxhp: 10000,
+ },
+ tick: function(pixel) {
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.hp < 1) {
+ pixel.element = "noita_meat"
+ return
+ }
+
+ // Find the body
+ if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "noita_body") {
+ var body = pixelMap[pixel.x][pixel.y+1];
+ if (body.hp !== pixel.hp) {
+ pixel.hp = body.hp;
+ }
+ }
+ else { var body = null }
+
+ // check for eating food
+ if (body && !pixel.dead && Math.random() < 0.1) {
+ shuffleArray(interactCoordsShuffle);
+ for (var i = 0; i < interactCoordsShuffle.length; i++) {
+ var x = pixel.x+interactCoordsShuffle[i][0];
+ var y = pixel.y+interactCoordsShuffle[i][1];
+ if (!isEmpty(x,y,true) && elements[pixelMap[x][y].element].isFood && pixelMap[x][y].panic === undefined) {
+ deletePixel(x,y);
+ break;
+ }
+ }
+ }
+
+ if (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 && !pixel.charge) {
+ createPixel("noita_blood", pixel.x, pixel.y+1);
+ // set dead to true 15% chance
+ if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ }
+ }
+ }
+ // homeostasis
+ if (pixel.temp > 37) { pixel.temp -= 1; }
+ else if (pixel.temp < 37) { pixel.temp += 1; }
+ },
+ onChange: function(pixel) {
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coord = adjacentCoords[i];
+ var x = pixel.x+coord[0];
+ var y = pixel.y+coord[1];
+ if (!isEmpty(x,y,true) && pixelMap[x][y].panic !== undefined) {
+ pixelMap[x][y].panic += 20;
+ }
+ }
+ },
+ onDelete: function(pixel) {
+ for (var i = 0; i < adjacentCoords.length; i++) {
+ var coord = adjacentCoords[i];
+ var x = pixel.x+coord[0];
+ var y = pixel.y+coord[1];
+ if (!isEmpty(x,y,true) && pixelMap[x][y].panic !== undefined) {
+ pixelMap[x][y].panic += 20;
+ }
+ }
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ },
+ blood: "noita_blood",
+ living: true,
+}
+
+elements.lammas = {
+ color: ["#cbcbcb","#ebebeb","#fffffe","#cbcbcb","#ebebeb","#fffffe","#ffcf93","#ffb373","#cbcbcb","#ebebeb","#fffffe"],
+ properties: {
+ maxhp: 250,
+ hp: 250,
+ dir: 1,
+ panic: 0,
+ },
+ tick: function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) {} // Fall
+ doDefaults(pixel);
+ if (pixel.hp < 1) {
+ pixel.element = "helpless_meat"
+ return
+ }
+ if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ if (pixel.panic < 0) { pixel.panic = 0; }
+ }
+ if (Math.random() < 0.1*(isEmpty(pixel.x, pixel.y+1) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,0],
+ [1*pixel.dir,-1],
+ ];
+ let moved = false;
+ // 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])) {
+ var origx = pixel.x+move[0];
+ var origy = pixel.y+move[1];
+ if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1]) && pixel.x===origx && pixel.y===origy) {
+ moved = true;
+ break;
+ }
+ }
+ else if (!isEmpty(pixel.x+move[0], pixel.y+move[1], true)) {
+ var hitPixel = pixelMap[pixel.x+move[0]][pixel.y+move[1]];
+ if (hitPixel.element === "lammas" && hitPixel.panic < pixel.panic) {
+ hitPixel.panic = pixel.panic;
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.15 || !moved) {
+ pixel.dir *= -1;
+ }
+
+ if (pixel.temp > 150 && Math.random() > 0.75) {
+ DoDamage(pixel,"fire",10)
+ pixel.panic++
+ }
+ if (pixel.temp < -25) {
+ DoDamage(pixel,"ice",10)
+ pixel.panic++
+ }
+ DoNoitaCreature(pixel)
+ }
+
+ },
+ onCollide: function(pixel,damagePixel) {
+ DoNoitaStaining(pixel,damagePixel)
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ },
+ reactions: {
+ },
+ category: "life",
+ tempLow: -50,
+ stateLow: "helpless_meat",
+ tempHigh: 200,
+ stateHigh: "helpless_meat",
+ breakInto: "helpless_meat",
+ breakIntoColor: ["#cbcbcb","#ebebeb","#fffffe","#cbcbcb","#ebebeb","#fffffe","#ffcf93","#ffb373","#cbcbcb","#ebebeb","#fffffe"],
+ blood: "noita_blood",
+ burn:80,
+ burnTime:150,
+ state: "solid",
+ density: 6000,
+ conduct: 0.25,
+ living: true,
+}
+
+elements.evakas = {
+ properties: {
+ maxhp: 250,
+ hp: 250,
+ dir: 1,
+ panic: 0,
+ },
+ tick: function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) {} // Fall
+ doDefaults(pixel);
+ if (pixel.hp < 1) {
+ pixel.element = "helpless_meat"
+ return
+ }
+ if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ if (pixel.panic < 0) { pixel.panic = 0; }
+ }
+ if (Math.random() < 0.1*((!isEmpty(pixel.x, pixel.y+1,true) && !outOfBounds(pixel.x, pixel.y+1,true) && elements[pixelMap[pixel.x][pixel.y+1].element].id === elements.noita_water.id) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,1],
+ [1*pixel.dir,-1],
+ ];
+ let moved = false;
+ 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],true) && !outOfBounds(pixel.x+move[0], pixel.y+move[1],true) && elements[pixelMap[pixel.x+move[0]][pixel.y+move[1]].element].id === elements.noita_water.id) {
+ var origx = pixel.x+move[0];
+ var origy = pixel.y+move[1];
+ swapPixels(pixel, pixelMap[pixel.x+move[0]][pixel.y+move[1]])
+ if (pixel.x===origx && pixel.y===origy) {
+ moved = true;
+ break;
+ }
+ }
+ else if (isEmpty(pixel.x+move[0], pixel.y+move[1]) || outOfBounds(pixel.x+move[0], pixel.y+move[1]) || elements[pixelMap[pixel.x+move[0]][pixel.y+move[1]].element].id !== elements.noita_water.id) {
+ }
+ else if (!isEmpty(pixel.x+move[0], pixel.y+move[1], true)) {
+ var hitPixel = pixelMap[pixel.x+move[0]][pixel.y+move[1]];
+ if (hitPixel.element === "evakas" && hitPixel.panic < pixel.panic) {
+ hitPixel.panic = pixel.panic;
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.15 || !moved || outOfBounds(pixel.x+1, pixel.y) || outOfBounds(pixel.x-1, pixel.y)) {
+ pixel.dir *= -1;
+ }
+ if (pixel.temp > 150 && Math.random() > 0.75) {
+ DoDamage(pixel,"fire",10)
+ pixel.panic++
+ }
+ if (pixel.temp < -25) {
+ DoDamage(pixel,"ice",10)
+ pixel.panic++
+ }
+ DoNoitaCreature(pixel)
+ }
+
+ },
+ onCollide: function(pixel,damagePixel) {
+ DoNoitaStaining(pixel,damagePixel)
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ },
+ color: ["#313540","#4e5b95","#4e5b95","#4c89ab"],
+ name:"eväkäs",
+ reactions: {
+ },
+ tempHigh: 200,
+ tempLow: -50,
+ stateLow: "helpless_meat",
+ category:"life",
+ stateHigh: "helpless_meat",
+ breakInto: "helpless_meat",
+ breakIntoColor: ["#313540","#4e5b95","#4e5b95","#4c89ab"],
+ blood: "noita_blood",
+ burn:20,
+ burnTime:200,
+ state: "solid",
+ density: 1080,
+ conduct: 0.2,
+ living: true,
+}
+
+elements.hamis = {
+ color: ["#52316f","#52316f","#beda65","#52316f","#52316f","#beda65","#52316f","#52316f","#beda65","#2d1b3d","#2d1b3d","#2d1b3d","#2d1b3d","#634c7e"],
+ name: "hämis",
+ properties: {
+ maxhp: 275,
+ hp: 275,
+ dir: 1,
+ panic: 0,
+ },
+ tick: function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) {} // Fall
+ doDefaults(pixel);
+ if (pixel.hp < 1) {
+ pixel.element = "noita_meat"
+ return
+ }
+ if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ if (pixel.panic < 0) { pixel.panic = 0; }
+ }
+ if (Math.random() < 0.1*(isEmpty(pixel.x, pixel.y+1) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,0],
+ [1*pixel.dir,-1],
+ ];
+ let moved = false;
+ // 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])) {
+ var origx = pixel.x+move[0];
+ var origy = pixel.y+move[1];
+ if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1]) && pixel.x===origx && pixel.y===origy) {
+ moved = true;
+ break;
+ }
+ }
+ else if (!isEmpty(pixel.x+move[0], pixel.y+move[1], true)) {
+ var hitPixel = pixelMap[pixel.x+move[0]][pixel.y+move[1]];
+ if (hitPixel.element === "hamis") {
+ DoDamage(pixel,"melee",750)
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.15 || !moved) {
+ pixel.dir *= -1;
+ }
+
+ if (pixel.temp > 150 && Math.random() > 0.75) {
+ DoDamage(pixel,"fire",10)
+ pixel.panic++
+ }
+ if (pixel.temp < -25) {
+ DoDamage(pixel,"ice",10)
+ pixel.panic++
+ }
+ DoNoitaCreature(pixel)
+ }
+
+ },
+ onCollide: function(pixel,damagePixel) {
+ DoNoitaStaining(pixel,damagePixel)
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ },
+ reactions: {
+ },
+ category: "life",
+ tempLow: -50,
+ stateLow: "noita_meat",
+ tempHigh: 200,
+ stateHigh: "noita_meat",
+ breakInto: "noita_meat",
+ breakIntoColor: ["#52316f","#52316f","#beda65","#52316f","#52316f","#beda65","#52316f","#52316f","#beda65","#2d1b3d","#2d1b3d","#2d1b3d","#2d1b3d","#634c7e"],
+ blood: "noita_blood",
+ burn:80,
+ burnTime:150,
+ state: "solid",
+ density: 6000,
+ conduct: 0.25,
+ living: true,
+}
+
+// creatures above
+// props below
+
+elements.lantern = {
+ color: ["#524526","#6c9ccc","#6c9ccc","#efd97d","#6c9ccc","#6c9ccc","#6d5c2e","#524526","#6c9ccc","#647cdc","#efd97d","#6c9ccc","#647cdc","#6d5c2e","#23211b"],
+ properties: {
+ maxhp: 375,
+ hp: 375,
+ },
+ tick: function(pixel) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ tryMove(pixel, pixel.x+(Math.random() < 0.5 ? -1 : 1), pixel.y+1);
+ }
+ doDefaults(pixel);
+ if (pixel.hp < 1) {
+ pixel.element = "glass_broken"
+ return
+ }
+
+ if (pixel.temp > 150 && Math.random() > 0.75) {
+ DoDamage(pixel,"fire",10)
+ }
+ if (pixel.temp < -25) {
+ DoDamage(pixel,"ice",10)
+ }
+
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ },
+ reactions: {
+ },
+ category: "props",
+ tempLow: -50,
+ stateLow: "glass_broken",
+ tempHigh: 200,
+ stateHigh: "glass_broken",
+ breakInto: "glass_broken",
+ breakIntoColor: ["#524526","#6c9ccc","#efd97d","#6c9ccc","#6d5c2e","#524526","#6c9ccc","#efd97d","#6c9ccc","#6d5c2e","#23211b"],
+ blood: "noita_oil",
+ burnTime:150,
+ state: "solid",
+ density: 6000,
+ conduct: 0.25,
+ living: true,
+}
+
+elements.propane_tank = {
+ color: ["#60547a","#78669d","#ccbc6c","#78669d","#8777ae","#78669d","#8f7340","#78669d","#60547a"],
+ properties: {
+ maxhp: 5000,
+ hp: 5000,
+ },
+ tick: function(pixel) {
+ if (!tryMove(pixel, pixel.x, pixel.y+1)) {
+ tryMove(pixel, pixel.x+(Math.random() < 0.5 ? -1 : 1), pixel.y+1);
+ }
+ doDefaults(pixel);
+ if (pixel.hp < 1) {
+ pixel.element = "noita_prop_steel"
+ releaseElement(pixel,"freezing_vapour")
+ NExplode(pixel.x,pixel.y,6,32500,["freezing_vapour"])
+ return
+ }
+
+ if (pixel.temp > 150 && Math.random() > 0.75) {
+ DoDamage(pixel,"fire",10)
+ }
+ if (pixel.temp < -25) {
+ DoDamage(pixel,"ice",10)
+ }
+ },
+ onBreak: function(pixel) {
+ releaseElement(pixel,elements[pixel.element].blood,4);
+ changePixel(pixel,"propane_tank_spell")
+ },
+ reactions: {
+ },
+ category: "props",
+ tempLow: -50,
+ stateLow: "noita_prop_steel",
+ tempHigh: 200,
+ stateHigh: "noita_prop_steel",
+ breakInto: "noita_prop_steel",
+ breakIntoColor: ["#60547a","#78669d","#ccbc6c","#78669d","#8777ae","#78669d","#8f7340","#78669d","#60547a"],
+ blood: "freezing_liquid",
+ burnTime:150,
+ state: "solid",
+ density: 6000,
+ conduct: 0.25,
+ living: true,
+}
+
+// props above
+// spells below
+
+elements.square_of_fire = {
+ color: "#ff9700",
+ category: "spells",
+ hidden: true,
+ tick: function(pixel){
+ if (!pixel.expandedT){
+ pixel.expandedT = 0
+ }
+ if (pixel.expandedT === 0){
+ for (i = 0; i < squareCoords.length; i++){
+ let x = squareCoords[i][0] + pixel.x;
+ let y = squareCoords[i][1] + pixel.y;
+ if (isEmpty(x, y)){
+ createPixel(pixel.element, x, y)
+ }
+ }
+ }
+ pixel.expandedT ++;
+ if (pixel.expandedT > 2){
+ if (Math.random() > 0.5) {
+ changePixel(pixel, "noita_fire")
+ return
+ }
+ else {
+ deletePixel(pixel.x,pixel.y)
+ return
+ }
+ }
+ },
+ movable: false,
+ hardness: 0.8
+}
+
+elements.square_of_acid = {
+ color: "#00ff3c",
+ category: "spells",
+ hidden: true,
+ tick: function(pixel){
+ if (!pixel.expandedT){
+ pixel.expandedT = 0
+ }
+ if (pixel.expandedT === 0){
+ for (i = 0; i < squareCoords.length; i++){
+ let x = squareCoords[i][0] + pixel.x;
+ let y = squareCoords[i][1] + pixel.y;
+ if (isEmpty(x, y)){
+ createPixel(pixel.element, x, y)
+ }
+ }
+ }
+ pixel.expandedT ++;
+ if (pixel.expandedT > 2){
+ if (Math.random() > 0.5) {
+ changePixel(pixel, "noita_acid")
+ return
+ }
+ else {
+ deletePixel(pixel.x,pixel.y)
+ return
+ }
+ }
+ },
+ movable: false,
+ hardness: 0.8
+}
+
+elements.square_of_oil = {
+ color: "#3d3628",
+ category: "spells",
+ hidden: true,
+ tick: function(pixel){
+ if (!pixel.expandedT){
+ pixel.expandedT = 0
+ }
+ if (pixel.expandedT === 0){
+ for (i = 0; i < squareCoords.length; i++){
+ let x = squareCoords[i][0] + pixel.x;
+ let y = squareCoords[i][1] + pixel.y;
+ if (isEmpty(x, y)){
+ createPixel(pixel.element, x, y)
+ }
+ }
+ }
+ pixel.expandedT ++;
+ if (pixel.expandedT > 2) {
+ if (Math.random() > 0.5) {
+ changePixel(pixel, "noita_oil")
+ return
+ }
+ else {
+ deletePixel(pixel.x,pixel.y)
+ return
+ }
+ }
+ },
+ movable: false,
+ hardness: 0.8
+}
+
+elements.square_of_water = {
+ color: "#366158",
+ category: "spells",
+ hidden: true,
+ tick: function(pixel){
+ if (!pixel.expandedT){
+ pixel.expandedT = 0
+ }
+ if (pixel.expandedT === 0){
+ for (i = 0; i < squareCoords.length; i++){
+ let x = squareCoords[i][0] + pixel.x;
+ let y = squareCoords[i][1] + pixel.y;
+ if (isEmpty(x, y)){
+ createPixel(pixel.element, x, y)
+ }
+ }
+ }
+ pixel.expandedT ++;
+ if (pixel.expandedT > 2){
+ if (Math.random() > 0.5) {
+ changePixel(pixel, "noita_water")
+ return
+ }
+ else {
+ deletePixel(pixel.x,pixel.y)
+ return
+ }
+ }
+ },
+ movable: false,
+ hardness: 0.8
+}
+
+elements.acid_ball = {
+ color: ["#84b44c","#cce464","#5c7c4c"],
+ tick: function(pixel) {
+ if (!pixel.xDir && !pixel.Dirx) {
+ let Brandom = Math.random()
+ if (Brandom > 0.5) {
+ pixel.xDir = 1
+ pixel.Dirx = true
+ }
+ else {
+ pixel.xDir = -1
+ pixel.Dirx = true
+ }
+ }
+ if (!pixel.yDir && !pixel.Diry) {
+ let Brandom = Math.random()
+ if (Brandom > 0.66) {
+ pixel.yDir = 1
+ pixel.Diry = true
+ }
+ else if (Brandom < 0.33) {
+ pixel.yDir = -1
+ pixel.Diry = true
+ }
+ else {
+ pixel.yDir = 0
+ pixel.Diry = true
+ }
+ }
+ if (!tryMove(pixel, pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ NExplode(pixel.x,pixel.y,5,0,["noita_acid"])
+ deletePixel(pixel.x,pixel.y)
+ }
+ if ((pixel.start + 330) < pixelTicks) {
+ NExplode(pixel.x,pixel.y,5,0,["noita_acid"])
+ deletePixel(pixel.x,pixel.y)
+ }
+ },
+ state: "solid",
+ category:"spells",
+ density: 1300,
+ excludeRandom: true,
+ maxSize: 1,
+ cooldown: defaultCooldown,
+ hardness: 0.8,
+}
+
+elements.bullet = {
+ color: ["#f7e787","#f7e787","#f7c34f"],
+ name: "???",
+ tick: function(pixel) {
+ if (!pixel.xDir && !pixel.Dirx) {
+ let Brandom = Math.random()
+ if (Brandom > 0.5) {
+ pixel.xDir = 1
+ pixel.Dirx = true
+ }
+ else {
+ pixel.xDir = -1
+ pixel.Dirx = true
+ }
+ }
+ if (!pixel.yDir && !pixel.Diry) {
+ let Brandom = Math.random()
+ if (Brandom > 0.66) {
+ pixel.yDir = 1
+ pixel.Diry = true
+ }
+ else if (Brandom < 0.33) {
+ pixel.yDir = -1
+ pixel.Diry = true
+ }
+ else {
+ pixel.yDir = 0
+ pixel.Diry = true
+ }
+ }
+ if (!tryMove(pixel, pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ NExplode(pixel.x,pixel.y,2,1000,["spark"])
+ deletePixel(pixel.x,pixel.y)
+ }
+ if ((pixel.start + 330) < pixelTicks) {
+ NExplode(pixel.x,pixel.y,2,1000,["spark"])
+ deletePixel(pixel.x,pixel.y)
+ }
+ },
+ state: "solid",
+ category:"spells",
+ density: 1300,
+ excludeRandom: true,
+ maxSize: 1,
+ cooldown: defaultCooldown,
+ hardness: 0.8,
+}
+
+elements.arrow = {
+ color: ["#953232","#654f2e","#9a7946","#deddd7"],
+ tick: function(pixel) {
+ if (!pixel.xDir && !pixel.Dirx) {
+ let Brandom = Math.random()
+ if (Brandom > 0.5) {
+ pixel.xDir = 1
+ pixel.Dirx = true
+ }
+ else {
+ pixel.xDir = -1
+ pixel.Dirx = true
+ }
+ }
+ if (!pixel.yDir && !pixel.Diry) {
+ let Brandom = Math.random()
+ if (Brandom > 0.66) {
+ pixel.yDir = 1
+ pixel.Diry = true
+ }
+ else if (Brandom < 0.33) {
+ pixel.yDir = -1
+ pixel.Diry = true
+ }
+ else {
+ pixel.yDir = 0
+ pixel.Diry = true
+ }
+ }
+ if (!tryMove(pixel, pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ if (pixel.bouncy == true) {
+ if (pixel.xDir != pixel.yDir) { pixel.xDir = -pixel.xDir; }
+ if (pixel.yDir != (-pixel.xDir)) { pixel.yDir = -pixel.yDir; }
+ }
+ if (!outOfBounds(pixel.x+pixel.xDir,pixel.y+pixel.yDir) && !isEmpty(pixel.x+pixel.xDir,pixel.y+pixel.yDir, true)) {
+ var hitPixel = pixelMap[pixel.x+pixel.xDir][pixel.y+pixel.yDir]
+ if (hitPixel.hp) { // lower hp
+ DoDamage(hitPixel,"ice",500)
+ }
+ }
+ pixel.element = "plant_material"
+ pixel.settled = true
+ }
+ if ((pixel.start + 330) < pixelTicks) {
+ pixel.element = "plant_material"
+ pixel.settled = true
+ }
+ },
+ state: "solid",
+ category:"spells",
+ density: 1300,
+ excludeRandom: true,
+ maxSize: 1,
+ cooldown: defaultCooldown,
+ hardness: 0.8,
+}
+
+elements.bouncing_burst = {
+ color: ["#4db73a","#358627","#95ed57"],
+ tick: function(pixel) {
+ if (!pixel.xDir && !pixel.Dirx) {
+ let Brandom = Math.random()
+ if (Brandom > 0.5) {
+ pixel.xDir = 1
+ pixel.Dirx = true
+ }
+ else {
+ pixel.xDir = -1
+ pixel.Dirx = true
+ }
+ }
+ if (!pixel.yDir && !pixel.Diry) {
+ let Brandom = Math.random()
+ if (Brandom > 0.66) {
+ pixel.yDir = 1
+ pixel.Diry = true
+ }
+ else if (Brandom < 0.33) {
+ pixel.yDir = -1
+ pixel.Diry = true
+ }
+ else {
+ pixel.yDir = 0
+ pixel.Diry = true
+ }
+ }
+ if (pixel.bounces > 10) {
+ pixel.bouncy = false
+ }
+ if (!tryMove(pixel, pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ if (pixel.bouncy == true) {
+ if (pixel.xDir != pixel.yDir) { pixel.xDir = -pixel.xDir; }
+ if (pixel.yDir != (-pixel.xDir)) { pixel.yDir = -pixel.yDir; }
+ if (!pixel.bounces) { pixel.bounces = 1 }
+ else { pixel.bounces ++ }
+ }
+ if (!outOfBounds(pixel.x+pixel.xDir,pixel.y+pixel.yDir) && !isEmpty(pixel.x+pixel.xDir,pixel.y+pixel.yDir, true)) {
+ var hitPixel = pixelMap[pixel.x+pixel.xDir][pixel.y+pixel.yDir]
+ if (hitPixel.hp) { // lower hp
+ DoDamage(hitPixel,"ice",300)
+ }
+ deletePixel(pixel.x,pixel.y)
+ }
+ if (!pixel.bouncy || (pixel.start + 330) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ }
+ },
+ properties: {
+ "bouncy": true
+ },
+ state: "solid",
+ category:"spells",
+ density: 1300,
+ excludeRandom: true,
+ maxSize: 1,
+ cooldown: defaultCooldown,
+ hardness: 0.8,
+}
+
+elements.propane_tank_spell = {
+ name: "propane_tank",
+ color: ["#60547a","#78669d","#ccbc6c","#78669d","#8777ae","#78669d","#8f7340","#78669d","#60547a"],
+ tick: function(pixel) {
+ if (!pixel.xDir && !pixel.Dirx) {
+ let Brandom = Math.random()
+ if (Brandom > 0.5) {
+ pixel.xDir = 1
+ pixel.Dirx = true
+ }
+ else {
+ pixel.xDir = -1
+ pixel.Dirx = true
+ }
+ }
+ if (!pixel.yDir && !pixel.Diry) {
+ let Brandom = Math.random()
+ if (Brandom > 0.66) {
+ pixel.yDir = 1
+ pixel.Diry = true
+ }
+ else if (Brandom < 0.33) {
+ pixel.yDir = -1
+ pixel.Diry = true
+ }
+ else {
+ pixel.yDir = 0
+ pixel.Diry = true
+ }
+ }
+ if (pixel.bounces > 5) {
+ pixel.bouncy = false
+ }
+ releaseElement(pixel,"freezing_vapour")
+ if (!tryMove(pixel, pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ if (pixel.bouncy == true) {
+ if (pixel.xDir != pixel.yDir) { pixel.xDir = -pixel.xDir; }
+ if (pixel.yDir != (-pixel.xDir)) { pixel.yDir = -pixel.yDir; }
+ if (!pixel.bounces) { pixel.bounces = 1 }
+ else { pixel.bounces ++ }
+ }
+ if (!outOfBounds(pixel.x+pixel.xDir,pixel.y+pixel.yDir) && !isEmpty(pixel.x+pixel.xDir,pixel.y+pixel.yDir, true)) {
+ var hitPixel = pixelMap[pixel.x+pixel.xDir][pixel.y+pixel.yDir]
+ if (hitPixel.hp) { // lower hp
+ DoDamage(hitPixel,"explosion",32500)
+ NExplode(pixel.x,pixel.y,6,32500,["freezing_vapour"])
+ deletePixel(pixel.x,pixel.y)
+ }
+ }
+ if (!pixel.bouncy) {
+ NExplode(pixel.x,pixel.y,6,32500,["freezing_vapour"])
+ deletePixel(pixel.x,pixel.y)
+ }
+ }
+ },
+ properties: {
+ "bouncy": true
+ },
+ state: "solid",
+ category:"spells",
+ density: 1300,
+ excludeRandom: true,
+ maxSize: 1,
+ cooldown: defaultCooldown,
+ hardness: 0.8,
+}
+
+elements.black_hole = {
+ color: ["#251b35","#251b35","#251b35","#997bc6","#997bc6","#251b35","#251b35"],
+ tick: function(pixel) {
+ if (!pixel.xDir && !pixel.Dirx) {
+ let Brandom = Math.random()
+ if (Brandom > 0.5) {
+ pixel.xDir = 1
+ pixel.Dirx = true
+ }
+ else {
+ pixel.xDir = -1
+ pixel.Dirx = true
+ }
+ }
+ if (!pixel.yDir && !pixel.Diry) {
+ let Brandom = Math.random()
+ if (Brandom > 0.66) {
+ pixel.yDir = 1
+ pixel.Diry = true
+ }
+ else if (Brandom < 0.33) {
+ pixel.yDir = -1
+ pixel.Diry = true
+ }
+ else {
+ pixel.yDir = 0
+ pixel.Diry = true
+ }
+ }
+ for (let i = -10; i < 11; i++) {
+ if (!isEmpty(pixel.x+i,pixel.y+i,true) && !outOfBounds(pixel.x+i,pixel.y+i) && elements[pixelMap[pixel.x+i][pixel.y+i].element].state == "solid" && elements[pixelMap[pixel.x+i][pixel.y+i].element].movable == true) {
+ if (pixel.x > pixel.x+i) {
+ var dirx = 1
+ }
+ else if (pixel.x < pixel.x+i) {
+ var dirx = -1
+ }
+ else {
+ var diry = 0
+ }
+ if (pixel.y > pixel.y+i) {
+ var diry = 1
+ }
+ else if (pixel.y < pixel.y+i) {
+ var diry = -1
+ }
+ else {
+ var diry = 0
+ }
+ if (dirx != undefined && diry != undefined && !((dirx==0) && (diry==0))) {
+ tryMove(pixelMap[pixel.x+i][pixel.y+i], (pixel.x+i)+dirx, (pixel.y+i)+diry)
+ }
+ }
+ }
+ for (let i = -6; i < 7; i++) {
+ for (j = -6; j < 7; j++) {
+ if (!isEmpty(pixel.x+j,pixel.y+i) && !outOfBounds(pixel.x+j,pixel.y+i) && !((i==0) && (j==0))) {
+ if (elements[pixelMap[pixel.x+j][pixel.y+i].element].state == "solid") {
+ deletePixel(pixel.x+j,pixel.y+i)
+ }
+ }
+ }
+ }
+ if (!tryMove(pixel, pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ if (!isEmpty(pixel.x+pixel.xDir, pixel.y+pixel.yDir) && !outOfBounds(pixel.x+pixel.xDir, pixel.y+pixel.yDir)) {
+ swapPixels(pixel,pixelMap[pixel.x+pixel.xDir][pixel.y+pixel.yDir])
+ }
+ else {
+ deletePixel(pixel.x,pixel.y)
+ }
+ }
+ if ((pixel.start + 130) < pixelTicks) {
+ deletePixel(pixel.x,pixel.y)
+ }
+ },
+ renderer: function(pixel,ctx) {
+ drawSquare(ctx,"#60bbf7",pixel.x-3,pixel.y-3,7,0.5);
+ drawSquare(ctx,pixel.color,pixel.x-2,pixel.y-2,5,1);
+ drawDefault(ctx,pixel);
+ },
+ state: "solid",
+ category:"spells",
+ density: 1300,
+ excludeRandom: true,
+ maxSize: 1,
+ cooldown: defaultCooldown,
+ hardness: 0.8,
+}
+
+worldgentypes.noita_surface = {
+ layers: [
+ [0.8, "soil"],
+ [0.3, "noita_rock"],
+ [0.1, "dense_rock"],
+ [0, "extremely_dense_rock"],
+ ],
+ decor: [
+ ["lammas", 0.1],
+ ]
+} /*
+
+worldgentypes.noita_lava = {
+ layers: [
+ [0.3, "lava"],
+ [0.1, "dense_rock"],
+ [0, "extremely_dense_rock"],
+ ],
+}
+
+worldgentypes.noita_holy_mountain = {
+ layers: [
+ [0.9, "extremely_dense_rock"],
+ [0.8, "dense_rock"],
+ [0.7, "brickwork"],
+ [0.3, "flash"],
+ [0.2, "brickwork"],
+ [0.1, "dense_rock"],
+ [0, "extremely_dense_rock"],
+ ],
+ baseHeight: 0.9,
+ heightVariance: 0.05,
+ complexity: 1,
+} */
\ No newline at end of file
diff --git a/mods/pixelResizeTool.js b/mods/pixelResizeTool.js
index 9d305268..d287555f 100644
--- a/mods/pixelResizeTool.js
+++ b/mods/pixelResizeTool.js
@@ -2,9 +2,15 @@ pixelResizeButton = document.createElement("button");
pixelResizeButton.onclick = function(pixel) {
let canvas_width = document.getElementById("game").width;
let canvas_height = document.getElementById("game").height;
- let pixelSizeNeeded = prompt("How big should pixels be?");
- if (!pixelSizeNeeded || isNaN(pixelSizeNeeded)) { alert('number is invalid!'); return; }
- resizeCanvas(canvas_height,canvas_width, parseFloat(pixelSizeNeeded), true);
+ promptInput("How big should pixels be?", (pixelSizeNeeded) => {
+ // let pixelSizeNeeded = prompt("How big should pixels be?");
+ if (!pixelSizeNeeded || isNaN(pixelSizeNeeded)) {
+ // alert('number is invalid!');
+ promptText("Number is invalid!");
+ return;
+ }
+ resizeCanvas(canvas_height,canvas_width, parseFloat(pixelSizeNeeded), true);
+ },"Pixel Size")
};
pixelResizeButton.textContent = "Resize";
window.addEventListener("load",function(){
diff --git a/mods/plants.js b/mods/plants.js
index 1921fc97..807c3f46 100644
--- a/mods/plants.js
+++ b/mods/plants.js
@@ -1,16 +1,67 @@
/*
-Version 2.1.0
+Version 2.2.0
*/
+function noiseify(color, range){
+ if(color.startsWith("#")){
+ color = hexToRGB(color);
+ } else {
+ color = getRGB(color);
+ }
+ let num = Math.round(Math.random()*(range*2))-range;
+ for(let value in color){
+ color[value] += num;
+ }
+ return `rgb(${color.r},${color.g},${color.b})`;
+}
let is2d = (arr)=>{
return arr.some(item => Array.isArray(item));
}
+class growInterval {
+ constructor(seedPixel, pattern, basePos, c = 0.025, dieAfter = undefined, fruit = undefined, elems = undefined){
+ let currentLength = 0;
+ let chance = c;
+ let pos = basePos;
+ let interval = setInterval(()=>{
+ if(currentLength == pattern.length || seedPixel == undefined){
+ clearInterval(interval);
+ } else {
+ let x = pos[0]+pattern[currentLength][0], y = pos[1]+pattern[currentLength][1];
+ if(Math.random() exclude[0] && angle < exclude[1]){
+ angle = min+(Math.random()*(max-min));
+ }
+ }
+ let res = [];
+ let num = (angle < 270) ? -0.5 : 0.5;
+ for(let i = 0; i < length; i++){
+ let tempAngle = (angle+(num*i))*(Math.PI/180);
+ let dX = Math.cos(tempAngle)*i, dY = Math.sin(tempAngle)*i;
+ res.push([Math.floor(dX), Math.floor(dY)]);
+ }
+ return res;
+ },
+ palm: function(length, min, max, exclude = null){
+ let angle = min+(Math.random()*(max-min));
+ if(exclude != null){
+ while(angle > exclude[0] && angle < exclude[1]){
+ angle = min+(Math.random()*(max-min));
+ }
+ }
+ let res = [];
+ let num = (angle < 270) ? -3 : 3;
+ for(let i = 0; i < length; i++){
+ let tempAngle = (angle+(num*i))*(Math.PI/180);
+ let dX = Math.cos(tempAngle)*i, dY = Math.sin(tempAngle)*i;
+ res.push([Math.floor(dX), Math.floor(dY)]);
+ }
+ return res;
+ },
+ palm_bloom: function(){
+ let res = [];
+
+ let width = 3+Math.round(Math.random()*2);
+ let length = 5+(width-3);
+ for(let i = 1; i < length; i++){
+ for(let ii = 1; ii < width; ii++){
+ res.push([-ii,i]);
+ res.push([ii,i]);
+ }
+ }
+ return res;
+ },
+ stalk: function(height){
+ let res = [];
+ for(let i = 1; i <= height; i++){
+ res.push([0, -i]);
+ }
+ return res;
+ },
};
let growthElems = {
pineapple1: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","fruit_leaves","fruit_leaves","fruit_leaves"],
@@ -35,6 +146,14 @@ let growthElems = {
melon_3x3: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower"],
melon_4x4: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower"],
melon_5x5: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower"],
+ palm_1: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves"],
+ palm_2: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves"],
+ palm_3: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves"],
+ palm_4: ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves"],
+ "palm_5-1": ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower"],
+ "palm_5-2":["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower"],
+ "coconut_5-1": ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","fruit_leaves"],
+ "coconut_5-2": ["fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","fruit_leaves","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower","flower"],
}
let ethyleneChance = {
tomato: 0.000055,
@@ -276,6 +395,35 @@ elements.fruit_leaves = {
bloomColor: "#FFE2E2",
},
tick: function(pixel){
+ if(pixel.dieAfter != undefined){
+ let chance = (pixel.age-pixel.dieAfter)/150;
+ chance = Math.max(0, Math.min(1, chance));
+ if(Math.random() < chance){
+ changePixel(pixel, "dead_plant");
+ let neighbors = [], boolArr = [];
+
+ for(let coords of squareCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2 != null){
+ neighbors[neighbors.length] = p2;
+ boolArr[boolArr.length] = (p2.dieAfter != undefined);
+ }
+ }
+ if(boolArr.includes(true)){
+ for(let coords of squareCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2 != null){
+ if(p2.dieAfter != undefined){
+ p2.age = p2.dieAfter+150;
+ }
+ }
+ }
+ }
+ }
+
+ }
if(pixelTicks == pixel.start + 1 && pixel.blooming == undefined && !pixel.growthPattern && !pixel.noBloom){
if(Math.floor(Math.random() * 3) == 2){
pixel.blooming = true;
@@ -287,13 +435,22 @@ elements.fruit_leaves = {
if(pixel.blooming && elements[pixel.fruit] != undefined && elements[pixel.fruit].bloomColor != undefined && !elements[pixel.fruit].bloomColor.includes(pixel.bloomColor)){
pixel.bloomColor = elements[pixel.fruit].bloomColor;
}
- if(pixel.blooming && !pixel.bloomColor.includes(pixel.color)){
+ if(pixel.blooming && !pixel.bloomColor.includes(pixel.c)){
let color = "";
if(Array.isArray(pixel.bloomColor)){
color = pixel.bloomColor[Math.round(Math.random()*pixel.bloomColor.length)];
+ while(color == undefined){
+ color = pixel.bloomColor[Math.round(Math.random()*pixel.bloomColor.length)];
+ }
} else {
color = pixel.bloomColor;
}
+ pixel.c = color;
+ let range = (elements[pixel.fruit] && elements[pixel.fruit].bloomRange) ? elements[pixel.fruit].bloomRange : 5;
+ let rgb = (color.startsWith("#")) ? hexToRGB(color) : getRGB(color);
+ let num = (Math.round(Math.random()*(range*2)))-range;
+ color = RGBToHex({r: Math.max(0, Math.min(255, rgb.r+num)), g: Math.max(0, Math.min(255, rgb.g+num)), b: Math.max(0, Math.min(255, rgb.b+num))});
+
pixel.color = color;
}
for(var i = 0; i < adjacentCoords.length; i++){
@@ -312,6 +469,15 @@ elements.fruit_leaves = {
} else if (!pixel.age && pixel2.age){
pixel.age = pixel2.age;
}
+ } else if(pixel2.element == "bee" && pixel.blooming){
+ for(let value of pixel2.fruitPollen){
+ if(value.fruit == pixel.fruit){
+ let rgb1 = (value.color.startsWith("#")) ? hexToRGB(value.color) : getRGB(value.color);
+ let rgb2 = (pixel.color.startsWith("#")) ? hexToRGB(pixel.color) : getRGB(pixel.color);
+ let combinedRGB = {r: (rgb1.r+rgb2.r)/2, g: (rgb1.g+rgb2.g)/2, b: (rgb1.b+rgb2.b)/2};
+ pixel.offspringColor = combinedRGB;
+ }
+ }
}
}
if(pixel.blooming && pixel.fruit == "pineapple" && Math.random() < 0.0035){
@@ -337,7 +503,11 @@ elements.fruit_leaves = {
if(pixel.fruit == "random"){
changePixel(pixel, fruits[Math.floor(Math.random() * fruits.length)]);
} else {
+ let c = (pixel.offspringColor) ? pixel.offspringColor : undefined;
changePixel(pixel, pixel.fruit);
+ if(c != undefined){
+ pixel.bloomColor = c;
+ }
}
}
}
@@ -359,6 +529,7 @@ elements.fruit_leaves = {
} else {
createPixel((growthElems[pixel.pattern][pixel.growthStage] == undefined) ? growthElems[pixel.pattern][0] : growthElems[pixel.pattern][pixel.growthStage], x, y);
pixelMap[x][y].noBloom = true;
+ pixelMap[x][y].dieAfter = pixel.dieAfter;
}
}
}
@@ -372,6 +543,7 @@ elements.fruit_leaves = {
} else {
createPixel((growthElems[pixel.pattern][pixel.growthStage] == undefined) ? growthElems[pixel.pattern][0] : growthElems[pixel.pattern][pixel.growthStage], x, y);
pixelMap[x][y].noBloom = true;
+ pixelMap[x][y].dieAfter = pixel.dieAfter;
}
}
}
@@ -528,6 +700,7 @@ elements.fruit_vine = {
if(isEmpty(x2,y2) && !outOfBounds(x2,y2)){
createPixel("fruit_vine", x2, y2);
pixelMap[x2][y2].fruit = pixel.fruit;
+ pixelMap[x2][y2].bloomColor = pixel.bloomColor;
}
} //else {pixel.drag = false;}
}
@@ -540,7 +713,7 @@ elements.fruit_vine = {
if(isEmpty(x,y) && !outOfBounds(x,y) && Math.floor(Math.random() * 5000) == 5 && pixel.age > 650){
createPixel("fruit_leaves", x, y);
pixelMap[x][y].blooming = true;
- pixelMap[x][y].color = "#FFE2E2";
+ pixelMap[x][y].bloomColor = pixel.bloomColor;
}
}
}
@@ -566,6 +739,7 @@ elements.tomato.behavior = behaviors.VINEFRUIT;
elements.grape_seed = new vineSeed("grape",["#281B01", "#2D1F06", "#2D1F06"]);
elements.tomato_seed = new vineSeed("tomato", ["#F8F5D1","#E7E5CF","#E3E1C5"]);
elements.apple = new fruit("apple", ["#FF0507", "#EC0A0D", "#F22426", "#DC2C2E"], ["#F9C497", "#EED3BB", "#EEDEBB"]);
+elements.apple.bloomColor = ["#fff0f7", "#fcebf3", "#fff0f7", "#ffe6f2", "#fff7fb"];
elements.apple_seed = new treeSeed("apple", ["#3B1C01", "#3E2107", "#3A1C02"]);
function colorMix(p1, p2, bias = 0.5){
p1.color = interpolateRgb(getRGB(p1.color), getRGB(p2.color), bias);
@@ -662,19 +836,18 @@ elements.seed_maker = {
for(let i = 0; i < squareCoords.length; i++){
let x = pixel.x+squareCoords[i][0], y = pixel.y+squareCoords[i][1];
if((!isEmpty(x,y) && !outOfBounds(x,y)) && plants.includes(pixelMap[x][y].element)){
+ let c = (pixelMap[x][y].bloomColor) ? pixelMap[x][y].bloomColor : undefined;
changePixel(pixelMap[x][y], `${pixelMap[x][y].element}_seed`);
- }
+ if(c != undefined){
+ pixelMap[x][y].bloomColor = c;
+ }
+ } else if ((!isEmpty(x,y) && !outOfBounds(x,y)) && pixelMap[x][y].alive == false){
+ pixelMap[x][y].alive = true;
+ }
}
}
}
-let r;
-if(settings.cleargases){
- if(settings.bg != undefined){
- r = interpolateRgb(hexToRGB("#E5EAEA"), hexToRGB(settings.bg), 0.85);
- } else {
- r = interpolateRgb(hexToRGB("#E5EAEA"), {r:0,g:0,b:0}, 0.85);
- }
-};
+
elements.ethylene = {
behavior: behaviors.GAS,
category: "gases",
@@ -685,8 +858,8 @@ elements.ethylene = {
reactions: {
oxidized_copper: { elem1: "vinegar", elem2: "copper", chance: 0.025},
},
- color: r || ["#fffffc", "#f7f7f2", "#eaebe6", "#ededed", "#f7f7f2", "#f2f2f2"],
- colorObject: (r != undefined) ? r.split("(")[1].split(")")[0].split(",") : undefined,
+ color: ["#fffffc", "#f7f7f2", "#eaebe6", "#ededed", "#f7f7f2", "#f2f2f2"],
+ buttonColor: ["#fffffc", "#f7f7f2"],
state: "gas",
burnInto: ["carbon_dioxide", "steam"],
burn: 100,
@@ -714,8 +887,8 @@ elements.propylene = {
reactionCatalysts: {
nickel: {e1: "hydrogen", product: "propane", chance: 0.025},
},
- color: r || ["#fffffc", "#f7f7f2", "#eaebe6", "#ededed", "#f7f7f2", "#f2f2f2"],
- colorObject: (r != undefined) ? r.split("(")[1].split(")")[0].split(",") : undefined,
+ color: ["#fffffc", "#f7f7f2", "#eaebe6", "#ededed", "#f7f7f2", "#f2f2f2"],
+ buttonColor: ["#fffffc", "#f7f7f2"],
state: "gas",
burnInto: ["carbon_dioxide", "steam"],
burn: 100,
@@ -744,6 +917,18 @@ elements.propane.reactionCatalysts = {
elements.propane.tick = function(pixel){
catalyse(pixel);
}
+runAfterAutogen(()=>{
+ let r;
+ if(settings.cleargases){
+ if(settings.bg != undefined){
+ r = interpolateRgb(hexToRGB("#E5EAEA"), hexToRGB(settings.bg), 0.85);
+ } else {
+ r = interpolateRgb(hexToRGB("#E5EAEA"), {r:0,g:0,b:0}, 0.85);
+ }
+ };
+ elements.ethylene.color = r;
+ elements.propylene.color = r;
+})
function catalyse(pixel){
let rC = elements[pixel.element].reactionCatalysts;
let neighbors = [];
@@ -785,14 +970,19 @@ elements.raspberry = new fruit("raspberry", ['#FF201C', '#EF3D3A', '#FA5350', '#
elements.raspberry_seed = new bushSeed("raspberry", ['#572600', '#4C2506', '#592E0D', '#5E3211']);
elements.blueberry = new fruit("blueberry", ['#322954', '#3F3366', '#2B1B5E', '#4C3C81'], ['#51042C', '#550E33', '#420D28', '#520F32'], "bush", ['#78573A', '#72492D', '#7D5438', '#704F3A']);
elements.blackberry = new fruit("blackberry", ['#1A013A', '#1E073A', '#3D0A49', '#33043F'], ['#DC5F5F', '#D76D6D', '#BF6363', '#B05D5D'], "bush", ['#DA7878', '#C87B7B', '#AD6161', '#915656']);
+elements.blackberry.bloomColor = ["#f5f5f5", "#ede8ec", "#ebdfe8", "#f7f2f6", "#ffffff"];
elements.strawberry = new fruit("strawberry", ['#FE3030', '#E93030', '#DE1F1F', '#CE0B0B'], ['#EA5C46', '#E24B34', '#CE5A48', '#E7604B'], "vine", ['#B27F65', '#AA7358', '#A27553', '#AF8B62'], false, true);
elements.pear = new fruit("pear", ["#F1F8A7", "#DCE398", "#E3EE7E", "#D6E07F"], ["#F6F9D5", "#F6F9D5", "#E8ECC6", "#E8ECC0"], "tree", ["#3B1C01", "#3E2107", "#3A1C02"]);
elements.mango = new fruit("mango", ["#F74E3E", "#E95D51", "#EE853B", "#D77026", "#F8BF46", "#F8B524", "#95C408", "#A5CD2D"], ["#FFC905", "#FFD605", "#FFE205", "#FFF305", "#FCE118"], "tree", ["#E8EABB", "#E3E5BA", "#EAEDC0", "#E8EAB1", "#D8DBA5"]);
elements.lemon = new fruit("lemon", ["#FCF924", "#FCF924", "#EEEA1A", "#F6F212", "#FBF70B"], ["#F6F373", "#EEEC77", "#E3E267", "#F3F18B"], "tree", ["#F8F7B2", "#E9E9B1", "#E9E8A7", "#F1EFA4"]);
elements.plum = new fruit("plum", ["#67486E", "#705476", "#634A69", "#785281"], ["#D58D77", "#DC9984", "#CA8D7A", "#CF816A"], "tree", ["#A08C5D", "#907D50", "#9B8551", "#AA9563"]);
+elements.plum.bloomColor = ["#ffb3df", "#ffa6da", "#ffbde3", "#ffd1ec"];
elements.peach = new fruit("peach", ["#F76856", "#EA5D4A", "#EA6D4A", "#E5785A", "#FE824A", "#EE7A45", "#FAA543", "#F59D39", "#FF744D"], ["#F86F1F", "#EC742F", "#EC832F", "#EC9A2F", "#ECA62F"], "tree", ["#735940", "#7B5C3D", "#7D5935"]);
+elements.peach.bloomColor = ["#ffb3df", "#ffa6da", "#ffbde3", "#ffd1ec"];
elements.apricot = new fruit("apricot", ["#F5A61F", "#F5A61F", "#EA9B12", "#F8A109"], ["#F2B016", "#F2AD0C", "#FBB81E", "#FFB301"], "tree", ["#735940", "#7B5C3D", "#7D5935"]);
+elements.apricot.bloomColor = ["#fff0fb", "#ffffff", "#fadef3", "#fcd9f4"];
elements.avocado = new fruit("avocado", ["#3c9419", "#348514", "#367a1b", "#2f7d10"], ["#cff74a", "#caf244", "#c1e649", "#b3d640"], "tree", ["#4d290a", "#4d2b0d", "#63360f", "#572d09"]);
+elements.avocado.bloomColor = ["#e3ff9c", "#e1ff96", "#e6ffa6", "#e1faa2"];
elements.avocado.breakInto = "guacamole";
elements.guacamole = {
color: ["#cff74a", "#caf244", "#c1e649", "#b3d640"],
@@ -914,6 +1104,7 @@ elements.unripe_fruit = {
elements.pineapple = {
category: "food",
breakInto: "juice",
+ bloomColor: ["#ff6682", "#ff6e88", "#ff6198", "#de73a5"],
color: ["#ffe712", "#f0d802", "#f2db05", "#d9c409"],
breakIntoColor: ["#fafa2a", "#f2f23d", "#f7f748", "#eded26"],
isFood: true,
@@ -969,6 +1160,7 @@ elements.sugarcane_seed = {
},
}
elements.watermelon = new fruit("watermelon", ["#0e6614", "#065c0c", "#03700b", "#109119", "#098f12"], ["#ff4242", "#ed2f2f", "#ff2e2e", "#ed2828"]);
+elements.watermelon.bloomColor = ["#e9ed11", "#f1f50a", "#fbff19", "#fbff29"];
elements.watermelon.behavior = behaviors.WALL;
elements.watermelon_seed = {
behavior: behaviors.POWDER,
@@ -1002,3 +1194,311 @@ elements.watermelon_seed = {
}
}
elements.tomato.bloomColor = ["#edd93e", "#fae334", "#e6dc22", "#f5ec3d"];
+elements.banana_seed = {
+ behavior: [['XX', 'XX', 'XX'],['XX', 'XX', 'XX'],['M2', 'M1 AND ST:wood', 'M2']],
+ color: ["#121211", "#121211", "#0f0f0e", "#171716"],
+ category: "life",
+ properties: {
+ age: 0,
+ fruit: "banana",
+ height: 0,
+ maxHeight: null,
+ leafLength: null,
+ intervals: [],
+ },
+ onDelete: function(pixel){
+ for(let value of pixel.intervals){
+ clearInterval(value);
+ }
+ },
+ tick: function(pixel){
+ if(pixel.maxHeight == null){
+ pixel.maxHeight = 15+Math.round(Math.random()*6);
+ }
+ if(pixel.leafLength == null){
+ pixel.leafLength = Math.round((pixel.maxHeight/21)*Math.random()*4)+12;
+ }
+ if(Math.random()<(pixel.age-95)/7500 && pixel.height < pixel.maxHeight){
+ let y = pixel.y;
+ tryMove(pixel, pixel.x, pixel.y-1);
+ pixel.height++;
+ createPixel("wood", pixel.x, y);
+ if(Math.random()<0.333){
+ let i = new growInterval(pixel, growthPatterns.palm(Math.min(Math.round((pixel.height/pixel.maxHeight)*10),10)+4, 174, 366, [235,285]), [pixel.x, y], 0.25, 250);
+ pixel.intervals.push(i.interval);
+ }
+ }
+ if(pixel.height == pixel.maxHeight && Math.random()<0.055){
+ let amnt = 6+Math.round(Math.random()*4);
+ for(let i = 0; i < amnt; i++){
+ let i = new growInterval(pixel, growthPatterns.palm(pixel.leafLength, 174, 366, [255,285]), [pixel.x, pixel.y], 0.15);
+ pixel.intervals.push(i.interval);
+ }
+ let i = new growInterval(pixel, growthPatterns.palm_bloom(), [pixel.x,pixel.y], 0.025, undefined, pixel.fruit, ["flower"]);
+ pixel.intervals.push(i.interval);
+ pixel.height++;
+ }
+ pixel.age++;
+ }
+}
+elements.dead_plant.behavior = [["XX","XX","XX"],["XX","CH:dirt%0.015","XX"],["M2","M1","M2"]];
+elements.banana = {
+ category: "food",
+ breakInto: "juice",
+ bloomColor: ["#6e2942", "#63293e", "#703249", "#82314f"],
+ color: ["#e8de20", "#f2e824", "#f0e626", "#ebe01c", "#f0e51a"],
+ breakIntoColor: ["#f2f0cb", "#f0eec5", "#f2f0c4"],
+ isFood: true,
+};
+elements.coconut = {
+ behavior: [['XX', 'XX', 'XX'],['XX', 'XX', 'XX'],['M2', 'M1 AND ST:wood', 'M2']],
+ color: ["#291706", "#382007", "#2e1905", "#361d05", "#361e06"],
+ category: "food",
+ properties: {
+ age: 0,
+ fruit: "coconut",
+ height: 0,
+ maxHeight: null,
+ alive: null,
+ leafLength: null,
+ intervals: [],
+ },
+ breakInto: "coconut_water",
+ extract: "coconut_oil",
+ onDelete: function(pixel){
+ for(let value of pixel.intervals){
+ clearInterval(value);
+ }
+ },
+ tick: function(pixel){
+ if(pixel.alive == null){
+ pixel.alive = shiftDown;
+ }
+ if(pixel.maxHeight == null){
+ pixel.maxHeight = 15+Math.round(Math.random()*6);
+ }
+ if(pixel.leafLength == null){
+ pixel.leafLength = Math.round((pixel.maxHeight/21)*Math.random()*4)+12;
+ }
+ if(pixel.alive && pixel.temp > 55){
+ pixel.alive = false;
+ }
+ if(Math.random()<(pixel.age-95)/7500 && pixel.height < pixel.maxHeight && pixel.alive){
+ let y = pixel.y;
+ tryMove(pixel, pixel.x, pixel.y-1);
+ pixel.height++;
+ createPixel("wood", pixel.x, y);
+ if(Math.random()<0.333){
+ let i = new growInterval(pixel, growthPatterns.palm(Math.round((pixel.height/pixel.maxHeight)*14), 174, 366, [235,305]), [pixel.x, y], 0.25, 200);
+ pixel.intervals.push(i.interval);
+ }
+ }
+ if(pixel.height == pixel.maxHeight && Math.random()<0.055){
+ let amnt = 6+Math.round(Math.random()*4);
+ for(let i = 0; i < amnt; i++){
+ let i = new growInterval(pixel, growthPatterns.palm(16, 174, 366, [255,285]), [pixel.x, pixel.y], 0.15);
+ pixel.intervals.push(i.interval);
+ }
+ let i = new growInterval(pixel, growthPatterns.palm_bloom(), [pixel.x,pixel.y], 0.025, undefined, pixel.fruit, ["flower"]);
+ pixel.intervals.push(i.interval);
+ pixel.height++;
+ }
+ pixel.age++;
+ }
+}
+elements.coconut_oil = {
+ behavior: behaviors.SOLID,
+ color: ["#f0efed", "#edeceb", "#e6e4e3", "#ebe9e8"],
+ category: "food",
+ isFood: true,
+ reactions: {
+ caustic_potash: {elem1: "soap", elem2: "soap"},
+ lye: {elem1: "soap", elem2: "soap"},
+ },
+ tempHigh: 24,
+ stateHigh: "melted_coconut_oil",
+ state: "solid",
+}
+elements.melted_coconut_oil = {
+ behavior: behaviors.LIQUID,
+ color: ["#f0f0eb", "#e6e5d5", "#f5f4e6", "#f7f7e6", "#ededdd"],
+ viscosity: 750,
+ category: "states",
+ state: "liquid",
+ isFood: true,
+ reactions: {
+ caustic_potash: {elem1: "soap", elem2: "soap"},
+ lye: {elem1: "soap", elem2: "soap"},
+ },
+ tempLow: 23,
+ stateLow: "coconut_oil"
+}
+elements.coconut_water = {
+ color: ["#8dd6d9", "#8cd9db", "#82d6d9"],
+ behavior: behaviors.LIQUID,
+ isFood: true,
+ category: "food",
+ state: "liquid",
+ tempHigh: 100,
+ stateHigh: ["sugar", "steam", "steam", "steam", "potassium_salt", "salt", "epsom_salt", "steam", "steam", "steam"]
+}
+elements.morning_glory_seed = {
+ behavior: behaviors.VINEFRUIT,
+ bloomColors: [["#f783f0", "#fa8cf3", "#fa96f3", "#f590ee"], ["#8d40f7", "#9a52ff", "#8041d9", "#7e3ade"], ["#ed5365", "#f0485b", "#f55b6d", "#eb3d51"], ["#f53d49", "#fa4652", "#f54e59", "#f23a46"], ["#f53d49", "#fa8cf3", "#f55b6d", "#f23a46"]],
+ color: ["#5c5036", "#473e29", "#4f4631", "#fcf2b8"],
+ properties: {
+ bloomColor: null,
+ fruit: "morning_glory_seed",
+ age: 0,
+ },
+ category: "life",
+ tick: function(pixel){
+ if(pixel.bloomColor == null){
+ let arr = elements.morning_glory_seed.bloomColors[Math.round(Math.random()*elements.morning_glory_seed.bloomColors.length)];
+ while(!Array.isArray(arr)){
+ arr = elements.morning_glory_seed.bloomColors[Math.round(Math.random()*elements.morning_glory_seed.bloomColors.length)];
+ }
+ let num = 100*(10**Math.random()/10);
+ let newArr = false;
+ for(let item of arr){
+ let o = item;
+ let rgb = hexToRGB(item);
+ let newRGB = {r: Math.min(255, rgb.r+num), g: Math.min(255, rgb.g+num), b: Math.min(255, rgb.b+num)};
+ newArr = [];
+ newArr[arr.indexOf(item)] = RGBToHex(newRGB);
+
+ }
+ pixel.bloomColor = (newArr) ? newArr : arr;
+ } else if(Math.random() < (pixel.age/2000)) {
+ let fruit = pixel.fruit, bloomColor = pixel.bloomColor;
+ changePixel(pixel, "fruit_vine");
+ pixel.fruit = fruit, pixel.bloomColor = bloomColor;
+ }
+ pixel.age++;
+ }
+}
+elements.apricot_seed.tempHigh = 175;
+elements.apricot_seed.stateHigh = "almond";
+elements.almond = {
+ color: ["#ab9450", "#b3994d", "#a18943", "#a18c43", "#a18d47"],
+ behavior: behaviors.POWDER,
+ state: "solid",
+ category: "food",
+ isFood: true,
+ density: 1100,
+ stateHigh: ["charcoal", "fire", "smoke"],
+ tempHigh: 550,
+ tick: function(pixel){
+ for(let coords of squareCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ let chance = (pixel.temp > 0) ? ((pixel.temp**0.1)-1)*0.0025 : 0;
+ if(p2 != null && p2.element == "alcohol" && Math.random() < chance){
+ changePixel(p2, "almond_extract");
+ }
+ }
+ }
+}
+elements.almond_extract = {
+ color: ["#cfccbe", "#d6d4c7", "#c9c7bb", "#ccc9b8"],
+ behavior: behaviors.LIQUID,
+ isFood: true,
+ category: "food",
+ state: "liquid",
+ density: 815,
+ tempHigh: 78,
+ stateHigh: ["alcohol_gas", "fragrance"],
+ tempLow: -118,
+ stateLow: "frozen_almond_extract",
+ burn: 100,
+ burnTime: 15,
+ fireColor: ['#80acf0', '#96cdfe', '#bee6d4'],
+ burnInto: ["fragrance", "smoke", "smoke"],
+}
+elements.frozen_almond_extract = {
+ color: ["#cfccbe", "#d6d4c7", "#c9c7bb", "#ccc9b8"],
+ behavior: behaviors.SOLID,
+ isFood: true,
+ category: "states",
+ state: "solid",
+ density: 865,
+ tempHigh: -117,
+ stateHigh: "almond_extract",
+}
+
+elements.onion = {
+ category: "food",
+ color: ["#dbaa5a", "#cc9b4b", "#bd9048", "#faebb4", "#fcf5d9", "#f2e9c7", "#7d2d50", "#ad3d6e", "#c25182"],
+ state: "solid",
+ properties: {
+ age: 0,
+ sprouted: null,
+ intervals: [],
+ height: null,
+ },
+ isFood: true,
+ behavior: behaviors.POWDER,
+ onDelete: function(pixel){
+ for(let value of pixel.intervals){
+ clearInterval(value);
+ }
+ },
+ tick: function(pixel){
+ let inDirt = (getPixel(pixel.x,pixel.y+1) != null && eLists.SOIL.includes(pixelMap[pixel.x][pixel.y+1].element)) ? true : false;
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2 != null){
+ inDirt = (eLists.SOIL.includes(p2.element)) ? true : inDirt;
+ }
+ if((pixel.sprouted == null && pixel.sprouted != "disabled") && pixel.age > 60 && inDirt){
+ let height = 7+Math.round(Math.random()*4);
+ pixel.height = height;
+ let i = new growInterval(pixel, growthPatterns.stalk(height), [pixel.x,pixel.y], 0.15);
+ pixel.intervals.push(i.interval);
+ pixel.sprouted = true;
+ } else if ((pixel.sprouted == true && pixel.sprouted != "disabled") && Math.random() < 0.0015){
+ let i = new growInterval(pixel, growthPatterns.blade(7, 235, 315, [255,295]), [pixel.x,pixel.y], 0.15);
+ pixel.intervals.push(i.interval);
+ }
+ }
+ if(inDirt){
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2!=null && eLists.SOIL.includes(p2.element) && Math.random()<0.0005){
+ changePixel(p2, "onion");
+ p2.color = noiseify(pixel.color, 6);
+ p2.sprouted = "disabled";
+ }
+ }
+ }
+ if(pixel.sprouted === true && pixel.age > 600 && Math.random()<0.001){
+ let length = Math.round(Math.random()*2);
+ for(let i = 0; i < 5; i++){
+ let ii = new growInterval(pixel, growthPatterns.blade(length,0,360), [pixel.x, pixel.y-pixel.height-length+1], 0.25, undefined, "onion_seed",['flower']);
+ pixel.intervals.push(ii.interval);
+ }
+ }
+ pixel.age++;
+ },
+}
+elements.onion_seed = {
+ behavior: behaviors.POWDER,
+ color: ["#0f0f0f", "#0f0f0f", "#0a0a0a", "#0a0a0a"],
+ category: "life",
+ state: "solid",
+ tick: function(pixel){
+ let inDirt = (getPixel(pixel.x,pixel.y+1) != null && eLists.SOIL.includes(pixelMap[pixel.x][pixel.y+1].element)) ? true : false;
+ for(let coords of adjacentCoords){
+ let x = pixel.x+coords[0], y = pixel.y+coords[1];
+ let p2 = getPixel(x,y);
+ if(p2 != null){
+ inDirt = (eLists.SOIL.includes(p2.element)) ? true : inDirt;
+ }
+ }
+ if(inDirt && Math.random() < 0.025){
+ changePixel(pixel, "onion");
+ }
+ }
+}
diff --git a/mods/replace.js b/mods/replace.js
index c458b5bf..eaf374c4 100644
--- a/mods/replace.js
+++ b/mods/replace.js
@@ -10,26 +10,30 @@ document.addEventListener("keydown", function(e) { //replace prompt listener
});
function replaceElementPrompt() {
- var fromElement = prompt("Enter the element you want to change");
- // replace spaces with underscores
- fromElement = fromElement.replace(/ /g, "_");
- fromElementS = mostSimilarElement(fromElement);
- if (fromElementS === null || fromElementS === undefined || fromElementS === "") {
- alert("Element \"" + fromElement + "\" not found! Defaulting to rock.");
- fromElementS = "rock";
- };
-
- var toElement = prompt("Enter what you want to replace \"" + fromElementS + "\" with");
- // replace spaces with underscores
- toElement = toElement.replace(/ /g, "_");
- toElementS = mostSimilarElement(toElement);
- if (toElementS === null || toElementS === undefined || toElementS === "") {
- alert("Element \"" + toElement + "\" not found! Defaulting to sand.");
- toElementS = "sand";
- };
- replaceFrom = fromElementS;
- replaceTo = toElementS;
- updateReplaceDescriptions();
+ promptInput("Enter the element you want to change", (fromElement) => {
+ // var fromElement = prompt("Enter the element you want to change");
+ // replace spaces with underscores
+ fromElement = fromElement.replace(/ /g, "_");
+ fromElementS = mostSimilarElement(fromElement);
+ if (fromElementS === null || fromElementS === undefined || fromElementS === "") {
+ alert("Element \"" + fromElement + "\" not found! Defaulting to rock.");
+ fromElementS = "rock";
+ };
+
+ promptInput("Enter what you want to replace \"" + fromElementS + "\" with", (toElement) => {
+ // var toElement = prompt("Enter what you want to replace \"" + fromElementS + "\" with");
+ // replace spaces with underscores
+ toElement = toElement.replace(/ /g, "_");
+ toElementS = mostSimilarElement(toElement);
+ if (toElementS === null || toElementS === undefined || toElementS === "") {
+ alert("Element \"" + toElement + "\" not found! Defaulting to sand.");
+ toElementS = "sand";
+ };
+ replaceFrom = fromElementS;
+ replaceTo = toElementS;
+ updateReplaceDescriptions();
+ },"Replace With")
+ },"Replace Element")
}
function updateReplaceDescriptions() {
diff --git a/mods/schematics.js b/mods/schematics.js
new file mode 100644
index 00000000..f49b44a6
--- /dev/null
+++ b/mods/schematics.js
@@ -0,0 +1,211 @@
+// for pasting schematics (mostly logic gates)
+// created by SquareScreamYT/sq
+// https://github.com/SquareScreamYT/
+// https://youtube.com/@sqec
+
+elems = {
+ e: "ecloner", // ecloner with flash at -250c
+ E: "ecloner", // ecloner with flash at 20c
+ c: "cloner", // cloner with flash at -250c
+ C: "cloner", // cloner with flash at 20c
+ l: "ecloner", // ecloner with sand
+ L: "ecloner", // ecloner with liquid light
+ A: "ecloner", // cloner with antifluid
+ a: "ecloner", // cloner with antipowder
+ p: "porcelain",
+ W: "water",
+ w: "wall",
+ m: "meat",
+ b: "battery",
+ f: "flash",
+ s: "sensor",
+ x: "wire",
+ F: "fuse",
+ v: "void",
+ R: "led_r",
+ G: "led_g",
+ B: "led_b",
+}
+
+schematics = {
+
+not_gate_1: `
+C e
+ b
+ m
+ x
+`,
+
+not_gate_2: `
+CeC
+
+pWp
+wsw
+`,
+
+or_gate: `
+E E
+ s
+`,
+
+and_gate: `
+Ce eC
+
+pWwWp
+wsxsw
+ CeC
+
+ pWp
+ wsw
+`,
+
+nand_gate: `
+Ce eC
+
+pWwWp
+wsxsw
+`,
+
+nor_gate: `
+Ce eC
+
+pWwWp
+wsxsw
+ CeC
+
+ pWp
+ wsw
+`,
+
+xor_gate: `
+w x x w
+ xxxe exxx
+ xC Cx
+ x pWwWp x
+ x wsxsw x
+Ce ex xe eC
+ C
+pWwWp pWwWp
+wsxsx xsxsw
+ Ce eC
+
+ pWwWp
+ wsxsw
+`,
+
+xnor_gate: `
+w x x w
+ xxxe exxx
+ xC Cx
+ x pWwWp x
+ x wsxsw x
+Ce ex xe eC
+ C
+pWwWp pWwWp
+wsxsx xsxsw
+ Ce eC
+
+ pWwWp
+ wsxsw
+ CeC
+
+ pWp
+ wsw
+`,
+
+intersection_tl: `
+wlww
+A s
+w vw
+wsww
+`,
+
+intersection_tr: `
+wwlw
+s A
+wv w
+wwsw
+`,
+
+intersection_bl: `
+wsww
+w vw
+L s
+waww
+`,
+
+intersection_br: `
+wwsw
+wv w
+s L
+wwaw
+`,
+
+}
+
+function pasteSchematic(pattern, startX, startY) {
+ const lines = pattern.trim().split('\n');
+ for (let y = 0; y < lines.length; y++) {
+ for (let x = 0; x < lines[y].length; x++) {
+ const char = lines[y][x];
+ if (char !== ' ' && elems[char]) {
+ const pixelX = startX + x;
+ const pixelY = startY + y;
+ if (isEmpty(pixelX, pixelY)) {
+ createPixel(elems[char], pixelX, pixelY);
+ if (char.toLowerCase() == "e" || char.toLowerCase() == "c") {
+ pixelMap[pixelX][pixelY].clone = "flash"
+ if (char.toLowerCase() == char) {
+ pixelMap[pixelX][pixelY].temp = -250
+ }
+ } else if (char.toLowerCase() == "l" || char.toLowerCase() == "a") {
+ if (char == "a") {
+ pixelMap[pixelX][pixelY].clone = "antipowder"
+ } else if (char == "A") {
+ pixelMap[pixelX][pixelY].clone = "antifluid"
+ } else if (char == "L") {
+ pixelMap[pixelX][pixelY].clone = "liquid_light"
+ pixelMap[pixelX][pixelY].temp = -273.15
+ } else if (char == "l") {
+ pixelMap[pixelX][pixelY].clone = "sand"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+for (schematic in schematics) {
+ elements[schematic] = {
+ category: "schematics",
+ color: "#888888",
+ behavior: behaviors.WALL,
+ state: "solid",
+ maxSize: 1,
+ onSelect: (function(pattern) {
+ return function() {
+ const lines = pattern.trim().split('\n');
+ let pixelCount = 0;
+ const height = lines.length;
+ const width = Math.max(...lines.map(line => line.length));
+ for (let y = 0; y < lines.length; y++) {
+ for (let x = 0; x < lines[y].length; x++) {
+ const char = lines[y][x];
+ if (char !== ' ' && elems[char]) {
+ pixelCount++;
+ }
+ }
+ }
+ logMessage(pixelCount + " pixels, " + width + "x" + height);
+ }
+ })(schematics[schematic]),
+ tick: (function(pattern) {
+ return function(pixel) {
+ deletePixel(pixel.x, pixel.y);
+ pasteSchematic(pattern, pixel.x, pixel.y);
+ }
+ })(schematics[schematic]),
+ excludeRandom: true
+ }
+}
\ No newline at end of file
diff --git a/mods/worldEdit.js b/mods/worldEdit.js
index baec5a16..5da6a623 100644
--- a/mods/worldEdit.js
+++ b/mods/worldEdit.js
@@ -1,6 +1,6 @@
"use strict";
// WorldEdit.js (compiled)
-// Version: 1.1.0
+// Version: 1.2.0
// Constants
const w_accentColor = "#7cff62";
const w_style = {
@@ -9,7 +9,8 @@ const w_style = {
selectStroke: w_accentColor,
selectDash: true,
pasteFill: "#00FFFF40",
- pasteStroke: "#00FFFF"
+ pasteStroke: "#00FFFF",
+ pastePixelColor: "#00FFFF44"
};
// Global variables
let worldEditElements = {};
@@ -18,7 +19,7 @@ let w_state = {
firstSelectionPos: {x: 0, y: 0},
selection: null,
clipboard: null,
- prevNonWorldEditElement: "unknown"
+ lastNonWorldEditElement: "unknown"
};
// Define settings
let w_settingsTab;
@@ -81,6 +82,10 @@ class Rect {
}
// Functions
+function reverseString(str) {
+ return [...str].reverse().join("");
+}
+
function isPointInWorld(point) {
return point.x >= 0 && point.x <= width && point.y >= 0 && point.y <= height;
}
@@ -112,10 +117,11 @@ function updatePastePreviewCanvas() {
const imageData = pastePreviewCtx.createImageData(clipboardRect.w, clipboardRect.h);
const buffer = new Uint32Array(imageData.data.buffer);
buffer.fill(0x00000000);
+ const pixelColorBinary = parseInt(reverseString(w_style.pastePixelColor.slice(1)), 16);
for (let y = 0; y < clipboardRect.h; y++) {
for (let x = 0; x < clipboardRect.w; x++) {
if (clipboard[y][x])
- buffer[y * clipboardRect.w + x] = 0x44FFFF00;
+ buffer[y * clipboardRect.w + x] = pixelColorBinary;
}
}
pastePreviewCtx.putImageData(imageData, 0, 0);
@@ -200,8 +206,8 @@ function modifySelectElement() {
// @ts-ignore
selectElement = (element) => {
// Keep track of last non-worldEdit element
- if (!worldEditElements.hasOwnProperty(currentElement))
- w_state.prevNonWorldEditElement = currentElement;
+ if (!worldEditElements.hasOwnProperty(element))
+ w_state.lastNonWorldEditElement = element;
originalSelectElement(element);
};
}
@@ -221,7 +227,7 @@ function addWorldEditElements(elementsToAdd) {
element.rawOnSelect = originalOnSelect;
element.onSelect = function (...args) {
originalOnSelect(...args);
- selectElement(w_state.prevNonWorldEditElement);
+ selectElement(w_state.lastNonWorldEditElement);
};
}
}
@@ -248,17 +254,17 @@ worldEditElements.w_select = {
return;
if (!isPointInWorld(pos))
return;
- if (mouseType === "middle" || mouseType === "right")
+ if (e.button === 1 || e.button === 2)
return;
w_state.firstSelectionPos = pos;
},
- onPointerMove: function (e) {
+ onPointerMoveAnywhere: function (e) {
const pos = mousePosToWorldPos({x: e.clientX, y: e.clientY});
if (!mouseIsDown)
return;
if (showingMenu)
return;
- if (mouseType === "middle" || mouseType === "right")
+ if (e.button === 1 || e.button === 2)
return;
if (currentElement !== "w_select")
return;
@@ -291,12 +297,12 @@ worldEditElements.w_copy = {
}
};
worldEditElements.w_paste = {
- onPointerDown: function () {
+ onPointerDown: function (e) {
if (showingMenu)
return;
if (!isPointInWorld(mousePos))
return;
- if (mouseType === "middle" || mouseType === "right")
+ if (e.button === 1 || e.button === 2)
return;
const clipboard = w_state.clipboard;
if (!clipboard) {
@@ -380,7 +386,7 @@ worldEditElements.w_delete = {
worldEditElements.w_fill = {
onSelect: function () {
const selection = w_state.selection;
- const fillElement = w_state.prevNonWorldEditElement;
+ const fillElement = w_state.lastNonWorldEditElement;
if (!selection) {
logMessage("Error: Nothing is selected.");
return;
@@ -388,9 +394,11 @@ worldEditElements.w_fill = {
// Fill area
for (let y = selection.y; y < selection.y2; y++) {
for (let x = selection.x; x < selection.x2; x++) {
+ if (pixelMap[x][y])
+ continue;
const placed = currentPixels.push(new Pixel(x, y, fillElement));
if (!placed)
- return;
+ continue;
if (currentPixels.length > maxPixelCount || !fillElement) {
currentPixels[currentPixels.length - 1].del = true;
} else if (elements[fillElement] && elements[fillElement].onPlace !== undefined) {
@@ -425,5 +433,9 @@ runAfterReset(() => {
if (elements[currentElement] && elements[currentElement].onPointerMove)
elements[currentElement].onPointerMove(e);
}, {passive: false});
+ document.addEventListener("pointermove", (e) => {
+ if (elements[currentElement] && elements[currentElement].onPointerMoveAnywhere)
+ elements[currentElement].onPointerMoveAnywhere(e);
+ });
addedCustomEventListeners = true;
});
diff --git a/mods/worldEdit.ts b/mods/worldEdit.ts
index b6405fa4..c21d5d6e 100644
--- a/mods/worldEdit.ts
+++ b/mods/worldEdit.ts
@@ -1,12 +1,12 @@
// WorldEdit.ts
-// Version: 1.1.0
+// Version: 1.2.0
// Interfaces
interface WorldEditState {
firstSelectionPos: Vec2D,
clipboard: Pixel[][] | null
selection: Rect | null
- prevNonWorldEditElement: string
+ lastNonWorldEditElement: string
}
interface WorldEditStyle {
@@ -16,17 +16,21 @@ interface WorldEditStyle {
selectDash: boolean
pasteFill: string
pasteStroke: string
+ pastePixelColor: string
}
// Constants
const w_accentColor = "#7cff62"
const w_style: WorldEditStyle = {
strokeWidth: 1,
+
selectFill: "#57b64530",
selectStroke: w_accentColor,
selectDash: true,
+
pasteFill: "#00FFFF40",
- pasteStroke: "#00FFFF"
+ pasteStroke: "#00FFFF",
+ pastePixelColor: "#00FFFF44"
}
// Global variables
@@ -37,7 +41,7 @@ let w_state: WorldEditState = {
firstSelectionPos: {x: 0, y: 0},
selection: null,
clipboard: null,
- prevNonWorldEditElement: "unknown"
+ lastNonWorldEditElement: "unknown"
}
// Define settings
@@ -121,6 +125,10 @@ class Rect {
}
// Functions
+function reverseString(str: string): string {
+ return [...str].reverse().join("")
+}
+
function isPointInWorld(point: Vec2D): boolean {
return point.x >= 0 && point.x <= width && point.y >= 0 && point.y <= height
}
@@ -159,10 +167,17 @@ function updatePastePreviewCanvas(): void {
buffer.fill(0x00000000)
+ const pixelColorBinary: number = parseInt(
+ reverseString(
+ w_style.pastePixelColor.slice(1)
+ ),
+ 16
+ );
+
for (let y = 0; y < clipboardRect.h; y++) {
for (let x = 0; x < clipboardRect.w; x++) {
if (clipboard[y][x])
- buffer[y * clipboardRect.w + x] = 0x44FFFF00
+ buffer[y * clipboardRect.w + x] = pixelColorBinary
}
}
@@ -280,8 +295,8 @@ function modifySelectElement(): void {
// @ts-ignore
selectElement = (element: string): void => {
// Keep track of last non-worldEdit element
- if (!worldEditElements.hasOwnProperty(currentElement))
- w_state.prevNonWorldEditElement = currentElement
+ if (!worldEditElements.hasOwnProperty(element))
+ w_state.lastNonWorldEditElement = element
originalSelectElement(element)
}
@@ -304,7 +319,7 @@ function addWorldEditElements(elementsToAdd: ElementsType): void {
element.rawOnSelect = originalOnSelect
element.onSelect = function (...args: any[]) {
originalOnSelect(...args)
- selectElement(w_state.prevNonWorldEditElement)
+ selectElement(w_state.lastNonWorldEditElement)
}
}
}
@@ -334,16 +349,16 @@ worldEditElements.w_select = {
if (showingMenu) return
if (!isPointInWorld(pos)) return
- if (mouseType === "middle" || mouseType === "right") return
+ if (e.button === 1 || e.button === 2) return
w_state.firstSelectionPos = pos
},
- onPointerMove: function (e: PointerEvent): void {
+ onPointerMoveAnywhere: function (e: PointerEvent): void {
const pos = mousePosToWorldPos({x: e.clientX, y: e.clientY})
if (!mouseIsDown) return
if (showingMenu) return
- if (mouseType === "middle" || mouseType === "right") return
+ if (e.button === 1 || e.button === 2) return
if (currentElement !== "w_select") return
const rect = Rect.fromCorners(
@@ -388,10 +403,11 @@ worldEditElements.w_copy = {
}
worldEditElements.w_paste = {
- onPointerDown: function (): void {
+ onPointerDown: function (e: PointerEvent): void {
if (showingMenu) return
if (!isPointInWorld(mousePos)) return
- if (mouseType === "middle" || mouseType === "right") return
+
+ if (e.button === 1 || e.button === 2) return
const clipboard = w_state.clipboard
@@ -430,7 +446,6 @@ worldEditElements.w_cut = {
onSelect: function (): void {
const selection = w_state.selection
-
if (!selection) {
logMessage("Error: Nothing is selected.")
return
@@ -489,7 +504,7 @@ worldEditElements.w_delete = {
worldEditElements.w_fill = {
onSelect: function (): void {
const selection = w_state.selection
- const fillElement = w_state.prevNonWorldEditElement
+ const fillElement = w_state.lastNonWorldEditElement
if (!selection) {
logMessage("Error: Nothing is selected.")
@@ -499,8 +514,10 @@ worldEditElements.w_fill = {
// Fill area
for (let y = selection.y; y < selection.y2; y++) {
for (let x = selection.x; x < selection.x2; x++) {
+ if (pixelMap[x][y]) continue
+
const placed = currentPixels.push(new Pixel(x, y, fillElement))
- if (!placed) return
+ if (!placed) continue
if (currentPixels.length > maxPixelCount || !fillElement) {
currentPixels[currentPixels.length - 1].del = true
@@ -543,5 +560,10 @@ runAfterReset(() => {
elements[currentElement].onPointerMove(e)
}, {passive: false})
+ document.addEventListener("pointermove", (e: PointerEvent) => {
+ if (elements[currentElement] && elements[currentElement].onPointerMoveAnywhere)
+ elements[currentElement].onPointerMoveAnywhere(e)
+ })
+
addedCustomEventListeners = true
})