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). ![Landscape made in Sandboxels](https://raw.githubusercontent.com/R74nCom/sandboxels/main/icons/cover-3840x1240px-text.png) - + +# 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

  1. Go to the official Sandboxels website.
  2. Press the Mods button in the toolbar to open the Mod Manager.
  3. @@ -89,7 +94,7 @@
  4. 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 @@ + @@ -263,6 +269,7 @@ + @@ -394,6 +401,7 @@ + @@ -473,11 +481,12 @@
text.jsTools to write textRedBirdly
texturepack.jsTools that let you create and share custom texture packsnousernamefound
the_ground.jsSeveral rock types, worldgen settings, and gemstonesAlice
worldEdit.jsSelection and editing toolsRedBirdly
worldgenlibrary.jsWorld generation libraryAdora
Science & Chemistry
pullers.jsPixels that pull pixels towards themvoidapex11
pushers.jsPixels that push elements away from themAlice
sandboxels.jsDigital screen to play a mini version of SandboxelsNekonico
schematics.jsSchematics for logic gatesSquareScreamYT
spouts.jsSpouts for all liquidskaeud
state_voids.jsSeveral elements that delete specific states of matterAlice
switches.jsElectrical switches that can be toggledAlice
Visual Effects
acid_and_shapes.jsWeird visual effects enabled in settingsAlice
asciiboxels.jsRenders pixels as ASCII charactersNekonico
clouds.jsMoving clouds, sky.js recommendedRedBirdly
customBackground.jsSet your background to an image linkJayd
fast_lightmap.jsLight sources glow, but fasterRedBirdly
-

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 })