diff --git a/README.md b/README.md
index 68beee50..dfa4a21d 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Play at [Sandboxels.R74n.com](https://sandboxels.r74n.com/).
Join the [Discord server](https://discord.com/invite/ejUc6YPQuS).

-
+
# Controls
* Left Click = Draw pixels
* Right Click = Erase pixels
diff --git a/lang/cs.json b/lang/cs.json
index 25a64d8f..6eb4758f 100644
--- a/lang/cs.json
+++ b/lang/cs.json
@@ -527,21 +527,21 @@
"molten_potassium_salt":"Rozteklá_Draselná_Sůl",
"molten_sodium_acetate":"Rozteklý_Octan_Sodný",
"frozen_nitro":"Zmrzlé_Nitro",
-"cured_meat": "Uzené_Maso",
-"nut_oil": "Ořechový_Olej",
-"grease": "Tuk",
-"fat": "Tuk",
-"potassium": "Draslík",
-"molten_potassium": "Rozteklý_Draslík",
-"magnesium": "Magnézium",
-"molten_magnesium": "Rozteklé_Magnézium",
-"sandstorm": "Píšecná_Bouře",
-"caustic_potash": "Potaš",
-"antibomb": "Anti-bomba",
-"tornado": "Tornádo",
-"earthquake": "Zemětřesení",
-"tsunami": "Tsunami",
-"blaster": "Blaster",
-"propane_ice": "Zrmzlý_Propan",
-"molten_caustic_potash": "Rozteklý_Potaš"
+"cured_meat":"Uzené_Maso",
+"nut_oil":"Ořechový_Olej",
+"grease":"Tuk",
+"fat":"Tuk",
+"potassium":"Draslík",
+"molten_potassium":"Rozteklý_Draslík",
+"magnesium":"Magnézium",
+"molten_magnesium":"Rozteklé_Magnézium",
+"sandstorm":"Píšecná_Bouře",
+"caustic_potash":"Potaš",
+"antibomb":"Anti-bomba",
+"tornado":"Tornádo",
+"earthquake":"Zemětřesení",
+"tsunami":"Tsunami",
+"blaster":"Blaster",
+"propane_ice":"Zrmzlý_Propan",
+"molten_caustic_potash":"Rozteklý_Potaš"
}
diff --git a/mod-list.html b/mod-list.html
index b04ea04d..cbc7784f 100644
--- a/mod-list.html
+++ b/mod-list.html
@@ -177,7 +177,7 @@
| Science & Chemistry |
| alcohol.js | Adds methanol, (iso-)propanol, and butanol | Alice |
| alkahest.js | Adds the alkahest, a liquid which dissolves anything | Alice |
-| aScientistsWish.js | Adds things that related to science, especially radiation | Carbon Monoxide, salmonfishy |
+| aScientistsWish.js | Adds several things that related to science and physics | Carbon Monoxide, salmonfishy |
| bettermetalscrap.js | Allows metal scrap to be melted back into its original material | nousernamefound |
| bigger_star_spawners.js | Adds spawners for larger stars | Alice |
| bioooze_and_pyrogens.js | Adds Bio-Ooze from Frackin’ Universe and several heat-producing materials from various games’ mods | Alice |
@@ -185,6 +185,7 @@
| chalcopyrite.js | Adds the chalcopyrite ore | Sophie |
| chem.js | Adds several chemistry and physics-related elements | lllllllllwith10ls |
| clf3.js | Adds Chlorine Trifluoride | Alice |
+| fire_extinguisher.js | Adds fire extinguisher blocks and realistic firefighting foam to put out nearly anything | Dr_Lego |
| fire_mod.js | Adds various properties to change fire behavior, & a radioactive version of fire | Alice |
| fire_slime.js | Adds a pyrogenic version of slime | Alice |
| Gemstones.js | Adds more gemstones | Schweeny |
@@ -314,7 +315,7 @@
| lone_urea.js | Adds urea without the rest of the piss mod | Alice |
| maze.js | Adds a solvable maze generator | ggod |
| memelists.js | Makes it so you must select elements through a list at the bottom of the page. We like lists | mollthecoder |
-| minecraft.js | Adds several things from Minecraft | StellarX20 |
+| minecraft.js | Adds several things from Minecraft | StellarX20, nousernamefound |
| minesweeper.js | A subpar implementation of Minesweeper | Alice |
| musicalfruit.js | Humans get gas from eating Beans | mollthecoder |
| prideflags.js | Adds some pride flags to the game. | Adora |
diff --git a/mods/aScientistsWish.js b/mods/aScientistsWish.js
index 258159bf..64769c97 100644
--- a/mods/aScientistsWish.js
+++ b/mods/aScientistsWish.js
@@ -1,580 +1,1159 @@
+//this mod is still on proggres (WIP) you can give feedback or report bug to these discord account. @salmonfishy or @carbon_monoxides6
+
elements.carbon_monoxide = {
- color: "#b5b5b5",
- behavior: behaviors.GAS,
- behaviorOn: [
- "XX|XX|XX",
- "XX|CH:fire|XX",
- "XX|XX|XX",
- ],
- category: "gases",
- state: "gas",
- density: 1.14,
- burn: 75,
- tempHigh: 609,
- stateHigh: "fire",
- tempLow: -192,
- stateLow: "liquid_carbon_monoxide",
- burntime: 5,
- darkText: true,
- fireColor: "#ebba34",
- reactions: {
- "head": { elem1:"rotten_meat", chance:0.5 },
- "body": { elem1:"rotten_meat", chance:0.5 },
- "human": { elem1:"rotten_meat", chance:0.5 },
- }
+ color: "#b5b5b5",
+ behavior: behaviors.GAS,
+ behaviorOn: [
+ "XX|XX|XX",
+ "XX|CH:fire|XX",
+ "XX|XX|XX",
+],
+ category: "gases",
+ state: "gas",
+ density: 1.14,
+ burn: 75,
+ tempHigh: 609,
+ stateHigh: "fire",
+ tempLow: -192,
+ stateLow: "liquid_carbon_monoxide",
+ burntime: 5,
+ darkText: true,
+ fireColor: "#ebba34",
+ reactions: {
+ "head": { elem2:"rotten_meat", chance:0.5 },
+ "body": { elem2:"rotten_meat", chance:0.5 },
+ "human": { elem2:"rotten_meat", chance:0.5 },
+ }
};
elements.liquid_carbon_monoxide = {
- color: "#b5b5b5",
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 1.14,
- darkText: true,
- tempHigh: -190,
- temp: -192,
- tempLow: -199,
- hidden: true,
- stateLow: "ice_carbon_monoxide",
- stateHigh: "carbon_monoxide",
+ color: "#b5b5b5",
+ behavior: behaviors.LIQUID,
+ category: "liquids",
+ state: "liquid",
+ density: 1.14,
+ darkText: true,
+ tempHigh: -190,
+ temp: -192,
+ tempLow: -199,
+ hidden: true,
+ stateLow: "ice_carbon_monoxide",
+ stateHigh: "carbon_monoxide",
};
elements.ice_carbon_monoxide = {
- color: "#b5b5b5",
- behavior: behaviors.WALL,
- category: "solids",
- state: "solid",
- temp: -199,
- density: 1.14,
- tempHigh: -192,
- darkText: true,
- stateHigh: "liquid_carbon_monoxide",
+ color: "#b5b5b5",
+ behavior: behaviors.WALL,
+ category: "solids",
+ state: "solid",
+ temp: -199,
+ density: 1.14,
+ tempHigh: -192,
+ darkText: true,
+ stateHigh: "liquid_carbon_monoxide",
};
elements.carbon_monoxide_detector = {
- behavior: behaviors.WALL,
- desc: "give red light and electric when found Carbon Monoxide touch",
- color: "#ffffff",
- reactions: {
- "carbon_monoxide": {"charge1":1},
- },
- conduct: 1,
- tempHigh: 1550,
- stateHigh: ["molten_metal_scrap","electric","molten_plastic"],
- colorOn: "#ff0000",
- movable: false,
- insulate: true,
- noMix: true,
- category:"machines",
- darkText: true,
- hardness: 1,
+ behavior: behaviors.WALL,
+ desc: "give red light and electric when found Carbon Monoxide touch",
+ color: "#ffffff",
+ reactions: {
+ "carbon_monoxide": {"charge1":1},
+ },
+ conduct: 1,
+ tempHigh: 1550,
+ stateHigh: ["molten_metal_scrap","electric","molten_plastic"],
+ colorOn: "#ff0000",
+ movable: false,
+ insulate: true,
+ noMix: true,
+ category:"machines",
+ darkText: true,
+ hardness: 1,
};
elements.cpu = {
- color: "#575757",
- behavior: behaviors.SOLID,
- category: "machines",
- state: "solid",
- insulate: true,
- movable: false,
- noMix: true,
- density: 75,
- tempHigh: 1414,
- stateHigh: ["explosion","metal_scrap"],
+ color: "#575757",
+ behavior: behaviors.SOLID,
+ category: "machines",
+ state: "solid",
+ insulate: true,
+ movable: false,
+ noMix: true,
+ density: 75,
+ tempHigh: 1414,
+ stateHigh: ["explosion","metal_scrap"],
reactions: {
- "virus": { elem1 : null , elem2:"malware", chance:0.9 },
- "metal_scrap": { elem2:"computer" },
-
- }
+ "virus": { elem1 : null , elem2:"malware", chance:0.9 },
+ "metal_scrap": { elem2:"computer" },
+
+ }
};
elements.computer = {
- color: "#2b2b2a",
- behavior: behaviors.SOLID,
- category: "machines",
- state: "solid",
- density: 8908,
- insulate: true,
- noMix: true,
- movable: false,
- tempHigh: 1414,
- stateHigh: ["explosion","metal_scrap"],
+ color: "#2b2b2a",
+ behavior: behaviors.SOLID,
+ category: "machines",
+ state: "solid",
+ density: 8908,
+ insulate: true,
+ noMix: true,
+ movable: false,
+ tempHigh: 1414,
+ stateHigh: ["explosion","metal_scrap"],
reactions: {
- "virus": { elem1 : null , elem2:"malware", chance:0.9 },
- "water": { elem1: null , elem2: "electric" },
- }
+ "virus": { elem1 : null , elem2:"malware", chance:0.9 },
+ "water": { elem1: null , elem2: "electric" },
+ }
}
elements.electrons = {
- color: "#b80606",
- behavior: [
- "XX|SH|XX", // shocks (adds charge)
- "SH|DL%0.25|SH",
- "XX|SH|XX",
- ],
- tick: behaviors.BOUNCY,
- reactions: {},
- temp: 20,
- category: "energy",
- state: "gas",
- density: 0.000003,
- ignoreAir: true,
+color: "#b80606",
+behavior: [
+ "XX|SH|XX", // shocks (adds charge)
+ "SH|DL%0.25|SH",
+ "XX|SH|XX",
+],
+tick: behaviors.BOUNCY,
+temp: 20,
+category: "energy",
+state: "gas",
+density: 0.000003,
+ignoreAir: true,
};
elements.gelatin = {
- behavior: behaviors.SOLID,
- category: "food",
- state: "solid",
- color: "#faf8ca",
- breakInto: "gelatin_powder",
- ignoreAir: true,
- isFood: true,
+ behavior: behaviors.SOLID,
+ category: "food",
+ state: "solid",
+ color: "#faf8ca",
+ breakInto: "gelatin_powder",
+ ignoreAir: true,
+ isFood: true,
};
elements.gelatin_powder = {
- behavior: behaviors.POWDER,
- category: "food",
- state: "powder",
- color: "#edeb9f",
- hidden: true,
- ignoreAir: true,
- isFood: true,
+ behavior: behaviors.POWDER,
+ category: "food",
+ state: "powder",
+ color: "#edeb9f",
+ hidden: true,
+ ignoreAir: true,
+ isFood: true,
};
elements.blueberries = {
- behavior: behaviors.POWDER,
- category: "food",
- state: "solid",
- color: ["#464196","#2e2b64"],
- breakInto: "blueberries_juice",
- ignoreAir: true,
- isFood: true,
- reactions: {
- "sugar": { elem1: "blueberries_jam" },
- },
+behavior: behaviors.POWDER,
+category: "food",
+state: "solid",
+color: ["#464196","#2e2b64"],
+breakInto: "blueberries_juice",
+ignoreAir: true,
+isFood: true,
+reactions: {
+"sugar": { elem1: "blueberries_jam" },
+},
};
elements.blueberries_juice = {
- behavior: behaviors.LIQUID,
- category: "food",
- state: "liquid",
- color: "#1f1c42",
- hidden: true,
- tempHigh: 170,
- stateHigh: ["steam","sugar"],
- reactions: {
- ignoreAir: true,
- isFood: true,
- "gelatin": { elem1: "blueberries_jelly", elem2: null },
- "gelatin_powder": { elem1: "blueberries_jelly", elem2: null },
- },
+behavior: behaviors.LIQUID,
+category: "food",
+state: "liquid",
+color: "#1f1c42",
+hidden: true,
+tempHigh: 170,
+stateHigh: ["steam","sugar"],
+reactions: {
+ignoreAir: true,
+isFood: true,
+"gelatin": { elem1: "blueberries_jelly", elem2: null },
+"gelatin_powder": { elem1: "blueberries_jelly", elem2: null },
+},
};
elements.blueberries_jam = {
- behavior: behaviors.LIQUID,
- category: "food",
- viscosity: 5000,
- state: "liquid",
- tempHigh: 200,
- stateHigh: ["smoke","sugar"],
- color: "#080629",
- hidden: true,
- ignoreAir: true,
- isFood: true,
+behavior: behaviors.LIQUID,
+category: "food",
+viscosity: 5000,
+state: "liquid",
+tempHigh: 200,
+stateHigh: ["smoke","sugar"],
+color: "#080629",
+hidden: true,
+ignoreAir: true,
+isFood: true,
};
elements.blueberries_jelly = {
- behavior: behaviors.LIQUID,
- category: "food",
- viscosity: 200000,
- state: "liquid",
- color: "#59559e",
- hidden: true,
- tempHigh: 200,
- stateHigh: ["smoke","sugar"],
- tempLow: -5,
- stateLow: ["sugar_ice","sugar_ice","juice_ice"],
- ignoreAir: true,
- isFood: true,
+behavior: behaviors.LIQUID,
+category: "food",
+viscosity: 200000,
+state: "liquid",
+color: "#59559e",
+hidden: true,
+tempHigh: 200,
+stateHigh: ["smoke","sugar"],
+tempLow: -5,
+stateLow: ["sugar_ice","sugar_ice","juice_ice"],
+ignoreAir: true,
+isFood: true,
};
elements.fallout_drum = {
- behavior: behaviors.WALL,
- category: "radiated",
- state: "solid",
- density: 9000,
- color: "#e3cc34",
- tempHigh: 2500,
- stateHigh: ["aluminum","radiated_water","radiated_water","fallout"],
- breakInto: ["fallout","fallout"],
- reactions: {
- "water": { elem1:"fallout_drum", elem2:"radiated_water" },
- }
+behavior: behaviors.WALL,
+category: "radiated",
+state: "solid",
+density: 9000,
+color: "#e3cc34",
+tempHigh: 2500,
+stateHigh: ["aluminum","radiated_water","radiated_water","fallout"],
+breakInto: ["fallout","fallout"],
+reactions: {
+"water": { elem1:"fallout_drum", elem2:"radiated_water" },
+}
};
elements.radiated_water = {
- behavior: behaviors.LIQUID,
- category: "radiated",
- state:"liquid",
- density :1300,
- color: ["#23d959","#29d65d"],
- hidden: true,
- tempHigh: 140,
- stateHigh: "polluted_air",
- tempLow: -6,
- stateLow: "rad_ice",
- reactions: {
- "human": { elem2:"rotten_meat" },
- "body": { elem2:"rotten_meat" },
- "head": { elem2:"ash" },
- "bird": { elem2:"rotten_meat"},
- "cell": { elem2:"cancer"},
- }
+behavior: behaviors.LIQUID,
+category: "radiated",
+state:"liquid",
+density :1300,
+color: ["#23d959","#29d65d"],
+hidden: true,
+tempHigh: 140,
+stateHigh: "polluted_air",
+tempLow: -6,
+stateLow: "rad_ice",
+reactions: {
+"human": { elem2:"rotten_meat" },
+"body": { elem2:"rotten_meat" },
+"head": { elem2:"ash" },
+"bird": { elem2:"rotten_meat"},
+"cell": { elem2:"cancer"},
+"worm": { elem2:"rotten_meat"},
+}
};
elements.polluted_air = {
- behavior: behaviors.GAS,
- category: "radiated",
- state:"gas",
- density :10,
- color: ["#60f53b","#65ba50"],
- reactions: {
- "body": { elem2:"rotten_meat" },
- "head": { elem2:"rotten_meat" },
- "human": { elem2:"rotten_meat" },
- "bird": { elem2:"rotten_meat" },
- "cell": { elem2:"cancer" },
- "water": { elem1: null, elem2: "radiated_water" },
- "worm": { elem2: ["ash","cancer"] },
- "flea": { elem2: "ash" },
- "seed": {elem2: "dead_plant" },
- "plant": {elem1: null, chance:0.5, elem2: "dead_plant", chance:0.5 },
- },
+behavior: behaviors.DGAS,
+category: "radiated",
+state:"gas",
+density :10,
+color: ["#60f53b","#65ba50"],
+reactions: {
+ "body": { elem2:"rotten_meat" },
+ "head": { elem2:"rotten_meat" },
+ "human": { elem2:"rotten_meat" },
+ "bird": { elem2:"rotten_meat" },
+ "cell": { elem2:"cancer" },
+ "water": { elem1: null, elem2: "radiated_water" },
+ "worm": { elem2: ["ash","cancer"] },
+ "flea": { elem2: "ash" },
+ "seed": {elem2: "dead_plant" },
+ "plant": {elem1: null, chance:0.5, elem2: "dead_plant", chance:0.5 },
+},
};
elements.siren = {
- desc: "Detecting Nuclear Radiation Residues",
- behavior: behaviors.WALL,
- category: "machines",
- state:"solid",
- density :500,
- color: "#808080",
- reactions: {
- "fallout": {"charge1":1},
- "radiated_water": {"charge1":1},
- "polluted_air": {"charge1":1},
- }
+desc: "Detecting Nuclear Radiation Residues",
+behavior: behaviors.WALL,
+category: "machines",
+state:"solid",
+density :500,
+color: "#808080",
+reactions: {
+ "fallout": {"charge1":1},
+ "radiated_water": {"charge1":1},
+ "polluted_air": {"charge1":1},
+ "radiation": {"charge1":1},
+ "rad_snow": {"charge1":1},
+ "rad_rock": {"charge1":1},
+}
};
elements.radiated_metal = {
- behavior: behaviors.WALL,
- category: "radiated",
- state:"solid",
- density :2045,
- color: ["#5e705a","#83ab7b","#474747"],
- tempHigh: 1440,
- stateHigh: ["molten_nickel","molten_iron","molten_tin","fallout"],
- reactions: {
- "water": { elem2:"radiated_water", chance:0.7 },
- "foam": { elem1:["tin","nickel","iron"] },
- }
+behavior: behaviors.WALL,
+category: "radiated",
+state:"solid",
+density :2045,
+color: ["#5e705a","#83ab7b","#474747"],
+tempHigh: 1440,
+stateHigh: ["molten_nickel","molten_iron","molten_tin","fallout"],
+reactions: {
+ "water": { elem2:"radiated_water", chance:0.7 },
+ "foam": { elem1:["tin","nickel","iron"] },
+}
};
elements.rad_ice = {
- behavior: behaviors.WALL,
- category: "radiated",
- state:"solid",
- density: 1905,
- color: ["#81d79c","#68b899","#68abb8"],
- hidden: true,
- temp: -6,
- tempHigh: 5,
- stateHigh: ["radiated_water","water"],
- reactions: {
- "snow": { elem2:"dirty_water" },
- "water": { elem2:"radiated_water" },
- }
+behavior: behaviors.WALL,
+category: "radiated",
+state:"solid",
+density: 1905,
+color: ["#81d79c","#68b899","#68abb8"],
+hidden: true,
+temp: -6,
+tempHigh: 5,
+stateHigh: ["radiated_water","water"],
+reactions: {
+ "snow": { elem2:"dirty_water" },
+ "water": { elem2:"radiated_water" },
+}
}
elements.rad_snow = {
- behavior: behaviors.POWDER,
- category: "radiated",
- state:"powder",
- density: 1500,
- color: ["#9effe4","#b5fffd","#d4fff1"],
- temp: -2,
- tempHigh: 21,
- stateHigh: "radiated_water",
+behavior: behaviors.POWDER,
+category: "radiated",
+state:"powder",
+density: 1500,
+color: ["#9effe4","#b5fffd","#d4fff1"],
+temp: -2,
+tempHigh: 21,
+stateHigh: "radiated_water",
};
elements.rad_rock = {
- behavior: behaviors.POWDER,
- category: "land",
- state: "powder",
- density: 2790,
- color: ["#34382d","#3f4633","#595a4d"],
- tempHigh: 1200,
- stateHigh: ["magma","fallout"],
- reactions: {
- "water": { elem2:"dirty_water" },
- "salt_water": { elem2:"dirty_water" },
- "sugar_water": { elem2:"dirty_water" },
- "seltzer": { elem2:"dirty_water" },
- "bleach": {elem2: "rock", chance:0.1 },
- "rad_cleaner": { elem1:"rock" },
- "foam": { elem1:"rock" },
- "juice": { elem2: null },
- "blood": { elem2:"infection" },
- "grass": { elem2:"dead_plant" },
- "plant": { elem2:"dead_plant" },
- "cell": { elem2:"cancer" },
- "worm": { elem2:"ash" },
- "glass": { elem2:"rad_glass"},
- "glass_shard": { elem2:"rad_shard" },
- }
+behavior: behaviors.POWDER,
+category: "land",
+state: "powder",
+density: 2790,
+color: ["#34382d","#3f4633","#595a4d"],
+tempHigh: 1200,
+stateHigh: ["magma","fallout"],
+reactions: {
+ "water": { elem2:"dirty_water" },
+ "salt_water": { elem2:"dirty_water" },
+ "sugar_water": { elem2:"dirty_water" },
+ "seltzer": { elem2:"dirty_water" },
+ "bleach": {elem2: "rock", chance:0.1 },
+ "rad_cleaner": { elem1:"rock" },
+ "foam": { elem1:"rock" },
+ "juice": { elem2: null },
+ "blood": { elem2:"infection" },
+ "grass": { elem2:"dead_plant" },
+ "plant": { elem2:"dead_plant" },
+ "cell": { elem2:"cancer" },
+ "worm": { elem2:"ash" },
+ "glass": { elem2:"rad_glass"},
+ "glass_shard": { elem2:"rad_shard" },
+}
};
elements.rad_cleaner = {
- behavior: behaviors.WALL,
- category: "machines",
- state: "solid",
- density: 2500,
- color: ["#383838","#212220"],
- desc: "clean radiated elements",
- tempHigh: 1250,
- stateHigh: ["fallout","molten_plastic","steam"],
- reactions: {
- "radiated_water": {elem2:"water" },
- "polluted_air": {elem2: "oxygen"},
- "rad_snow": {elem2: "snow"},
- "rad_rock": {elem2: "rock"},
- }
- };
+behavior: behaviors.WALL,
+category: "machines",
+state: "solid",
+density: 2500,
+color: ["#383838","#212220"],
+desc: "clean radiated elements",
+tempHigh: 1250,
+stateHigh: ["fallout","molten_plastic","steam"],
+reactions: {
+ "radiated_water": {elem2:"water" },
+ "polluted_air": {elem2: "oxygen"},
+ "rad_snow": {elem2: "snow"},
+ "rad_rock": {elem2: "rock"},
+ "radiated_metal": {elem2: ["nickel","tin","iron"], },
+ "fallout": {elem2: "rock", },
+}
+};
elements.rad_meat = {
- behavior: behaviors.STURDYPOWDER,
- category: "food",
- state: "solid",
- density: 1500,
- color: ["#e8fc03","#f0b446","#92f046"],
- tempHigh: 120,
- stateHigh: ["rotten_meat","fallout"],
- tempLow:-12,
- stateLow: ["frozen_meat","radiation"],
- reactions: {
- "water": {elem2: "radiated_water", chance:0.4},
- "salt_water": { elem2: "radiated_water" },
- }
+behavior: behaviors.STURDYPOWDER,
+category: "food",
+state: "solid",
+density: 1500,
+color: ["#e8fc03","#f0b446","#92f046"],
+tempHigh: 120,
+stateHigh: ["rotten_meat","fallout"],
+tempLow:-12,
+stateLow: ["frozen_meat","radiation"],
+reactions: {
+ "water": {elem2: "radiated_water", chance:0.4},
+ "salt_water": { elem2: "radiated_water" },
+}
};
elements.lemon = {
- behavior: behaviors.POWDER,
- category: "food",
- state: "powder",
- density: 800,
- color: ["#f9f934", "#f1ee20",],
- tempHigh: 90,
- stateHigh: "hot_lemon",
- tempLow: -2,
- stateLow: "wrinkled_lemon",
- burn: 120,
- burntime: 600,
- burnInto: "ash",
- breakInto: [ "lemon_water", "lemon_zest", ],
- reactions: {
- "water": { elem2: "lemon_water", chance:0.2},
- "salt_water": { elem2: [ "lemon_water", "water",] },
- "dirty_water": { elem1: "rotten_lemon", },
- "soda": { elem2: "lemon_soda", },
- "head": { elem1: "saliva", chance:0.75},
- "milk": { elem2: "lemon_milk", },
- "tea": { elem2: "lemon_tea", },
- "poison": { elem2: "rotten_lemon", },
- }
+behavior: behaviors.POWDER,
+category: "food",
+state: "powder",
+density: 800,
+color: ["#f9f934", "#f1ee20",],
+tempHigh: 90,
+stateHigh: "hot_lemon",
+tempLow: -2,
+stateLow: "wrinkled_lemon",
+burn: 120,
+burntime: 600,
+burnInto: "ash",
+breakInto: [ "lemon_water", "lemon_zest", ],
+reactions: {
+ "water": { elem2: "lemon_water", chance:0.2},
+ "salt_water": { elem2: [ "lemon_water", "water",] },
+ "dirty_water": { elem1: "rotten_lemon", },
+ "soda": { elem2: "lemon_soda", },
+ "head": { elem1: "saliva", chance:0.75},
+ "milk": { elem2: "lemon_milk", },
+ "tea": { elem2: "lemon_tea", },
+ "poison": { elem2: "rotten_lemon", },
+}
};
elements.hot_lemon = {
- behavior: behaviors.POWDER,
- state: "powder",
- category: "food",
- hidden: true,
- density: 820,
- color: ["#8a6d1e","#70661a",],
- hidden: true,
- temp: 90,
- tempHigh: 200,
- stateHigh: "fire",
- tempLow: 30,
- stateLow: "wrinkled_lemon",
- burn: 120,
- burntime: 600,
- burnInto: "ash",
- reactions: {
- "water": { elem2: "lemon_water", },
- }
+behavior: behaviors.POWDER,
+state: "powder",
+category: "food",
+hidden: true,
+density: 820,
+color: ["#8a6d1e","#70661a",],
+hidden: true,
+temp: 90,
+tempHigh: 200,
+stateHigh: "fire",
+tempLow: 30,
+stateLow: "wrinkled_lemon",
+burn: 120,
+burntime: 600,
+burnInto: "ash",
+reactions: {
+ "water": { elem2: "lemon_water", },
+}
};
elements.leather = {
- behavior: behaviors.SUPPORTPOWDER,
- color: ["#3f261d","#664f40",],
- state: "powder",
- category: "powders",
- tempHigh: 200,
- stateHigh: "fire",
- breakInto: "dust",
- burn: 20,
- burntime: 200,
- burnInto: "ash",
+behavior: behaviors.SUPPORTPOWDER,
+color: ["#3f261d","#664f40",],
+state: "powder",
+category: "powders",
+tempHigh: 200,
+stateHigh: "fire",
+breakInto: "dust",
+burn: 20,
+burntime: 200,
+burnInto: "ash",
};
elements.wrinkled_lemon = {
- behavior: behaviors.POWDER,
- color: ["#999543","#a6a03a",],
- state: "powder",
- category: "food",
- tempHigh: 90,
- stateHigh: "hot_lemon",
- hidden: true,
- burn: 120,
- burntime: 600,
- burnInto: "ash",
- reactions: {
- "water": { elem2: "lemon_water", chance: 0.2,
- }
- }
+behavior: behaviors.POWDER,
+color: ["#999543","#a6a03a",],
+state: "powder",
+category: "food",
+tempHigh: 90,
+stateHigh: "hot_lemon",
+hidden: true,
+burn: 120,
+burntime: 600,
+burnInto: "ash",
+reactions: {
+"water": { elem2: "lemon_water", chance: 0.2,
+}
+}
};
elements.coolant = {
- color: "#0eebeb",
- behavior: [
- "XX|CO:4|XX",
- "CO:4|HT:1|CO:4",
- "XX|CO:4|XX",
- ],
- category: "liquids",
- state: "liquid",
- insulate: true,
- density: 1000,
- darkText: false,
- tempHigh: 500,
- hidden: true,
- stateHigh: "steam",
+color: "#0eebeb",
+behavior: [
+ "XX|CO:4|XX",
+ "CO:4|HT:1|CO:4",
+ "XX|CO:4|XX",
+],
+category: "liquids",
+state: "liquid",
+insulate: true,
+density: 1000,
+darkText: false,
+tempHigh: 500,
+hidden: true,
+stateHigh: "steam",
};
elements.arkycite = {
- color: "#46ab63",
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 997,
- darkText: false,
- tempHigh: 400,
- hidden: true,
- burn: 40,
- stateHigh: "fire",
- burntime: 500,
+color: "#46ab63",
+behavior: behaviors.LIQUID,
+category: "liquids",
+state: "liquid",
+density: 997,
+darkText: false,
+tempHigh: 400,
+hidden: true,
+burn: 40,
+stateHigh: "fire",
+burntime: 500,
};
elements.lemon_water = {
- color: ["#faec52","#faee69",],
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 900,
- tempHigh: 100,
- stateHigh: ["steam","fragrance",],
- hidden: true,
- tempLow: -10,
- stateLow: "lemon_ice",
- reactions: {
- "balloon": { elem2: "helium", chance: 0.5, },
- "head": { elem1: "saliva", chance: 0.2, },
- }
+color: ["#faec52","#faee69",],
+behavior: behaviors.LIQUID,
+category: "liquids",
+state: "liquid",
+density: 900,
+tempHigh: 100,
+stateHigh: ["steam","fragrance",],
+hidden: true,
+tempLow: -10,
+stateLow: "lemon_ice",
+reactions: {
+"balloon": { elem2: "helium", chance: 0.5, },
+"head": { elem1: "saliva", chance: 0.2, },
+}
};
elements.lemon_zest = {
- color: ["#ded254","#ccc03d",],
- behavior: behaviors.POWDER,
- category: "trashes",
- state: "powder",
- density: 1000,
- hidden: true,
- tempHigh: 350,
- stateHigh: "fire",
- breakInto: "lemon_water",
- burn: 60,
- burntime: 200,
- burnInto: "smoke"
+color: ["#ded254","#ccc03d",],
+behavior: behaviors.POWDER,
+category: "trashes",
+state: "powder",
+density: 1000,
+hidden: true,
+tempHigh: 350,
+stateHigh: "fire",
+breakInto: "lemon_water",
+burn: 60,
+burntime: 200,
+burnInto: "smoke"
};
elements.saliva = {
- color: ["#a6f5f0","#b6f0ec",],
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 1280,
- tempHigh: 105,
- stateHigh: ["steam","fragrance"],
- tempLow: -5,
- stateHigh: "saliva_ice",
- reactions: {
- "water": { elem1: null, chance: 0.5, elem2: "dirty_water", chance: 0.5,
- }
- }
+color: ["#a6f5f0","#b6f0ec",],
+behavior: behaviors.LIQUID,
+category: "liquids",
+state: "liquid",
+density: 1280,
+tempHigh: 105,
+stateHigh: ["steam","fragrance"],
+tempLow: -5,
+stateHigh: "saliva_ice",
+reactions: {
+"water": { elem1: null, chance: 0.5, elem2: "dirty_water", chance: 0.5,
+}
+}
};
elements.lemon_milk = {
- color: ["#f5f2c4","#f7f4b2",],
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 1002,
- tempHigh: 500,
- stateHigh: "smoke",
- tempLow: -2,
- stateLow: "frozen_yogurt",
- stateLowColor: ["#f5f3cb","#f7f5bc"],
- reactions: {
- "bacteria": { elem1: "yogurt", },
- }
+color: ["#f5f2c4","#f7f4b2",],
+behavior: behaviors.LIQUID,
+category: "liquids",
+state: "liquid",
+density: 1002,
+tempHigh: 500,
+stateHigh: "smoke",
+tempLow: -2,
+stateLow: "frozen_yogurt",
+stateLowColor: ["#f5f3cb","#f7f5bc"],
+reactions: {
+"bacteria": { elem1: "yogurt", },
+}
};
elements.lemon_soda = {
- color: ["#f5c842","#edcc68",],
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 1240,
- tempHigh: 140,
- stateHigh: ["carbon_dioxide", "smoke",],
- reactions: {
- "poison": { elem1: null, }
- }
+color: ["#f5c842","#edcc68",],
+behavior: behaviors.LIQUID,
+category: "liquids",
+state: "liquid",
+density: 1240,
+tempHigh: 140,
+stateHigh: ["carbon_dioxide", "smoke",],
+reactions: {
+"poison": { elem1: null, }
+}
};
elements.saliva_ice = {
- color: ["#97fcfb","#bcf7f6",],
- behavior: behaviors.SOLID,
- category: "states",
- state: "solid",
- density: 1300,
- tempHigh: 5,
- stateHigh: "saliva",
+color: ["#97fcfb","#bcf7f6",],
+behavior: behaviors.SOLID,
+category: "states",
+state: "solid",
+density: 1300,
+tempHigh: 5,
+stateHigh: "saliva",
};
elements.lemon_tea = {
- color: ["#dec85b","#edd351",],
- behavior: behaviors.LIQUID,
- category: "liquids",
- state: "liquid",
- density: 1580,
- tempHigh: 280,
- stateHigh: ["fragrance","smoke","smoke",],
- tempLow: -2,
- stateLowColor: ["#e8cf8b","#f0dca5",],
- stateLow: "tea_ice",
- reactions: {
- "sugar": { elem2: null, },
- }
+color: ["#dec85b","#edd351",],
+behavior: behaviors.LIQUID,
+category: "liquids",
+state: "liquid",
+density: 1580,
+tempHigh: 280,
+stateHigh: ["fragrance","smoke","smoke",],
+tempLow: -2,
+stateLowColor: ["#e8cf8b","#f0dca5",],
+stateLow: "tea_ice",
+reactions: {
+"sugar": { elem2: null, },
+}
};
elements.rotten_lemon = {
- color: ["#e3f283","#cdcf6b"],
- behavior: behaviors.POWDER,
- category: "food",
- state: "powder",
- density: 1890,
- tempHigh: 200,
- stateHigh: ["stench","ash",],
- reactions: {
- "water": { elem2: "dirty_water" },
- }
+color: ["#e3f283","#cdcf6b"],
+behavior: behaviors.POWDER,
+category: "food",
+state: "powder",
+density: 1890,
+tempHigh: 200,
+stateHigh: ["stench","ash",],
+reactions: {
+"water": { elem2: "dirty_water" },
}
+};
+
+elements.cow = {
+ color: ["#d9d9d9","#616161",],
+ behavior: [
+ "XX|XX|XX",
+ "XX|FX%5.0|M2%5.0 AND BO",
+ "XX|M1|XX",],
+ category: "life",
+ state: "powder",
+ density: 2800,
+ tempHigh: 250,
+ stateHigh: "cooked_meat",
+ tempLow: -10,
+ stateLow: "frozen_meat",
+ reactions: {
+ "water": { elem2: null, chance: 0.2,},
+ "milk": { elem2: null, chance: 0.1, },
+ "alcohol": { elem2: null, chance: 0.21, },
+ "poison": { elem1: "rotten_meat", elem2: null, },
+ "grass": { elem2: null, },
+ "plague": { elem1: "rotten_meat", chance: 0.3, },
+ "worm": { elem2: null, },
+ "flea": { elem2: null, },
+ }
+};
+
+elements.hazmat_head = {
+ color: ["#404040","#1a1a1a","#737373"],
+ category: "life",
+ hidden: true,
+ density: 1080,
+ state: "solid",
+ conduct: .05,
+ temp: 40,
+ tempHigh: 3500,
+ stateHigh: ["ash","iron",],
+ tempLow: -180,
+ stateLow: "frozen_meat",
+ breakInto: ["blood","meat","bone","metal_scrap"],
+ forceSaveColor: true,
+ reactions: {
+ "oxygen": { elem2:"carbon_dioxide", chance:0.5 },
+ "meat": { elem2:null, chance:0.1 },
+ "cooked_meat": { elem2:null, chance:0.1 },
+ "cured_meat": { elem2:null, chance:0.1 },
+ "sugar": { elem2:null, chance:0.1 },
+ "broth": { elem2:null, chance:0.2 },
+ "yolk": { elem2:null, chance:0.1 },
+ "hard_yolk": { elem2:null, chance:0.1 },
+ "dough": { elem2:null, chance:0.1 },
+ "batter": { elem2:null, chance:0.2 },
+ "butter": { elem2:null, chance:0.1 },
+ "melted_butter": { elem2:null, chance:0.2 },
+ "chocolate": { elem2:null, chance:0.2 },
+ "melted_chocolate": { elem2:null, chance:0.3 },
+ "grape": { elem2:null, chance:0.1 },
+ "tomato": { elem2:null, chance:0.1 },
+ "herb": { elem2:null, chance:0.1 },
+ "lettuce": { elem2:null, chance:0.1 },
+ "corn": { elem2:null, chance:0.1 },
+ "popcorn": { elem2:null, chance:0.15 },
+ "potato": { elem2:null, chance:0.1 },
+ "baked_potato": { elem2:null, chance:0.15 },
+ "bread": { elem2:null, chance:0.1 },
+ "toast": { elem2:null, chance:0.1 },
+ "gingerbread": { elem2:null, chance:0.1 },
+ "baked_batter": { elem2:null, chance:0.2 },
+ "wheat": { elem2:null, chance:0.1 },
+ "candy": { elem2:null, chance:0.1 },
+ "yogurt": { elem2:null, chance:0.2 },
+ "frozen_yogurt": { elem2:null, chance:0.1 },
+ "ice_cream": { elem2:null, chance:0.2 },
+ "beans": { elem2:[null,null,null,null,null,null,null,null,"stench"], chance:0.2 },
+ "tea": { elem2:null, chance:0.2 },
+ "coffee": { elem2:null, chance:0.2 },
+ "milk": { elem2:null, chance:0.2 },
+ "cream": { elem2:null, chance:0.2 },
+ "soda": { elem2:null, chance:0.2 },
+ "chocolate_milk": { elem2:null, chance:0.2 },
+ "fruit_milk": { elem2:null, chance:0.2 },
+ "pilk": { elem2:null, chance:0.2 },
+ "eggnog": { elem2:null, chance:0.2 },
+ "juice": { elem2:null, chance:0.2 },
+ "cheese": { elem2:null, chance:0.1 },
+ "melted_cheese": { elem2:null, chance:0.2 },
+ "alcohol": { elem2:null, chance:0.2 },
+ "antidote": { elem2:null, chance:0.2 },
+ "honey": { elem2:null, chance:0.2 },
+ "caramel": { elem2:null, chance:0.2 },
+ "molasses": { elem2:null, chance:0.05 },
+ "ketchup": { elem2:null, chance:0.1 },
+ "pumpkin_seed": { elem2:null, chance:0.1 },
+ "nut": { elem2:null, chance:0.1 },
+ "nut_meat": { elem2:null, chance:0.1 },
+ "nut_butter": { elem2:null, chance:0.1 },
+ "nut_milk": { elem2:null, chance:0.2 },
+ "jelly": { elem2:null, chance:0.2 },
+ "mayo": { elem2:null, chance:0.2 },
+ "mashed_potato": { elem2:null, chance:0.2 },
+ "sauce": { elem2:null, chance:0.2 },
+ "pickle": { elem2:null, chance:0.1 },
+ "light": { stain1:"#fff154" },
+ },
+ properties: {
+ dead: false
+ },
+ tick: function(pixel) {
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.dead) {
+ // Turn into rotten_meat if pixelTicks-dead > 500
+ if (pixelTicks-pixel.dead > 200 && Math.random() < 0.1) {
+ changePixel(pixel,"rotten_meat");
+ return
+ }
+ }
+
+ // Find the body
+ if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "hazmat_body") {
+ var body = pixelMap[pixel.x][pixel.y+1];
+ if (body.dead) { // If body is dead, kill head
+ pixel.dead = body.dead;
+ }
+ }
+ else { var body = null }
+
+ if (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("blood", pixel.x, pixel.y+1);
+ // set dead to true 15% chance
+ if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ }
+ }
+ }
+ // homeostasis
+ if (pixel.temp > 40) { pixel.temp -= 1; }
+ else if (pixel.temp < 40) { pixel.temp += 1; }
+ }
+};
+
+elements.hazmat_body = {
+ color: ["#ffdf4f","#e8c00e","#ffd412"],
+ category: "life",
+ hidden: true,
+ density: 1570,
+ state: "solid",
+ conduct: .25,
+ temp: 39,
+ tempHigh: 3500,
+ stateHigh: ["metal_scrap","ash"],
+ tempLow: -180,
+ stateLow: "frozen_meat",
+ breakInto: ["blood","meat","bone","metal_scrap","radiation","fallout",],
+ forceSaveColor: true,
+ reactions: {
+ "egg": { elem2:"yolk", chance:0.5, oneway:true },
+ "grape": { elem2:"juice", chance:0.5, color2:"#291824", oneway:true },
+ "ant": { elem2:"dead_bug", chance:0.05, oneway:true },
+ "fly": { elem2:"dead_bug", oneway:true },
+ "firefly": { elem2:"dead_bug", oneway:true },
+ "bee": { elem2:"dead_bug", oneway:true },
+ "flea": { elem2:"dead_bug", oneway:true },
+ "termite": { elem2:"dead_bug", oneway:true },
+ "worm": { elem2:"slime", chance:0.05, oneway:true },
+ "stink_bug": { elem2:"stench", oneway:true },
+ "grass_seed": { elem2:null, chance:0.05 },
+ "gold_coin": { elem2:null, chance:0.05 },
+ "diamond": { elem2:null, chance:0.05 },
+ },
+ properties: {
+ dead: false,
+ dir: 1,
+ panic: 0
+ },
+ tick: function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
+ if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
+ var headpixel = pixelMap[pixel.x][pixel.y-2];
+ if (headpixel.element == "hazmat_head") {
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
+ }
+ else {
+ swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
+ }
+ }
+ }
+ }
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.dead) {
+ // Turn into rotten_meat if pixelTicks-dead > 500
+ if (pixelTicks-pixel.dead > 200 && Math.random() < 0.1) {
+ changePixel(pixel,"rotten_meat");
+ }
+ return
+ }
+
+ // Find the head
+ if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "hazmat_head") {
+ var head = pixelMap[pixel.x][pixel.y-1];
+ if (head.dead) { // If head is dead, kill body
+ pixel.dead = head.dead;
+ }
+ }
+ else { var head = null }
+ if (pixel.burning) {
+ pixel.panic += 0.1;
+ if (head && pixelTicks-pixel.burnStart > 240) {
+ pixel.color = head.color;
+ }
+ }
+ else if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ }
+
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ // create blood if decapitated 10% chance
+ if (Math.random() < 0.1 && !pixel.charge) {
+ createPixel("blood", pixel.x, pixel.y-1);
+ // set dead to true 15% chance
+ if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ }
+ }
+ }
+ else if (head == null) { return }
+ else if (Math.random() < 0.1*(isEmpty(pixel.x, pixel.y+1) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,0],
+ [1*pixel.dir,-1],
+ ];
+ // While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
+ while (movesToTry.length > 0) {
+ var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
+ if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
+ 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(head, head.x+move[0], head.y+move[1]);
+ break;
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.15) {
+ pixel.dir *= -1;
+ }
+ // homeostasis
+ if (pixel.temp > 39) { pixel.temp -= 1; }
+ else if (pixel.temp < 39) { pixel.temp += 1; }
+ }
+
+ }
+};
+
+elements.hazmat_human = {
+ // color: ["#404040","#1a1a1a","#737373"],
+ color: ["#404040","#1a1a1a","#737373"],
+ category: "life",
+ properties: {
+ dead: false,
+ dir: 1,
+ panic: 0
+ },
+ tick: function(pixel) {
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel("hazmat_body", pixel.x, pixel.y+1);
+ pixel.element = "hazmat_head";
+ }
+ else if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel("hazmat_head", pixel.x, pixel.y-1);
+ pixelMap[pixel.x][pixel.y-1].color = pixel.color;
+ pixel.element = "hazmat_body";
+ pixel.color = pixelColorPick(pixel)
+ }
+ else {
+ deletePixel(pixel.x, pixel.y);
+ }
+ },
+ related: ["hazmat_body","hazmat_head"],
+ cooldown: defaultCooldown,
+ forceSaveColor: true,
+};
+
+elements.zombie_head = {
+ color: ["#57f542","#43de2f","#46c435"],
+ category: "life",
+ hidden: true,
+ density: 1025,
+ state: "solid",
+ conduct: .07,
+ temp: 28,
+ tempHigh: 320,
+ stateHigh: ["ash","zombie_virus",],
+ tempLow: -45,
+ stateLow: ["frozen_meat","zombie_virus",],
+ breakInto: ["infection","rotten_meat","bone","zombie_virus",],
+ forceSaveColor: true,
+ reactions: {
+ "head": { elem2: ["rotten_meat","zombie",], chance:0.8, },
+ "body": { elem2: ["rotten_meat","zombie",], chance:0.5, },
+ "oxygen": { elem2:"carbon_dioxide", chance:0.5 },
+ "rotten_meat": { elem2: null, chance:0.5 },
+ "meat": { elem2:null, chance:0.1 },
+ "cooked_meat": { elem2:null, chance:0.1 },
+ "cured_meat": { elem2:null, chance:0.1 },
+ "light": { stain1:"#45eb2f" },
+ },
+ properties: {
+ dead: false
+ },
+ tick: function(pixel) {
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.dead) {
+ // Turn into rotten_meat if pixelTicks-dead > 500
+ if (pixelTicks-pixel.dead > 200 && Math.random() < 0.1) {
+ changePixel(pixel,"rotten_meat");
+ return
+ }
+ }
+
+ // Find the body
+ if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "zombie_body") {
+ var body = pixelMap[pixel.x][pixel.y+1];
+ if (body.dead) { // If body is dead, kill head
+ pixel.dead = body.dead;
+ }
+ }
+ else { var body = null }
+
+ 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("blood", pixel.x, pixel.y+1);
+ // set dead to true 15% chance
+ if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ }
+ }
+ }
+ // homeostasis
+ if (pixel.temp > 28) { pixel.temp -= 1; }
+ else if (pixel.temp < 28) { pixel.temp += 1; }
+ }
+};
+
+elements.zombie_body = {
+ color: ["#2d7ecf","#4d94db","#65a175",],
+ category: "life",
+ hidden: true,
+ density: 1520,
+ state: "solid",
+ conduct: .29,
+ temp: 29,
+ tempHigh: 350,
+ stateHigh: ["zombie_virus","ash"],
+ tempLow: -180,
+ stateLow: ["frozen_meat","zombie_virus",],
+ breakInto: ["infection","rotten_meat","bone","zombie_virus",],
+ forceSaveColor: true,
+ reactions: {
+ "head": { elem2: "zombie", },
+ "body": { elem2: "zombie", },
+ },
+
+ properties: {
+ dead: false,
+ dir: 1,
+ panic: 0
+ },
+ tick: function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
+ if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
+ var headpixel = pixelMap[pixel.x][pixel.y-2];
+ if (headpixel.element == "zombie_head") {
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
+ }
+ else {
+ swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
+ }
+ }
+ }
+ }
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.dead) {
+ // Turn into rotten_meat if pixelTicks-dead > 500
+ if (pixelTicks-pixel.dead > 200 && Math.random() < 0.1) {
+ changePixel(pixel,"rotten_meat");
+ }
+ return
+ }
+
+ // Find the head
+ if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "zombie_head") {
+ var head = pixelMap[pixel.x][pixel.y-1];
+ if (head.dead) { // If head is dead, kill body
+ pixel.dead = head.dead;
+ }
+ }
+ else { var head = null }
+ if (pixel.burning) {
+ pixel.panic += 0.1;
+ if (head && pixelTicks-pixel.burnStart > 240) {
+ pixel.color = head.color;
+ }
+ }
+ else if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ }
+
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ // create blood if decapitated 10% chance
+ if (Math.random() < 0.1 && !pixel.charge) {
+ createPixel("blood", pixel.x, pixel.y-1);
+ // set dead to true 15% chance
+ if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ }
+ }
+ }
+ else if (head == null) { return }
+ else if (Math.random() < 0.1*(isEmpty(pixel.x, pixel.y+1) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,0],
+ [1*pixel.dir,-1],
+ ];
+ // While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
+ while (movesToTry.length > 0) {
+ var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
+ if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
+ 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(head, head.x+move[0], head.y+move[1]);
+ break;
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.15) {
+ pixel.dir *= -1;
+ }
+ // homeostasis
+ if (pixel.temp > 29) { pixel.temp -= 1; }
+ else if (pixel.temp < 29) { pixel.temp += 1; }
+ }
+
+ }
+};
+
+elements.zombie = {
+ // color: ["#404040","#1a1a1a","#737373"],
+ color: ["#57f542","#43de2f","#46c435"],
+ category: "life",
+ properties: {
+ dead: false,
+ dir: 1,
+ panic: 0,
+ },
+ tick: function(pixel) {
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel("zombie_body", pixel.x, pixel.y+1);
+ pixel.element = "zombie_head";
+ }
+ else if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel("zombie_head", pixel.x, pixel.y-1);
+ pixelMap[pixel.x][pixel.y-1].color = pixel.color;
+ pixel.element = "zombie_body";
+ pixel.color = pixelColorPick(pixel)
+ }
+ else {
+ deletePixel(pixel.x, pixel.y);
+ }
+ },
+ related: ["zombie_body","zombie_head"],
+ cooldown: defaultCooldown,
+ forceSaveColor: true,
+};
+
+elements.zombie_virus = {
+ behavior: behaviors.DGAS,
+ color: ["#660266","#bd06bd","#f041f0",],
+ category: "special",
+ density: 30,
+ state: "gas",
+ reactions: {
+ "head": { elem2: ["zombie","rotten_meat",], chance: 0.2, },
+ "body": { elem2: ["zombie","rotten_meat",], chance: 0.2, },
+ }
+}
+
+elements.matter = {
+ behavior: behaviors.GAS,
+ color: ["#c4f8ff","#b0f6ff","#9ccfd6",],
+ darkText: true,
+ category: "energy",
+ density: 2.20,
+ state: "gas",
+ reactions: {
+ "antimatter": { elem1: "explosion", },
+ "positron": { elem1: "explosion", },
+ "electron": { elem1: "explosion", },
+ }
+};
+elements.particle_accelerator_left = {
+ behavior: behaviors.SOLID,
+ color: ["#363aa3","#858585","#d1d1d1"],
+ density: 2400,
+ category: "machines",
+ state: "solid",
+ reactions: {
+ "matter": { elem2: ["accelerated_matter_left",] },
+ }
+};
+elements.particle_accelerator_right = {
+ behavior: behaviors.SOLID,
+ color: ["#363aa3","#858585","#d1d1d1"],
+ density: 2400,
+ category: "machines",
+ state: "solid",
+ reactions: {
+ "matter": { elem2: ["accelerated_matter_right",] },
+ }
+};
+
+elements.accelerated_matter_left = {
+ color: ["#c0ecf0","#a8f8ff",],
+ behavior: [
+ "M2|XX|XX",
+ "M1 AND XX|XX|XX",
+ "M2|XX|XX",
+ ],
+ hidden: true,
+ state: "gas",
+ category: "energy",
+ density: 2.20,
+ reactions: {
+ "accelerated_matter_right": { elem1: ["antimatter","pop",], chance: 0.3, },
+ "accelerated_matter_left": { elem1: ["antimatter","pop",], chance: 0.3, },
+ "antimatter": { elem1: "pop", chance: 0.01, },
+ }
+
+};
+elements.accelerated_matter_right = {
+ color: ["#c0ecf0","#a8f8ff",],
+ behavior: [
+ "XX|XX|M2",
+ "XX|XX|M1 AND XX",
+ "XX|XX|M2",
+ ],
+ hidden: true,
+ state: "gas",
+ category:"energy",
+ density: 2.20,
+ reactions: {
+ "accelerated_matter_left": { elem1: ["antimatter","pop",], chance: 0.3, },
+ "accelerated_matter_right": { elem1: ["antimatter","pop",], chance: 0.3, },
+ "antimatter": { elem1: "pop", chance: 0.01, },
+
+ }
+
+};
diff --git a/mods/circuitcore.js b/mods/circuitcore.js
new file mode 100644
index 00000000..41903bd4
--- /dev/null
+++ b/mods/circuitcore.js
@@ -0,0 +1,1555 @@
+// CircuitCore: adds circuits to sandboxels, logicgates.js is required
+
+/*if (!enabledMods.includes("mods/betterSettings.js")) { enabledMods.unshift("mods/betterSettings.js"); localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); window.location.reload() };
+
+var cc_settingsTab = new SettingsTab("CircuitCore");
+var cc_setting1 = new Setting("Default Memory Fill; 0=empty,1=random,2=fill custom,3=custom data", "mem_fill", settingType.NUMBER, false, "The default method used to initialize ROM/RAM memory devices");
+var cc_setting2 = new Setting("Example Setting 2", "element", settingType.TEXT, false, "2");
+cc_settingsTab.registerSettings("Default Memory Fill", cc_setting1);
+cc_settingsTab.registerSettings("Setting 2", cc_setting2);
+settingsManager.registerTab(cc_settingsTab);*/
+
+var dataVisualizationPalette16 = [
+ "#000000", "#ff0000", "#ff7700", "#ffff00", "#00ff00", "#00ffff", "#0000ff", "#ff00ff",
+ "#777777", "#770000", "#773300", "#777700", "#007700", "#007777", "#000077", "#770077",
+];
+
+function binaryArrayToNumber(binaryArray) {
+ return binaryArray.reduce((acc, bit, index) => acc + bit * Math.pow(2, (binaryArray.length - 1) - index), 0);
+}
+
+function hexToPixelGrid(hex) {
+ var hexDigitStrings = [
+ "111101101101111", // 0
+ "001001001001001", // 1
+ "111001111100111", // 2
+ "111001111001111", // 3
+ "101101111001001", // 4
+ "111100111001111", // 5
+ "111100111101111", // 6
+ "111001001001001", // 7
+ "111101111101111", // 8
+ "111101111001111", // 9
+ "111101111101101", // A
+ "100100111101111", // B
+ "111100100100111", // C
+ "001001111101111", // D
+ "111100111100111", // E
+ "111100111100100" // F
+ ];
+
+ if (hex < 0 || hex > 15 || isNaN(hex)) {
+ console.log("inputted value: ", hex);
+ throw new Error("Input must be a valid 1-digit hexadecimal number.");
+ }
+
+ const binaryString = hexDigitStrings[hex];
+ const hexDigitArray = [];
+ for (let i = 0; i < 5; i++) {
+ hexDigitArray.push(binaryString.slice(i * 3, i * 3 + 3).split('').map(Number));
+ }
+ return hexDigitArray;
+}
+
+// Function to rotate a coordinate around the origin
+function rotateCoordinate(x, y, angle) {
+ var radians = angle * (Math.PI / 180);
+ var cos = Math.cos(radians);
+ var sin = Math.sin(radians);
+
+ var nx = Math.round(x * cos - y * sin);
+ var ny = Math.round(x * sin + y * cos);
+
+ return [nx, ny];
+}
+
+// Initialize the circuit with optional rotation
+function initializeCircuit(pixel, pins, w, h, center=true, rotation=circuitRotation, callback=()=>{}) {
+ if (pixel.hasGenerated) {return;}
+
+ if (!center) {rotation = 0;} // non-centered circuits don't support rotation yet
+ pixel.circuitRotation = rotation;
+
+ createCircuitFrame(pixel, w, h, center, rotation);
+ createPins(pixel, pins, rotation);
+ callback(pixel, pins, w, h);
+
+ pixel.hasGenerated = true;
+}
+
+function createCircuitFrame(pixel, width_, height_, center=true, rotation=0) {
+ var halfHeight = Math.floor(height_ / 2);
+ var halfWidth = Math.floor(width_ / 2);
+
+ var a = -halfHeight;
+ var b = halfHeight;
+ var c = -halfWidth;
+ var d = halfWidth;
+
+ if (!center) {
+ a = 0;
+ b = height_ - 1;
+ c = 0;
+ d = width_ - 1;
+ }
+
+ for (var y = a; y <= b; y++) {
+ for (var x = c; x <= d; x++) {
+ var [rx, ry] = rotateCoordinate(x, y, rotation);
+ var px = pixel.x + rx;
+ var py = pixel.y + ry;
+ if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
+
+ if (!pixelMap[px] || pixelMap[px][py] === undefined) {
+ createPixel("circuit_material", px, py);
+ }
+ }
+ }
+}
+
+function createPins(pixel, pins, rotation=0) {
+ for (var i = 0; i < pins.length; i++) {
+ var [rx, ry] = rotateCoordinate(pins[i][0], pins[i][1], rotation);
+ var px = pixel.x + rx;
+ var py = pixel.y + ry;
+ if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
+
+ if (!pixelMap[px] || pixelMap[px][py] == undefined) {
+ var pinType = pins[i][2] ? "input_pin" : "output_pin";
+ createPixel(pinType, px, py);
+ }
+ }
+}
+
+function checkPin(pixel, pins, index, rotation=pixel.circuitRotation) {
+ var [rx, ry] = rotateCoordinate(pins[index][0], pins[index][1], rotation);
+ var px = pixel.x + rx;
+ var py = pixel.y + ry;
+ if (!(0 <= px && px < width && 0 <= py && py < height)) {return;}
+
+ return pixelMap[px][py] && pixelMap[px][py].active;
+}
+
+function setPin(pixel, pins, index, value, rotation=pixel.circuitRotation) {
+ var [rx, ry] = rotateCoordinate(pins[index][0], pins[index][1], rotation);
+ var px = pixel.x + rx;
+ var py = pixel.y + ry;
+ if (!(0 <= px && px < width && 0 <= py && py < height)) {return;}
+
+ if (pixelMap[px][py] && pixelMap[px][py].element == "output_pin") {
+ pixelMap[px][py].active = value;
+ }
+}
+
+// Circuits
+elements.four_bit_enabler_circuit = {
+ centered: true,
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-3, -2, true], // D0
+ [-1, -2, true], // D1
+ [1, -2, true], // D2
+ [3, -2, true], // D3
+
+ // Enable input (E)
+ [5, 0, true], // Enable (E)
+
+ // Enable mirror (E2)
+ [-5, 0, false],
+
+ // Outputs (Q0-Q3)
+ [-3, 2, false], // Q0
+ [-1, 2, false], // Q1
+ [1, 2, false], // Q2
+ [3, 2, false] // Q3
+ ];
+
+ var elementData = elements[pixel.element];
+ initializeCircuit(pixel, pins, 9, 3, elementData.centered);
+
+ // Read inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ var C = checkPin(pixel, pins, 4); // Control input
+ setPin(pixel, pins, 5, C);
+
+ // Previous state initialization
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ }
+
+ // Update latch state based on control input
+ if (C) {
+ pixel._state = [D[0], D[1], D[2], D[3]]; // Update latch state with data inputs
+ } else {
+ pixel._state = [false, false, false, false];
+ }
+
+ // Output the latch state
+ setPin(pixel, pins, 6, pixel._state[0]); // Q0
+ setPin(pixel, pins, 7, pixel._state[1]); // Q1
+ setPin(pixel, pins, 8, pixel._state[2]); // Q2
+ setPin(pixel, pins, 9, pixel._state[3]); // Q3
+ }
+};
+
+elements.randomizer = {
+ color: "#FFCCFF",
+ tick: 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)) {
+ if (pixelMap[x][y].element == "logic_wire") {
+ if (Math.random() < 0.5){
+ pixelMap[x][y].lstate = 2
+ pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#ffe49c")
+ } else {
+ pixelMap[x][y].lstate = -2
+ pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#3d4d2c")
+ }
+ }
+ }
+ }
+ },
+}
+
+elements.four_bit_randomizer_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Clock input
+ [0, -2, true], // Clock
+
+ // Outputs (Q0-Q3)
+ [-3, 2, false], // Q0
+ [-1, 2, false], // Q1
+ [1, 2, false], // Q2
+ [3, 2, false] // Q3
+ ];
+
+ initializeCircuit(pixel, pins, 9, 3);
+
+ // Read clock input
+ var clock = checkPin(pixel, pins, 0);
+
+ // Initialize the state if not already done
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ pixel.prevClock = false;
+ }
+
+ // Detect the positive edge on the clock pin
+ if (clock && !pixel.prevClock) {
+ // Generate a new 4-bit random number
+ var randomValue = Math.floor(Math.random() * 16);
+
+ // Update the state with the new random value
+ pixel._state = [
+ (randomValue & 1) !== 0,
+ (randomValue & 2) !== 0,
+ (randomValue & 4) !== 0,
+ (randomValue & 8) !== 0
+ ];
+ }
+
+ // Output the current state
+ setPin(pixel, pins, 1, pixel._state[0]); // Q0
+ setPin(pixel, pins, 2, pixel._state[1]); // Q1
+ setPin(pixel, pins, 3, pixel._state[2]); // Q2
+ setPin(pixel, pins, 4, pixel._state[3]); // Q3
+
+ // Update previous state of clock input
+ pixel.prevClock = clock;
+ }
+};
+
+/*elements.ROM_circuit = {
+ previewSize: false,
+ tick: function(pixel) {
+ var romWidth = 16;
+ var romHeight = 16;
+
+ var pins = [
+ // Address inputs (D0-D7)
+ [-1, 1, true], // D0
+ [-1, 3, true], // D1
+ [-1, 5, true], // D2
+ [-1, 7, true], // D3
+ [-1, 9, true], // D4
+ [-1, 11, true], // D5
+ [-1, 13, true], // D6
+ [-1, 15, true], // D7
+
+ // ROM output
+ [romWidth + 2, 1, false],
+ [romWidth + 2, 3, false],
+ [romWidth + 2, 5, false],
+ [romWidth + 2, 7, false],
+ ];
+
+ initializeCircuit(pixel, pins, romWidth + 2, romHeight + 2, false, pixel.circuitRotation, addDisplayCallback);
+
+// if (!pixel.romData) {pixel.romData = new Array(64).fill(0);}
+ if (!pixel.romData) {
+ pixel.romData = Array.from({length: romWidth * romHeight}, () => Array.from({length: 4}, () => Math.floor(Math.random() * 2)));
+ }
+
+ // Read inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3),
+ checkPin(pixel, pins, 4),
+ checkPin(pixel, pins, 5),
+ checkPin(pixel, pins, 6),
+ checkPin(pixel, pins, 7)
+ ];
+
+ var address = binaryArrayToNumber(D);
+ if (isNaN(address)) {return;}
+
+ // Draw the ROM data
+ for (var y = 1; y <= romWidth; y++) {
+ for (var x = 1; x <= romHeight; x++) {
+ var px = pixel.x + x;
+ var py = pixel.y + y;
+ var cellAddress = ((y - 1) * romWidth) + x - 1;
+ var cellData = pixel.romData[cellAddress];
+ if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
+
+ if (pixelMap[px][py] && pixelMap[px][py].element == "art") {
+// if (address == cellAddress) {}
+ pixelMap[px][py].color = dataVisualizationPalette16[binaryArrayToNumber(cellData)];
+ }
+ }
+ }
+
+ var output = pixel.romData[address];
+
+ setPin(pixel, pins, 8, output[0]);
+ setPin(pixel, pins, 9, output[1]);
+ setPin(pixel, pins, 10, output[2]);
+ setPin(pixel, pins, 11, output[3]);
+ }
+};*/
+
+function general_encoder(inputBits) {
+ return function(pixel) {
+ var pins = [];
+ var outputBits = Math.ceil(Math.log2(inputBits));
+ var circuitWidth = (inputBits * 2) + 1;
+ var circuitHeight = (outputBits * 2) + 1;
+
+ // Define input pins
+ for (var i = 0; i < inputBits; i++) {
+ pins.push([-Math.floor(circuitWidth / 2) + 1 + 2 * i, outputBits + 1, true]);
+ }
+
+ // Define output pins
+ for (var i = 0; i < outputBits; i++) {
+ pins.push([Math.floor(circuitWidth / 2) + 1, -outputBits + 1 + 2 * i, false]); // Right outputs
+ }
+
+ for (var i = 0; i < outputBits; i++) {
+ pins.push([-Math.floor(circuitWidth / 2) - 1, -outputBits + 1 + 2 * i, false]); // Left outputs
+ }
+
+ initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
+
+ // Determine which input is active (priority encoder)
+ var activeInput = -1;
+ for (var i = inputBits - 1; i >= 0; i--) {
+ if (checkPin(pixel, pins, i)) {
+ activeInput = i;
+ break;
+ }
+ }
+
+ // Set output values based on active input
+ for (var i = 0; i < outputBits; i++) {
+ var outputValue = activeInput >= 0 ? ((activeInput >> i) & 1) : false;
+ setPin(pixel, pins, inputBits + i, outputValue); // Right outputs
+ setPin(pixel, pins, inputBits + outputBits + i, outputValue); // Left outputs
+ }
+ };
+}
+
+// Define a 2-to-1 encoder using the general_encoder function
+elements.two_to_one_encoder_circuit = {
+ tick: general_encoder(2)
+};
+
+// Define a 4-to-2 encoder using the general_encoder function
+elements.four_to_two_encoder_circuit = {
+ tick: general_encoder(4)
+};
+
+// Define an 8-to-3 encoder using the general_encoder function
+elements.eight_to_three_encoder_circuit = {
+ tick: general_encoder(8)
+};
+
+// Define a 16-to-4 encoder using the general_encoder function
+elements.sixteen_to_four_encoder_circuit = {
+ tick: general_encoder(16)
+};
+
+function general_demultiplexer(selectorBits) {
+ return function(pixel) {
+ var pins = [];
+ var outputCount = Math.pow(2, selectorBits);
+ var circuitWidth = 3;
+ var circuitHeight = (outputCount * 2) + 1;
+
+ // Define the input pin
+ pins.push([0, Math.floor(circuitHeight / 2) + 1, true]);
+
+ // Define selector pins
+ for (var i = 0; i < selectorBits; i++) {
+ pins.push([-2, (Math.floor(circuitHeight / 2) - 1) - (2 * i), true]);
+ }
+
+ // Define output pins
+ for (var i = 0; i < outputCount; i++) {
+ pins.push([Math.floor(circuitWidth / 2) + 1, -Math.floor(circuitHeight / 2) + 1 + 2 * i, false]);
+ }
+
+ initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
+
+ // Read input and selector values
+ var input = checkPin(pixel, pins, 0);
+ var selector = 0;
+ for (var i = 0; i < selectorBits; i++) {
+ if (checkPin(pixel, pins, 1 + i)) {
+ selector += Math.pow(2, i);
+ }
+ }
+
+ // Set output values based on selector
+ for (var i = 0; i < outputCount; i++) {
+ setPin(pixel, pins, 1 + selectorBits + i, i === selector ? input : false);
+ }
+ };
+}
+
+// Define a 1-to-2 demultiplexer using the general_demultiplexer function
+elements.one_to_two_demultiplexer_circuit = {
+ tick: general_demultiplexer(1)
+};
+
+// Define a 1-to-4 demultiplexer using the general_demultiplexer function
+elements.one_to_four_demultiplexer_circuit = {
+ tick: general_demultiplexer(2)
+};
+
+// Define a 1-to-8 demultiplexer using the general_demultiplexer function
+elements.one_to_eight_demultiplexer_circuit = {
+ tick: general_demultiplexer(3)
+};
+
+// Define a 1-to-16 demultiplexer using the general_demultiplexer function
+elements.one_to_sixteen_demultiplexer_circuit = {
+ tick: general_demultiplexer(4)
+};
+
+function general_decoder(inputBits) {
+ return function(pixel) {
+ var pins = [];
+ var outputCount = Math.pow(2, inputBits);
+ var circuitWidth = (inputBits * 2) + 1;
+ var circuitHeight = (outputCount * 2) + 1;
+
+ // Define input pins
+ for (var i = 0; i < inputBits; i++) {
+ pins.push([-Math.floor(circuitWidth / 2) + 1 + 2 * i, outputCount + 1, true]);
+ }
+
+ // Define output pins
+ for (var i = 0; i < outputCount; i++) {
+ pins.push([Math.floor(circuitWidth / 2) + 1, -outputCount + 1 + 2 * i, false]); // Right outputs
+ }
+
+ for (var i = 0; i < outputCount; i++) {
+ pins.push([-Math.floor(circuitWidth / 2) - 1, -outputCount + 1 + 2 * i, false]); // Left outputs
+ }
+
+ initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
+
+ // Read input values
+ var input = 0;
+ for (var i = 0; i < inputBits; i++) {
+ if (checkPin(pixel, pins, i)) {
+ input += Math.pow(2, i);
+ }
+ }
+
+ // Set output values
+ for (var i = 0; i < outputCount; i++) {
+ var outputValue = (i === input);
+ setPin(pixel, pins, inputBits + i, outputValue); // Right outputs
+ setPin(pixel, pins, inputBits + outputCount + i, outputValue); // Left outputs
+ }
+ };
+}
+
+elements.one_to_two_decoder_circuit = {
+ tick: general_decoder(1)
+};
+
+elements.two_to_four_decoder_circuit = {
+ tick: general_decoder(2)
+};
+
+elements.three_to_eight_decoder_circuit = {
+ tick: general_decoder(3)
+};
+
+elements.four_to_sixteen_decoder_circuit = {
+ tick: general_decoder(4)
+};
+
+function general_multiplexer(inputLines) {
+ return function(pixel) {
+ var pins = [];
+ var selectorBits = Math.ceil(Math.log2(inputLines));
+ var circuitWidth = (selectorBits * 2) + 1;
+ var circuitHeight = (inputLines * 2) + 1;
+
+ // Define selector pins
+ for (var i = 0; i < selectorBits; i++) {
+ pins.push([-Math.floor(circuitWidth / 2) + 1 + 2 * i, inputLines + 1, true]);
+ }
+
+ // Define input data pins
+ for (var i = 0; i < inputLines; i++) {
+ pins.push([-Math.floor(circuitWidth / 2) - 1, -inputLines + 1 + 2 * i, true]);
+ }
+
+ // Define output pin
+ pins.push([Math.floor(circuitWidth / 2) + 1, 0, false]);
+
+ initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
+
+ // Read selector input
+ var selector = 0;
+ for (var i = 0; i < selectorBits; i++) {
+ if (checkPin(pixel, pins, i)) {
+ selector += Math.pow(2, i);
+ }
+ }
+
+ setPin(pixel, pins, selectorBits + inputLines, checkPin(pixel, pins, selector + selectorBits)); // Output pin
+ };
+}
+
+// Define a 2-input multiplexer using the general_multiplexer function
+elements.two_to_one_multiplexer_circuit = {
+ tick: general_multiplexer(2)
+};
+
+// Define a 4-input multiplexer using the general_multiplexer function
+elements.four_to_one_multiplexer_circuit = {
+ tick: general_multiplexer(4)
+};
+
+// Define an 8-input multiplexer using the general_multiplexer function
+elements.eight_to_one_multiplexer_circuit = {
+ tick: general_multiplexer(8)
+};
+
+// Define an 8-input multiplexer using the general_multiplexer function
+elements.sixteen_to_one_multiplexer_circuit = {
+ tick: general_multiplexer(16)
+};
+
+elements.four_bit_PISO_shift_register_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-3, -3, true], // D0
+ [-1, -3, true], // D1
+ [1, -3, true], // D2
+ [3, -3, true], // D3
+
+ // Control input (Load/Shift Enable)
+ [-5, -1, true], // Load/Shift Enable
+
+ // Clock input
+ [-5, 1, true], // Clock
+
+ // Serial output
+ [5, -1, false], // Serial Out (Q)
+ [5, 1, false] // Transmission Flag
+ ];
+
+ initializeCircuit(pixel, pins, 9, 5);
+
+ // Read data inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ // Read control and clock inputs
+ var loadShiftEnable = checkPin(pixel, pins, 4);
+ var clock = checkPin(pixel, pins, 5);
+
+ // Initialize the state if not already done
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ pixel.bitIndex = 0;
+ pixel.prevLoadShiftEnable = false;
+ pixel.prevClock = false;
+ }
+
+ // Detect the positive edge on the control pin
+ if (loadShiftEnable && !pixel.prevLoadShiftEnable) {
+ // Load the data into the register on the first positive edge
+ pixel._state = [D[0], D[1], D[2], D[3]];
+ pixel.bitIndex = 0;
+ }
+
+ // Detect the positive edge on the clock pin
+ if (clock && !pixel.prevClock) {
+ if (pixel.bitIndex < 4) {
+ // Shift the register and output the next bit
+ var serialOut = pixel._state[0];
+ for (var i = 0; i < 3; i++) {
+ pixel._state[i] = pixel._state[i + 1];
+ }
+ pixel._state[3] = false; // Clear the last bit after shifting
+
+ // Output the serial value
+ setPin(pixel, pins, 6, serialOut);
+
+ // Update bit index
+ pixel.bitIndex++;
+ }
+ }
+
+ // Set the transmission flag
+ var transmitting = pixel.bitIndex < 4 && loadShiftEnable;
+ setPin(pixel, pins, 7, transmitting);
+
+ // Update previous state of control and clock inputs
+ pixel.prevLoadShiftEnable = loadShiftEnable;
+ pixel.prevClock = clock;
+ }
+};
+
+elements.four_bit_SIPO_shift_register_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Serial input (Data In)
+ [-2, -3, true], // Data In
+
+ // Clock input
+ [-2, -1, true], // Clock
+
+ // Parallel outputs (Q0-Q3)
+ [2, -3, false], // Q0
+ [2, -1, false], // Q1
+ [2, 1, false], // Q2
+ [2, 3, false] // Q3
+ ];
+
+ initializeCircuit(pixel, pins, 3, 9);
+
+ // Read serial and clock input
+ var serialIn = checkPin(pixel, pins, 0);
+ var clock = checkPin(pixel, pins, 1);
+
+ // Initialize the state if not already done
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ pixel.prevClock = false;
+ }
+
+ // Detect the positive edge on the clock pin
+ if (clock && !pixel.prevClock) {
+ pixel._state = [serialIn, pixel._state[0], pixel._state[1], pixel._state[2]];
+ }
+
+ // Output the parallel values
+ for (var i = 0; i < 4; i++) {
+ setPin(pixel, pins, 2 + i, pixel._state[i]);
+ }
+
+ // Update previous state of control and clock inputs
+ pixel.prevClock = clock;
+ }
+};
+
+elements.four_bit_program_counter_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-3, -3, true], // D0
+ [-1, -3, true], // D1
+ [1, -3, true], // D2
+ [3, -3, true], // D3
+
+ // Control inputs (Increment, Write Enable)
+ [5, -1, true], // Increment
+ [5, 1, true], // Write Enable
+
+ // Outputs (Q0-Q3)
+ [-3, 3, false], // Q0
+ [-1, 3, false], // Q1
+ [1, 3, false], // Q2
+ [3, 3, false], // Q3
+ ];
+
+ initializeCircuit(pixel, pins, 9, 5);
+
+ // Read data inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ // Read control inputs
+ var Increment = checkPin(pixel, pins, 4);
+ var WriteEnable = checkPin(pixel, pins, 5);
+
+ // Initialize the state if not already done
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ pixel.prevIncrement = false; // Previous state of Increment pin
+ }
+
+ // Convert the state to a 4-bit binary number
+ var stateValue = binaryArrayToNumber(pixel._state);
+
+ // Detect the positive edge on the Increment pin
+ if (Increment && !pixel.prevIncrement) {
+ stateValue = (stateValue + 1) % 16; // Ensure the value wraps around at 4 bits
+ }
+
+ // Update the register state if WriteEnable is active
+ if (WriteEnable) {
+ stateValue = binaryArrayToNumber(D); // Load data inputs into state
+ }
+
+ // Update the state
+ pixel._state = [
+ (stateValue & 8) !== 0,
+ (stateValue & 4) !== 0,
+ (stateValue & 2) !== 0,
+ (stateValue & 1) !== 0
+ ];
+
+ // Output the register state
+ setPin(pixel, pins, 6, pixel._state[0]); // Q0
+ setPin(pixel, pins, 7, pixel._state[1]); // Q1
+ setPin(pixel, pins, 8, pixel._state[2]); // Q2
+ setPin(pixel, pins, 9, pixel._state[3]); // Q3
+
+ // Update previous state of Increment pin
+ pixel.prevIncrement = Increment;
+ }
+};
+
+elements.four_bit_register_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-3, -3, true], // D0
+ [-1, -3, true], // D1
+ [1, -3, true], // D2
+ [3, -3, true], // D3
+
+ // Control inputs (Enable, Write Enable)
+ [5, -1, true], // Enable
+ [5, 1, true], // Write Enable
+
+ // Outputs (Q0-Q3)
+ [-3, 3, false], // Q0
+ [-1, 3, false], // Q1
+ [1, 3, false], // Q2
+ [3, 3, false], // Q3
+ ];
+
+ initializeCircuit(pixel, pins, 9, 5);
+
+ // Read data inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ // Read control inputs
+ var Enable = checkPin(pixel, pins, 4);
+ var WriteEnable = checkPin(pixel, pins, 5);
+
+ // Initialize the state if not already done
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ }
+
+ // Update the register state if WriteEnable is active
+ if (WriteEnable && Enable) {
+ pixel._state = [D[0], D[1], D[2], D[3]];
+ }
+
+ // Output the register state if Enable is active
+ if (Enable) {
+ setPin(pixel, pins, 6, pixel._state[0]); // Q0
+ setPin(pixel, pins, 7, pixel._state[1]); // Q1
+ setPin(pixel, pins, 8, pixel._state[2]); // Q2
+ setPin(pixel, pins, 9, pixel._state[3]); // Q3
+ } else {
+ // Disable outputs if Enable is not active
+ setPin(pixel, pins, 6, false); // Q0
+ setPin(pixel, pins, 7, false); // Q1
+ setPin(pixel, pins, 8, false); // Q2
+ setPin(pixel, pins, 9, false); // Q3
+ }
+ }
+};
+
+elements.SR_latch_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ [0, -2, true], // Input: Set
+ [0, 2, true], // Input: Reset
+ [2, 0, false], // Output
+ [-2, 0, false] // Output
+ ];
+ initializeCircuit(pixel, pins, 3, 3);
+
+ if (checkPin(pixel, pins, 0)) {pixel._state = true;} // Set
+ if (checkPin(pixel, pins, 1)) {pixel._state = false;} // Reset
+
+ setPin(pixel, pins, 2, pixel._state);
+ setPin(pixel, pins, 3, pixel._state);
+ }
+};
+
+elements.T_flip_flop_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ [0, -2, true], // Input: Toggle (T)
+ [2, 0, false], // Output (Q)
+ [-2, 0, false] // Output (not Q) - Optional
+ ];
+
+ initializeCircuit(pixel, pins, 3, 3);
+
+ // Check the current state of the Toggle (T) input
+ var T = checkPin(pixel, pins, 0);
+
+ // Initialize the previous state of T if not already done
+ if (pixel.prevT === undefined) {
+ pixel.prevT = false;
+ }
+
+ // Detect the positive edge
+ if (T && !pixel.prevT) {
+ pixel._state = !pixel._state; // Toggle state on positive edge
+ }
+
+ // Update the previous state of T
+ pixel.prevT = T;
+
+ setPin(pixel, pins, 1, pixel._state);
+ setPin(pixel, pins, 2, pixel._state);
+ }
+};
+
+elements.D_latch_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ [0, -2, true], // Input: Data
+ [2, 0, true], // Input: Enable
+ [0, 2, false], // Output
+ [-2, 0, false] // Output
+ ];
+ initializeCircuit(pixel, pins, 3, 3);
+
+ var D = checkPin(pixel, pins, 0); // Data input
+ var E = checkPin(pixel, pins, 1); // Enable input
+
+ if (E) {
+ pixel._state = D; // Q follows D when E is active
+ }
+
+ setPin(pixel, pins, 2, pixel._state);
+ setPin(pixel, pins, 3, pixel._state);
+ }
+};
+
+elements.D_flip_flop_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ [0, -2, true], // Input: Data
+ [2, 0, true], // Input: Enable
+ [0, 2, false], // Output
+ [-2, 0, false] // Output
+ ];
+
+ initializeCircuit(pixel, pins, 3, 3);
+
+ // Read inputs
+ var D = checkPin(pixel, pins, 0); // Data input
+ var C = checkPin(pixel, pins, 1); // Control input
+
+ // Initialize previous state of control input if not already done
+ if (pixel.prevC === undefined) {
+ pixel.prevC = false;
+ }
+
+ // Previous state initialization
+ if (pixel._state === undefined) {
+ pixel._state = false;
+ }
+
+ // Update flip-flop state on positive edge of control input
+ if (C && !pixel.prevC) {
+ pixel._state = D; // Q follows D on positive edge of C
+ }
+
+ // Update the previous state of control input
+ pixel.prevC = C;
+
+ // Output the flip-flop state
+ setPin(pixel, pins, 2, pixel._state);
+ setPin(pixel, pins, 3, pixel._state);
+ }
+};
+
+elements.four_bit_D_latch_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-3, -2, true], // D0
+ [-1, -2, true], // D1
+ [1, -2, true], // D2
+ [3, -2, true], // D3
+
+ // Control input (C)
+ [5, 0, true], // Control (C)
+
+ // Outputs (Q0-Q3)
+ [-3, 2, false], // Q0
+ [-1, 2, false], // Q1
+ [1, 2, false], // Q2
+ [3, 2, false] // Q3
+ ];
+
+ initializeCircuit(pixel, pins, 9, 3);
+
+ // Read inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ var C = checkPin(pixel, pins, 4); // Control input
+
+ // Previous state initialization
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ }
+
+ // Update latch state based on control input
+ if (C) {
+ pixel._state = [D[0], D[1], D[2], D[3]]; // Update latch state with data inputs
+ }
+
+ // Output the latch state
+ setPin(pixel, pins, 5, pixel._state[0]); // Q0
+ setPin(pixel, pins, 6, pixel._state[1]); // Q1
+ setPin(pixel, pins, 7, pixel._state[2]); // Q2
+ setPin(pixel, pins, 8, pixel._state[3]); // Q3
+ }
+};
+
+elements.four_bit_D_flip_flop_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-3, -2, true], // D0
+ [-1, -2, true], // D1
+ [1, -2, true], // D2
+ [3, -2, true], // D3
+
+ // Control input (C)
+ [5, 0, true], // Control (C)
+
+ // Outputs (Q0-Q3)
+ [-3, 2, false], // Q0
+ [-1, 2, false], // Q1
+ [1, 2, false], // Q2
+ [3, 2, false] // Q3
+ ];
+
+ initializeCircuit(pixel, pins, 9, 3);
+
+ // Read inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ var C = checkPin(pixel, pins, 4); // Control input
+
+ // Initialize previous state of control input if not already done
+ if (pixel.prevC === undefined) {
+ pixel.prevC = false;
+ }
+
+ // Previous state initialization
+ if (pixel._state === undefined) {
+ pixel._state = [false, false, false, false];
+ }
+
+ // Update flip-flop state on positive edge of control input
+ if (C && !pixel.prevC) {
+ pixel._state = [D[0], D[1], D[2], D[3]]; // Update flip-flop state with data inputs
+ }
+
+ // Update the previous state of control input
+ pixel.prevC = C;
+
+ // Output the flip-flop state
+ setPin(pixel, pins, 5, pixel._state[0]); // Q0
+ setPin(pixel, pins, 6, pixel._state[1]); // Q1
+ setPin(pixel, pins, 7, pixel._state[2]); // Q2
+ setPin(pixel, pins, 8, pixel._state[3]); // Q3
+ }
+};
+
+elements.four_bit_incrementer_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // 4-bit number inputs (N0-N3)
+ [-3, -2, true], // N0
+ [-1, -2, true], // N1
+ [1, -2, true], // N2
+ [3, -2, true], // N3
+
+ // Increment control input (INC)
+ [-5, 0, true], // Increment (INC)
+
+ // Outputs (Q0-Q3)
+ [-3, 2, false], // Q0
+ [-1, 2, false], // Q1
+ [1, 2, false], // Q2
+ [3, 2, false], // Q3
+
+ // Carry out
+ [5, 0, false] // Carry out (COUT)
+ ];
+
+ initializeCircuit(pixel, pins, 9, 3);
+
+ // Read inputs
+ var N = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ var INC = checkPin(pixel, pins, 4); // Increment control input
+
+ // Calculate the incremented value when control is active
+ var carry = 0;
+ var result = [];
+
+ if (INC) {
+ carry = 1; // Start with a carry of 1 to increment by 1
+ }
+
+ for (var i = 0; i < 4; i++) {
+ var sum = N[i] + carry;
+ result[i] = sum % 2; // Current bit sum
+ carry = Math.floor(sum / 2); // Carry for next bit
+ }
+
+ // Output the incremented value and carry out
+ setPin(pixel, pins, 5, result[0]); // Q0
+ setPin(pixel, pins, 6, result[1]); // Q1
+ setPin(pixel, pins, 7, result[2]); // Q2
+ setPin(pixel, pins, 8, result[3]); // Q3
+ setPin(pixel, pins, 9, carry); // Carry out (COUT)
+ }
+};
+
+elements.four_bit_adder_circuit = {
+ tick: function(pixel) {
+ var pins = [
+ // First 4-bit number (A)
+ [-7, -2, true], // A0
+ [-5, -2, true], // A1
+ [-3, -2, true], // A2
+ [-1, -2, true], // A3
+
+ // Second 4-bit number (B)
+ [1, -2, true], // B0
+ [3, -2, true], // B1
+ [5, -2, true], // B2
+ [7, -2, true], // B3
+
+ // Carry-in (C_in)
+ [9, 0, true], // Carry-in (C_in)
+
+ // Output sum (S)
+ [-7, 2, false], // S0
+ [-5, 2, false], // S1
+ [-3, 2, false], // S2
+ [-1, 2, false], // S3
+ [1, 2, false], // Carry Out (C4)
+ ];
+
+ initializeCircuit(pixel, pins, 17, 3);
+
+ // Read inputs
+ var A = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ var B = [
+ checkPin(pixel, pins, 4),
+ checkPin(pixel, pins, 5),
+ checkPin(pixel, pins, 6),
+ checkPin(pixel, pins, 7)
+ ];
+
+ var C_in = checkPin(pixel, pins, 8); // Carry-in
+
+ // Calculate the sum and carry
+ var sum = [];
+ var carry = C_in;
+
+ for (var i = 0; i < 4; i++) {
+ var bitSum = A[i] + B[i] + carry;
+ sum[i] = bitSum % 2; // Current bit sum
+ carry = Math.floor(bitSum / 2); // Carry for next bit
+ }
+
+ // Output the sum
+ setPin(pixel, pins, 9, sum[0]); // S0
+ setPin(pixel, pins, 10, sum[1]); // S1
+ setPin(pixel, pins, 11, sum[2]); // S2
+ setPin(pixel, pins, 12, sum[3]); // S3
+ setPin(pixel, pins, 13, carry); // Carry Out (C4)
+ }
+};
+
+function general_clock(speed, s2) {
+ return 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)) {
+ if (pixelMap[x][y].element == "logic_wire"){
+ if (pixelTicks % speed < s2){
+ pixelMap[x][y].lstate = 2
+ pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#ffe49c")
+ } else {
+ pixelMap[x][y].lstate = -2
+ pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#3d4d2c")
+ }
+ }
+ }
+ }
+ };
+}
+
+elements.slow_clock = {
+ color: "#BB66BB",
+ tick: general_clock(64, 32),
+}
+
+elements.medium_clock = {
+ color: "#DD88DD",
+ tick: general_clock(32, 16),
+}
+
+elements.fast_clock = {
+ color: "#FFAAFF",
+ tick: general_clock(16, 8),
+}
+
+elements.very_fast_clock = {
+ color: "#FFCCFF",
+ tick: general_clock(8, 4),
+}
+
+var addDisplayCallback = function(pixel, pins, w, h) {
+ for (var y = 1; y < h - 1; y++) {
+ for (var x = 1; x < w - 1; x++) {
+ var px = pixel.x + x;
+ var py = pixel.y + y;
+ if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
+
+ deletePixel(px, py);
+ createPixel("art", px, py);
+ pixelMap[px][py].color = "rgb(16, 24, 32)";
+ }
+ }
+}
+
+elements.simple_seven_segment_display = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-1, 1, true], // D0
+ [-1, 3, true], // D1
+ [-1, 5, true], // D2
+ [-1, 7, true], // D3
+ ];
+
+ initializeCircuit(pixel, pins, 5, 9, false, pixel.circuitRotation, addDisplayCallback);
+
+ // Read inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3)
+ ];
+
+ var hexNumber = (D[3] * 8) + (D[2] * 4) + (D[1] * 2) + (D[0] * 1);
+ if (isNaN(hexNumber)) {return;}
+
+ // Draw the number
+ var hexGrid = hexToPixelGrid(hexNumber);
+ for (var y = 2; y <= 6; y++) {
+ for (var x = 1; x <= 3; x++) {
+ var px = pixel.x + x;
+ var py = pixel.y + y;
+
+ if (pixelMap[px][py] && pixelMap[px][py].element == "art") {
+ if (hexGrid[y - 2][x - 1]) {
+ pixelMap[px][py].color = "rgb(16, 230, 120)";
+ } else {
+ pixelMap[px][py].color = "rgb(16, 24, 32)";
+ }
+ }
+ }
+ }
+ }
+};
+
+elements.simple_double_seven_segment_display = {
+ tick: function(pixel) {
+ var pins = [
+ // Data inputs (D0-D3)
+ [-1, 1, true], // D0
+ [-1, 3, true], // D1
+ [-1, 5, true], // D2
+ [-1, 7, true], // D3
+
+ [1, -1, true], // D2-0
+ [3, -1, true], // D2-1
+ [5, -1, true], // D2-2
+ [7, -1, true], // D2-3
+ ];
+
+ initializeCircuit(pixel, pins, 9, 9, false, pixel.circuitRotation, addDisplayCallback);
+
+ // Read inputs
+ var D = [
+ checkPin(pixel, pins, 0),
+ checkPin(pixel, pins, 1),
+ checkPin(pixel, pins, 2),
+ checkPin(pixel, pins, 3),
+ checkPin(pixel, pins, 4),
+ checkPin(pixel, pins, 5),
+ checkPin(pixel, pins, 6),
+ checkPin(pixel, pins, 7)
+ ];
+
+ var hexNumber = (D[3] * 8) + (D[2] * 4) + (D[1] * 2) + (D[0] * 1);
+ var hexNumber2 = (D[7] * 8) + (D[6] * 4) + (D[5] * 2) + (D[4] * 1);
+ if (isNaN(hexNumber) || isNaN(hexNumber2)) {return;}
+
+ // Draw the number
+ var hexGrid = hexToPixelGrid(hexNumber);
+ for (var y = 2; y <= 6; y++) {
+ for (var x = 1; x <= 3; x++) {
+ var px = pixel.x + x;
+ var py = pixel.y + y;
+
+ if (pixelMap[px][py] && pixelMap[px][py].element == "art") {
+ if (hexGrid[y - 2][x - 1]) {
+ pixelMap[px][py].color = "rgb(16, 230, 120)";
+ } else {
+ pixelMap[px][py].color = "rgb(16, 24, 32)";
+ }
+ }
+ }
+ }
+
+ var hexGrid2 = hexToPixelGrid(hexNumber2);
+ for (var y = 2; y <= 6; y++) {
+ for (var x = 5; x <= 7; x++) {
+ var px = pixel.x + x;
+ var py = pixel.y + y;
+
+ if (pixelMap[px][py] && pixelMap[px][py].element == "art") {
+ if (hexGrid2[y - 2][x - 5]) {
+ pixelMap[px][py].color = "rgb(16, 230, 120)";
+ } else {
+ pixelMap[px][py].color = "rgb(16, 24, 32)";
+ }
+ }
+ }
+ }
+ }
+};
+
+elements.circuit_material = {
+ color: "#444444",
+ category: "logic"
+};
+
+elements.input_pin = {
+ color: "#DDAA33",
+ category: "logic",
+ active: false,
+ tick: function(pixel) {
+ pixel.active = false;
+ var neighbors = getNeighbors(pixel);
+ for (var i = 0;i < neighbors.length;i++) {
+ var neighbor = neighbors[i];
+
+ if (neighbor.charge > 0 || neighbor.lstate == 2 || neighbor.active) {
+ pixel.active = true;
+ }
+ }
+ }
+};
+
+elements.output_pin = {
+ color: "#AAAAAA",
+ category: "logic",
+ active: false,
+ tick: function(pixel) {
+ var neighbors = getNeighbors(pixel);
+ for (var i = 0;i < neighbors.length;i++) {
+ var neighbor = neighbors[i];
+
+ // Check if it's a wire
+ if (elements[neighbor.element].conduct > 0 && pixel.active) {
+ neighbor.charge = 1;
+ }
+
+ // Check if it's a logic wire (logicgates.js)
+ if (neighbor.lstate != undefined) {
+ if (pixel.active) {
+ neighbor.lstate = 2;
+ neighbor.color = pixelColorPick(neighbor, "#ffe49c");
+ } else {
+ neighbor.lstate = -2;
+ neighbor.color = pixelColorPick(neighbor, "#3d4d2c");
+ }
+ }
+ }
+ }
+};
+
+elements.logic_corrupt = {
+ color: "#DD33DD",
+ category: "logic",
+ tool: function(pixel) {
+ if (pixel.element == "logic_wire") {
+ if (Math.random() < 0.01) {
+ if (Math.random() < 0.5) {
+ pixel.lstate = 2;
+ pixel.color = pixelColorPick(pixel, "#ffe49c");
+ } else {
+ pixel.lstate = -2;
+ pixel.color = pixelColorPick(pixel, "#3d4d2c");
+ }
+ }
+ }
+ },
+ excludeRandom: true,
+}
+
+elements.logic_corrupter_machine = {
+ color: "#DD33DD",
+ category: "logic",
+ tick: function(pixel) {
+ var radius = 10
+ for (var y = pixel.y - radius; y < pixel.y + radius; y++) {
+ for (var x = pixel.x - radius; x < pixel.x + radius; x++) {
+ if (!isEmpty(x, y, true)) {
+ if (pixelMap[x][y].element == "logic_wire" && Math.random() < Math.min(Math.max((pixel.temp + 273) / 473, 0), 1) * 0.005) {
+ if (Math.random() < 0.5) {
+ pixelMap[x][y].lstate = 2
+ pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#ffe49c")
+ } else {
+ pixelMap[x][y].lstate = -2
+ pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#3d4d2c")
+ }
+ }
+ }
+ }
+ }
+ },
+}
+
+elements.circuitCoreTutorial = {
+ color: "#33FF66",
+ category: "logic",
+ onSelect: function() {
+ window.open("https://redbirdly.github.io/circuitcore_tutorial.html");
+ },
+}
+
+// cc_ is circuit core prefix
+const cc_BROWN = "#773317";
+const cc_RED = "#DD3322";
+const cc_ORANGE = "#DD8833";
+const cc_YELLOW = "#DDCC44";
+const cc_LIME = "#77DD44";
+const cc_GREEN = "#33BB44";
+const cc_BLUE = "#224499";
+const cc_LIGHT_BLUE = "#77CCFF";
+const cc_LAVENDER = "#AA88EE";
+//const cc_PINK = "#DD88DD";
+const cc_WHITE = "#DDDDDD";
+
+var circuits = [
+ // Misc and I/O: brown
+ { circuit: elements.four_bit_enabler_circuit, color: cc_BROWN, size: [9, 3, true] },
+ { circuit: elements.randomizer, color: cc_BROWN },
+ { circuit: elements.four_bit_randomizer_circuit, color: cc_BROWN, size: [9, 3, true] },
+ // ROM/RAM: red
+// { circuit: elements.ROM_circuit, color: cc_RED, size: [18, 18, false] },
+ // Encoders and de-multiplexers: orange
+ { circuit: elements.two_to_one_encoder_circuit, color: cc_ORANGE, size: [5, 3, true] },
+ { circuit: elements.four_to_two_encoder_circuit, color: cc_ORANGE, size: [9, 5, true] },
+ { circuit: elements.eight_to_three_encoder_circuit, color: cc_ORANGE, size: [17, 7, true] },
+ { circuit: elements.sixteen_to_four_encoder_circuit, color: cc_ORANGE, size: [33, 9, true] },
+
+ { circuit: elements.one_to_two_demultiplexer_circuit, color: cc_ORANGE, size: [3, 5, true] },
+ { circuit: elements.one_to_four_demultiplexer_circuit, color: cc_ORANGE, size: [3, 9, true] },
+ { circuit: elements.one_to_eight_demultiplexer_circuit, color: cc_ORANGE, size: [3, 17, true] },
+ { circuit: elements.one_to_sixteen_demultiplexer_circuit, color: cc_ORANGE, size: [3, 33, true] },
+ // Decoders and multiplexers: yellow
+ { circuit: elements.one_to_two_decoder_circuit, color: cc_YELLOW, size: [3, 5, true] },
+ { circuit: elements.two_to_four_decoder_circuit, color: cc_YELLOW, size: [5, 9, true] },
+ { circuit: elements.three_to_eight_decoder_circuit, color: cc_YELLOW, size: [7, 17, true] },
+ { circuit: elements.four_to_sixteen_decoder_circuit, color: cc_YELLOW, size: [9, 33, true] },
+
+ { circuit: elements.two_to_one_multiplexer_circuit, color: cc_YELLOW, size: [3, 5, true] },
+ { circuit: elements.four_to_one_multiplexer_circuit, color: cc_YELLOW, size: [5, 9, true] },
+ { circuit: elements.eight_to_one_multiplexer_circuit, color: cc_YELLOW, size: [7, 17, true] },
+ { circuit: elements.sixteen_to_one_multiplexer_circuit, color: cc_YELLOW, size: [9, 33, true] },
+ // Program counter and shift registers: lime
+ { circuit: elements.four_bit_PISO_shift_register_circuit, color: cc_LIME, size: [9, 5, true] },
+ { circuit: elements.four_bit_SIPO_shift_register_circuit, color: cc_LIME, size: [3, 9, true] },
+ { circuit: elements.four_bit_program_counter_circuit, color: cc_LIME, size: [9, 5, true] },
+ // Registers: green
+ { circuit: elements.four_bit_register_circuit, color: cc_GREEN, size: [9, 5, true] },
+ // Latches and flip flops: light blue
+ { circuit: elements.SR_latch_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
+ { circuit: elements.T_flip_flop_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
+ { circuit: elements.D_latch_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
+ { circuit: elements.D_flip_flop_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
+ { circuit: elements.four_bit_D_latch_circuit, color: cc_LIGHT_BLUE, size: [9, 3, true] },
+ { circuit: elements.four_bit_D_flip_flop_circuit, color: cc_LIGHT_BLUE, size: [9, 3, true] },
+ // Addition/subtraction arithmetic: blue
+ { circuit: elements.four_bit_adder_circuit, color: cc_BLUE, size: [17, 3, true] },
+ { circuit: elements.four_bit_incrementer_circuit, color: cc_BLUE, size: [9, 3, true] },
+ // Complex circuits: lavender
+ // Clocks: pink
+ { circuit: elements.slow_clock },
+ { circuit: elements.medium_clock },
+ { circuit: elements.fast_clock },
+ { circuit: elements.very_fast_clock },
+ // Displays/visual circuits: white
+ { circuit: elements.simple_seven_segment_display, color: cc_WHITE, size: [5, 9, false] },
+ { circuit: elements.simple_double_seven_segment_display, color: cc_WHITE, size: [9, 9, false] },
+];
+
+circuits.forEach(circuitInfo => {
+ if (circuitInfo.color) {circuitInfo.circuit.color = circuitInfo.color;}
+ circuitInfo.circuit.category = "logic";
+ circuitInfo.circuit.maxSize = 1;
+ circuitInfo.circuit.isCircuitCore = true;
+ circuitInfo.circuit.previewSize = circuitInfo.size;
+});
+
+var circuitRotation = 0;
+document.addEventListener('keydown', function(event) {
+ if (event.key === 'ArrowUp') {
+ circuitRotation = (circuitRotation + 90) % 360;
+ logMessage('CircuitRotation changed to ' + circuitRotation);
+ }
+});
+
+function drawCircuitExtras() {
+ if (elements[currentElement].isCircuitCore && elements[currentElement].previewSize) {
+ var circuitWidth = elements[currentElement].previewSize[0];
+ var circuitHeight = elements[currentElement].previewSize[1];
+ var centered = elements[currentElement].previewSize[2];
+ var rotation = circuitRotation;
+
+ var startX = 0;
+ var startY = 0;
+ var endX = circuitWidth - 1;
+ var endY = circuitHeight - 1;
+
+ if (centered) {
+ startX = -Math.floor(circuitWidth / 2);
+ startY = -Math.floor(circuitHeight / 2);
+ endX = Math.floor(circuitWidth / 2);
+ endY = Math.floor(circuitHeight / 2);
+ }
+
+ for (var y = startY; y <= endY; y++) {
+ for (var x = startX; x <= endX; x++) {
+// if (!(0 <= x && x < width && 0 <= y && y < height)) {continue;}
+
+ var [rx, ry] = rotateCoordinate(x, y, rotation);
+ var px = mousePos.x + rx;
+ var py = mousePos.y + ry;
+
+ ctx.fillStyle = "rgba(255, 255, 255, 0.1)";
+ if ((rotation != 0 && !centered) || (0 <= px && px < width && 0 <= py && py < height) && pixelMap[px][py]) {
+ ctx.fillStyle = "rgba(255, 0, 0, 0.3)";
+ }
+
+ ctx.fillRect(px * pixelSize, py * pixelSize, pixelSize, pixelSize);
+ }
+ }
+ }
+}
+
+runAfterLoad(() => {
+ var originalDrawPixels3 = drawPixels;
+ drawPixels = function(forceTick=false) {
+ originalDrawPixels3(forceTick);
+ drawCircuitExtras();
+ };
+});
+resetInterval(tps);
diff --git a/mods/fire_extinguisher.js b/mods/fire_extinguisher.js
new file mode 100644
index 00000000..3ad77e03
--- /dev/null
+++ b/mods/fire_extinguisher.js
@@ -0,0 +1,128 @@
+elements.firefighting_foam = {
+ color: ["#E6F3FF", "#F0F8FF", "#F8FBFF"],
+ behavior: [
+ "XX|CR:foam%2.5|XX",
+ "M2 AND CR:foam%2.5|CH:foam%0.2|M2 AND CR:foam%2.5",
+ "M1|M1|M1",
+ ],
+ category: "liquids",
+ state: "liquid",
+ density: 0.9,
+ temp: 10,
+ conduct: 0.01,
+ stain: 0.01,
+ viscosity: 3000,
+ reactions: {
+ "greek_fire": { elem2: null, chance: 0.2 },
+ "water": { elem1: "foam", elem2: "salt_water", chance: 0.1 },
+ "acid": { elem1: "foam", elem2: "neutral_acid", chance: 0.05 },
+ "acid_gas": { elem1: "foam", elem2: "neutral_acid", chance: 0.05 },
+ },
+ tick: function (pixel) {
+ // Extinguish fire and smoke, remove burning state, and cool down pixels in a 6-pixel radius
+ let radius = 6
+ for (let dx = -radius; dx <= radius; dx++) {
+ for (let dy = -radius; dy <= radius; dy++) {
+ let nx = pixel.x + dx;
+ let ny = pixel.y + dy;
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
+ let neighborPixel = pixelMap[nx][ny];
+ if (neighborPixel && neighborPixel.element) {
+ if (neighborPixel.element === "fire" || neighborPixel.element === "smoke") {
+ deletePixel(nx, ny);
+ } else {
+ // Remove burning state
+ if (neighborPixel.burning) {
+ neighborPixel.burning = false;
+ }
+
+ // Cool down the pixel
+ if (neighborPixel.temp > 10) {
+ neighborPixel.temp = Math.max(10, neighborPixel.temp - 5);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Decay over time
+ if (Math.random() < 0.005) {
+ changePixel(pixel, "foam");
+ }
+ if (Math.random() < 0.0002) {
+ deletePixel(pixel.x, pixel.y);
+ }
+ }
+};
+
+elements.fire_extinguisher = {
+ color: "#ce2029",
+ behavior: [
+ "XX|XX|XX",
+ "XX|XX|XX",
+ "XX|XX|XX"
+ ],
+ category: "machines",
+ state: "solid",
+ density: 2,
+ temp: 20,
+ conduct: 0.1,
+ tick: function (pixel) {
+ let shouldExplode = false;
+
+ // Check for fire or smoke within a 10-pixel radius
+ let checkRadius = 10;
+ for (let dx = -checkRadius; dx <= checkRadius; dx++) {
+ for (let dy = -checkRadius; dy <= checkRadius; dy++) {
+ let nx = pixel.x + dx;
+ let ny = pixel.y + dy;
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
+ let neighborPixel = pixelMap[nx][ny];
+ if (neighborPixel && (neighborPixel.element === "fire" || neighborPixel.element === "smoke")) {
+ shouldExplode = true;
+ break;
+ }
+ }
+ }
+ if (shouldExplode) break;
+ }
+
+ if (shouldExplode) {
+ // Calculate the size of the fire extinguisher block
+ let blockSize = 1;
+ for (let dx = 0; dx < 3; dx++) {
+ for (let dy = 0; dy < 3; dy++) {
+ let nx = pixel.x + dx - 1;
+ let ny = pixel.y + dy - 1;
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
+ let neighborPixel = pixelMap[nx][ny];
+ if (neighborPixel && neighborPixel.element === "fire_extinguisher") {
+ blockSize++;
+ }
+ }
+ }
+ }
+
+ // Calculate explosion radius based on block size
+ let explosionRadius = Math.max(blockSize * 5, 10);
+
+ // Create a large explosion of foam
+ for (let dx = -explosionRadius; dx <= explosionRadius; dx++) {
+ for (let dy = -explosionRadius; dy <= explosionRadius; dy++) {
+ // Check if the pixel is within the circular radius
+ if (dx * dx + dy * dy <= explosionRadius * explosionRadius) {
+ let fx = pixel.x + dx;
+ let fy = pixel.y + dy;
+ if (fx >= 0 && fx < width && fy >= 0 && fy < height) {
+ let targetPixel = pixelMap[fx][fy];
+ if (!targetPixel || targetPixel.element === "air") {
+ createPixel("firefighting_foam", fx, fy);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/mods/littlejohnny.js b/mods/littlejohnny.js
new file mode 100644
index 00000000..abdd452e
--- /dev/null
+++ b/mods/littlejohnny.js
@@ -0,0 +1,49 @@
+//made by livvo
+//first time coding so bear with me
+
+elements.ecofriendly_wood_veneer = {
+ color: "#e3bb86",
+ behavior: behaviors.WALL,
+ category: "solids",
+ state: "solid",
+ tempHigh: 400,
+ stateHigh: ["ember","charcoal","fire","fire","fire"],
+ burn: 5,
+ burnTime: 300,
+ burnInto: ["ember","charcoal","fire"],
+ hardness: 0.15,
+ breakInto: "sawdust",
+};
+elements.screws_borrowed_from_aunt = {
+ color: "#687281",
+ behavior: behaviors.POWDER,
+ category: "powders",
+ state: "solid",
+ tempHigh: 1538,
+ stateHigh: "molten_metal_scrap",
+ breakInto: "metal_scrap",
+ hardness: 0.8,
+ conduct: 0.9,
+};
+elements.galvanized_square_steel = {
+ color: "#4a535c",
+ behavior: behaviors.WALL,
+ category: "solids",
+ state: "solid",
+ tempHigh: 1200,
+ stateHigh: "molten_galvanized_square_steel",
+ conduct: 0.5,
+};
+elements.molten_galvanized_square_steel = {
+ color: ["#a14612", "#b0572a", "b35a12", "#b06310"],
+ behavior: behaviors.MOLTEN,
+ category: "states",
+ state: "molten",
+ density: 7065,
+ viscosity: 500,
+ temp: 1200,
+ tempLow: 419,
+ stateLow: "galvanized_square_steel",
+ conduct: 0.5,
+ hidden: true
+};
\ No newline at end of file
diff --git a/mods/logicgates.js b/mods/logicgates.js
index c8e01d18..a88458bc 100644
--- a/mods/logicgates.js
+++ b/mods/logicgates.js
@@ -461,4 +461,40 @@ elements.logic_unshock = {
if (pixel.element == "logic_wire"){pixel.lstate = -2; pixel.color = pixelColorPick(pixel, "#3d4d2c")}
},
excludeRandom: true,
+}
+elements.list_all_wifi = {
+ color: elements.lookup.color,
+ category: "tools",
+ tool: function(){},
+ excludeRandom: true,
+ onSelect: function(){
+ let results = {}
+ for (let i in currentPixels){
+ var otherPixel = currentPixels[i]
+ if (["logic_receiver", "logic_transmitter"].includes(otherPixel.element)){
+ if (otherPixel.channel){
+ if (results[otherPixel.channel]){
+ results[otherPixel.channel].push([otherPixel.x, otherPixel.y])
+ } else {
+ results[otherPixel.channel] = [[otherPixel.x, otherPixel.y]]
+ }
+ }
+ }
+ }
+ console.log(results)
+ let keys = Object.keys(results)
+ let ans1 = prompt(keys.length + " unique channels have been found. Type 1 to list them all.", 1)
+ if(ans1 == "1"){
+ ans2 = prompt("["+keys +"]"+ " These are all the channels found. Type the name of one of them to see the positions of all pixels with that channel.", keys[0])
+ if (keys.includes(ans2)){
+ let finalString = ""
+ for (i in results[ans2]){
+ finalString += ", ["
+ finalString += results[ans2][i]
+ finalString += "]"
+ }
+ alert(finalString)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/mods/minecraft.js b/mods/minecraft.js
index ec64d42e..82c4f9c0 100644
--- a/mods/minecraft.js
+++ b/mods/minecraft.js
@@ -1,116 +1,118 @@
elements.endstone = {
-color: ["#e5edc2", "#bec797"],
-behavior: behaviors.WALL,
-category: "minecraft",
-state: "solid",
-stateHigh: "molten_endstone",
-tempHigh: 1265
+ color: ["#e5edc2", "#bec797"],
+ behavior: behaviors.WALL,
+ category: "minecraft",
+ state: "solid",
+ stateHigh: "molten_endstone",
+ tempHigh: 1265
};
elements.molten_endstone = {
-color: ["#6615d6", "#9651f5", "#d3c3eb"],
-behavior: behaviors.LIQUID,
-category: "minecraft",
-state: "liquid",
-stateLow: "endstone",
-tempLow: 1265,
-temp: 1500,
-viscosity: 1000,
-density: 1025
+ color: ["#6615d6", "#9651f5", "#d3c3eb"],
+ behavior: behaviors.LIQUID,
+ category: "minecraft",
+ state: "liquid",
+ stateLow: "endstone",
+ tempLow: 1265,
+ temp: 1500,
+ viscosity: 1000,
+ density: 1025
};
elements.netherrack = {
-color: ["#8c2a0a", "#783722"],
-behavior: behaviors.WALL,
-category: "minecraft",
-state: "solid",
-tempHigh: 2750,
-stateHigh: "molten_netherrack",
+ color: ["#8c2a0a", "#783722"],
+ behavior: behaviors.WALL,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 2750,
+ stateHigh: "molten_netherrack",
};
elements.glowstone_dust = {
-color: ["#d9d636", "#fffc63", "#a3a12f", "#e0dd3f"],
-behavior: behaviors.POWDER,
-category: "minecraft",
-state: "solid",
-tempHigh: 2500,
-stateHigh: "molten_glowstone",
-conduct: 0.975,
-density: 1075
+ color: ["#d9d636", "#fffc63", "#a3a12f", "#e0dd3f"],
+ behavior: behaviors.POWDER,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 2500,
+ stateHigh: "molten_glowstone",
+ conduct: 0.975,
+ density: 1075
};
elements.molten_netherrack = {
-name: "Nether Magma",
-color: ["#f7f09c", "#faf9eb", "#ffffff", "#dcf7f7", "#86dbdb", "#1268a6"],
-behavior: behaviors.LIQUID,
-category: "minecraft",
-state: "liquid",
-tempLow: 2750,
-stateLow: "netherrack",
-temp: 3000,
-viscosity: 1000,
-density: 2305
+ name: "Nether Magma",
+ color: ["#f7f09c", "#faf9eb", "#ffffff", "#dcf7f7", "#86dbdb", "#1268a6"],
+ behavior: behaviors.LIQUID,
+ category: "minecraft",
+ state: "liquid",
+ tempLow: 2750,
+ stateLow: "netherrack",
+ temp: 3000,
+ viscosity: 1000,
+ density: 2305
};
elements.redstone_dust = {
-color: ["#bf2424", "#f22424", "#a12020"],
-behavior: behaviors.POWDER,
-category: "minecraft",
-state: "solid",
-tempHigh: 1275,
-stateHigh: "liquid_redstone",
-density: 1250
+ color: ["#bf2424", "#f22424", "#a12020"],
+ behavior: behaviors.POWDER,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 1275,
+ stateHigh: "liquid_redstone",
+ density: 1250
};
+/*
behaviors.SOUL_SAND = [
-"SA|SA|SA",
-"XX|XX|XX",
-"SA AND M2|SA AND M1|SA AND M2",
-];
+ "SA|SA|SA",
+ "XX|XX|XX",
+ "SA AND M2|SA AND M1|SA AND M2",
+ ];
+ */
elements.soul_sand = {
-color: ["#91704d", "#704e2b", "#523517"],
-behavior: behaviors.SOUL_SAND,
-category: "minecraft",
-state: "solid",
-tempHigh: 2575,
-stateHigh: "soul_glass",
-density: 1375,
-reactions: {
-"water": { "elem1":"wet_soul_sand", "elem2":null },
-}
+ color: ["#91704d", "#704e2b", "#523517"],
+ behavior: behaviors.SUPPORTPOWDER,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 2575,
+ stateHigh: "soul_glass",
+ density: 1375,
+ reactions: {
+ "water": { "elem1":"wet_soul_sand", "elem2":null },
+ }
};
elements.soul_soil = {
-color: ["#80664b", "#6e553b", "#5c452e"],
-behavior: behaviors.SOUL_SAND,
-category: "minecraft",
-state: "solid",
-tempHigh: 2565,
-stateHigh: "soul_glass",
-density: 1450,
-reactions: {
-"water": { "elem1":"soul_mud", "elem2":null },
-}
+ color: ["#80664b", "#6e553b", "#5c452e"],
+ behavior: behaviors.SUPPORTPOWDER,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 2565,
+ stateHigh: "soul_glass",
+ density: 1450,
+ reactions: {
+ "water": { "elem1":"soul_mud", "elem2":null },
+ }
};
elements.soul_mud = {
-color: "#6e5437",
-behavior: behaviors.POWDER,
-category: "minecraft",
-state: "solid",
-tempHigh: 1985,
-stateHigh: "soul_adobe",
-density: 1585
+ color: "#6e5437",
+ behavior: behaviors.POWDER,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 1985,
+ stateHigh: "soul_adobe",
+ density: 1585
};
elements.soul_glass = {
-color: "#7a90c2",
-behavior: behaviors.WALL,
-category: "minecraft",
-state: "solid",
-tempHigh: 2585,
-stateHigh: "molten_soul_glass",
-density: 1685
+ color: "#7a90c2",
+ behavior: behaviors.WALL,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 2585,
+ stateHigh: "molten_soul_glass",
+ density: 1685
};
elements.wet_soul_sand = {
-color: ["#5c452e", "#856d56"],
-behavior: behaviors.POWDER,
-category: "minecraft",
-state: "solid",
-tempHigh: 150,
-stateHigh: "soul_sand",
-density: 1660,
+ color: ["#5c452e", "#856d56"],
+ behavior: behaviors.POWDER,
+ category: "minecraft",
+ state: "solid",
+ tempHigh: 150,
+ stateHigh: "soul_sand",
+ density: 1660,
};
/* unfinished but near:
Soul Adobe,
@@ -124,3 +126,521 @@ Liquid Redstone,
Soul Flame,
Soul
*/
+let wardenMurderList = ["head", "body", "frog", "worm", "fly", "flea", "fish", "bird", "bee"]
+function playSculk() {
+ var audio = new Audio("https://JustAGenericUsername.github.io/sculk" + Math.floor((Math.random()*6) +1) + ".ogg");
+ audio.play();
+}
+function playShriek() {
+ var audio = new Audio("https://JustAGenericUsername.github.io/shriek" + Math.floor((Math.random()*4) +1) + ".ogg");
+ audio.play();
+}
+function turnIntoSpecific(pixel){
+ newPixel = pixel.storedPixel
+ newPixel.x = pixel.x;
+ newPixel.y = pixel.y;
+ delete newPixel.del;
+ delete newPixel.sculkSpread;
+ delete newPixel.rSeed;
+ let tempPixel = newPixel;
+ pixelMap[pixel.x][pixel.y] = tempPixel
+ currentPixels = currentPixels.filter(a => a.x != pixel.x || a.y != pixel.y); currentPixels.push((tempPixel))
+}
+function findAboveNot(pixel, element){
+ for (let i = pixel.y; i <= (0-height); i--){
+ if (isEmpty(pixelMap[pixel.x][i], true) && element != "air"){
+ return {distance: i, element: "air"}
+ } else if (!(pixelMap[pixel.x][i].element != element)){
+ return {distance: i, element: pixelMap[pixel.x][i].element}
+ }
+ }
+ return {distance: height, element: "edge"}
+}
+function findAboveIs(pixel, element){
+ for (let i = pixel.y; i <= (0-height); i--){
+ if (isEmpty(pixelMap[pixel.x][i], true) && element == "air"){
+ return {distance: i, element: "air"}
+ } else if (!(pixelMap[pixel.x][i].element == element)){
+ return {distance: i, element: element}
+ }
+ }
+ return false
+}
+let canPlaySculk = 0
+let wardenCooldown = 0
+let totalSculk = {
+ sculk: 0,
+ wardens: 0,
+ sensors: 0,
+ shriekers: 0
+}
+elements.sculk = {
+ color: ["#0c1a22", "#0a171d", "#071319", "#030f14", "#000a0f"],
+ behavior: behaviors.SUPPORT,
+ density: 1500,
+ category: "minecraft",
+ tempHigh: 250,
+ stateHigh: "experience",
+ tick: function(pixel){
+ if (!pixel.type){pixel.type = "sculk"}
+ if (!pixel.rSeed && pixel.type == "sculk"){pixel.rSeed = [Math.random(), Math.random()]}
+ if (!pixel.rSeed && pixel.type == "sensor"){
+ pixel.rSeed = true
+ pixel.color = pixelColorPick(pixel, "#112b4d")
+ }
+ if (!pixel.rSeed && pixel.type == "shrieker"){
+ pixel.rSeed = true
+ pixel.color = pixelColorPick(pixel, "#dad6b8")
+ }
+ if (pixel.type == "sculk" && pixel.rSeed[0] < 0.05){
+ pixel.color = "rgb(40, " + (12*Math.sin((0.05*pixelTicks)+(pixel.rSeed[1]*100)) + 201) + ", " + (46*Math.sin((0.1*pixelTicks)+(pixel.rSeed[1]*100))+201) + ")";
+ }
+ if (pixel.type == "sculk"){
+ if (!pixel.storedPixel){pixel.storedPixel = {element: "dirt", color: pixelColorPick({element: "dirt"}), start: pixel.start, temp: pixel.temp, x: pixel.x, y: pixel.y}}
+ if (!pixel.sculkSpread){pixel.sculkSpread = 0}
+ if (Math.random()<0.0001){ pixel.sculkSpread ++}
+ for (var i = 0; i < squareCoords.length; i++) {
+ var x = pixel.x+squareCoords[i][0];
+ var y = pixel.y+squareCoords[i][1];
+ // higher penalty for top/bottom coords, lower for side coords
+ let penalty = 0.9994
+ for (var j = 0; j < squareCoords.length; j++) {
+ var jx = x+squareCoords[j][0];
+ var jy = y+squareCoords[j][1];
+ if (isEmpty(jx,jy,true)) {penalty = 0.8}
+ }
+ if (!isEmpty(x,y,true)) {
+ var newPixel = pixelMap[x][y];
+ if (newPixel.element == "sculk" && newPixel.type == "sculk"){
+ if (pixel.sculkSpread > newPixel.sculkSpread){
+ newPixel.sculkSpread ++
+ pixel.sculkSpread --
+ }
+ } else if (!(["fire", "radiation", "uranium", "plasma", "bless", "god_ray",
+ "experience", "meat", "ash", "cooked_meat", "rotten_meat", "frozen_meat",
+ "cured_meat", "dead_plant", "frozen_plant", "warden", "warden_head", "warden_body",
+ "sculk"].includes(newPixel.element) || wardenMurderList.includes(newPixel.element))){
+ if (Math.random() > (elements[newPixel.element].hardness || 0.2) && Math.random() > penalty && pixel.sculkSpread > 0 && pixel.temp < 80){
+ pixel.sculkSpread --
+ let pixelStorage = newPixel
+ deletePixel(x, y)
+ createPixel("sculk", x, y)
+ pixelMap[x][y].storedPixel = pixelStorage
+ }
+ } else if (["meat", "ash", "cooked_meat", "rotten_meat", "frozen_meat", "cured_meat",
+ "dead_plant", "frozen_plant", "blood", "cell", "cancer"].includes(newPixel.element) && pixel.temp < 80){
+ deletePixel(x, y)
+ pixel.sculkSpread += 3
+ }
+ }
+ }
+ }
+ if (pixel.type == "sensor"){
+ let cCoords = circleCoords(pixel.x, pixel.y, 8)
+ for (var i = 0; i < cCoords.length; i++) {
+ var x = cCoords[i].x
+ var y = cCoords[i].y
+ if (!isEmpty(x, y, true)){
+ if (wardenMurderList.includes(pixelMap[x][y].element)){
+ if (canPlaySculk == 0){playSculk(); canPlaySculk = 4*30}
+ }
+ }
+ }
+
+ }
+ if (pixel.type == "shrieker"){
+ if (canPlaySculk >= 3.7*30 && wardenCooldown == 0){
+ if (isEmpty(pixel.x-1, pixel.y-2, true)){
+ createPixel("warden", pixel.x-1, pixel.y-2)
+ playShriek()
+ wardenCooldown = 15*30
+ }
+ }
+ }
+ let nAirDist = findAboveNot(pixel, "air")
+ if (nAirDist){
+ if (Math.random() < 0.001 && pixel.sculkSpread >= 2 && nAirDist.distance >= 6 && (nAirDist.element == "air"||nAirDist.element == "edge") && totalSculk.sensors < 10 && pixel.type == "sculk"){
+ if (isEmpty(pixel.x, pixel.y-1, true)){
+ createPixel("sculk", pixel.x, pixel.y-1)
+ pixelMap[pixel.x][pixel.y-1].type = "sensor"
+ pixel.sculkSpread -= 2
+ }
+ }
+ else if (Math.random() < 0.0005 && pixel.sculkSpread >= 4 && nAirDist.distance >= 6 && (nAirDist.element == "air"||nAirDist.element == "edge") && totalSculk.shriekers < 4 && pixel.type == "sculk"){
+ if (isEmpty(pixel.x, pixel.y-1, true)){
+ createPixel("sculk", pixel.x, pixel.y-1)
+ pixelMap[pixel.x][pixel.y-1].type = "shrieker"
+ pixel.sculkSpread -= 4
+ }
+ }
+ }
+ },
+ breakInto: "experience",
+}
+const randgrid1 = Array.from({ length: Math.pow(12, 2) }, () => Math.random() * 2 * Math.PI);
+const randgrid2 = Array.from({ length: Math.pow(12, 2) }, () => Math.random() * 2 * Math.PI);
+function xpNoise(weight){
+ const length = randgrid1.length;
+ const weightedGrid = new Array(length);
+
+ for (let i = 0; i < length; i++) {
+ weightedGrid[i] = weightedAverage(randgrid1[i], randgrid2[i], weight);
+ }
+
+ return weightedGrid;
+}
+function weightedAverage(num1, num2, weight){
+ return ((weight * num1)+((1-weight)*num2))
+}
+function getScalingFactor(d1, d2){
+ return Math.min(d1, d2)/6
+}
+function badNoise(C, x, y) {
+ // Helper function to calculate dot product
+ function dotProduct(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+ }
+
+ // Function d
+ function d(index) {
+ return [Math.cos(C[index]), Math.sin(C[index])];
+ }
+
+ // Function f
+ function f(x, y, t) {
+ return x + (y - x) * (6 * t ** 5 - 15 * t ** 4 + 10 * t ** 3);
+ }
+
+ // Function g
+ function g(x, y, z, w) {
+ const dx = x - z;
+ const dy = y - w;
+ return dotProduct([dx, dy], d(z + w * 6 + 1));
+ }
+
+ // Main function h
+ const x0 = Math.floor(x);
+ const x1 = Math.ceil(x);
+ const y0 = Math.floor(y);
+ const y1 = Math.ceil(y);
+
+ const g00 = g(x, y, x0, y0);
+ const g10 = g(x, y, x1, y0);
+ const g01 = g(x, y, x0, y1);
+ const g11 = g(x, y, x1, y1);
+
+ const fx = f(g00, g10, x - x0);
+ const fy = f(g01, g11, x - x0);
+
+ return Math.sqrt(2) * f(fx, fy, y - y0);
+}
+elements.experience = {
+ color: ["#e0fc2c", "#c2f62b", "#a3f02f", "#83e935", "#5ee13d"],
+ behavior: behaviors.SUPERFLUID,
+ density: 1600,
+ category: "minecraft",
+ tick: function(pixel){
+ /*
+ if (typeof pixel.rSeed != "number"){delete pixel.rSeed}
+ if (!pixel.rSeed){pixel.rSeed = Math.random()}
+ */
+ let scaling = getScalingFactor(width, height)
+ pixel.rSeed = badNoise(xpNoise(Math.sin(pixelTicks/30)), pixel.x/scaling, pixel.y/scaling)
+ pixel.color = "rgb(" + 70*(Math.sin((4*Math.PI)*pixelTicks/70 + 3*pixel.rSeed)+2.5) + ", 235, 80)"
+ if (typeof pixel.storedPixel != "undefined" && Math.random() < 0.8){
+ deletePixel(pixel.x, pixel.y)
+ turnIntoSpecific(pixel)
+ return;
+ } else if (pixel.storedPixel){delete pixel.storedPixel}
+ /* // average rseed of neighbors
+ 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)){
+ let otherPixel = pixelMap[x][y]
+ if (otherPixel.element == "experience"){
+ let sum1 = weightedAverage((pixel.rSeed || Math.random()), (otherPixel.rSeed || Math.random()), 0.95)
+ let sum2 = weightedAverage((pixel.rSeed || Math.random()), (otherPixel.rSeed || Math.random()), 0.05)
+ pixel.rSeed = sum1
+ otherPixel.rSeed = sum2
+ pixel.rSeed += (Math.random()/100)-0.005
+ otherPixel.rSeed += (Math.random()/100)-0.005
+ }
+ }
+ }
+ */
+ },
+ glow: true,
+}
+ if (!elements.bless.reactions){elements.bless.reactions = {}}
+ elements.bless.reactions.sculk = {func: turnIntoSpecific, chance: 0.01}
+elements.warden = {
+ color: "#09273f",
+ category: "minecraft",
+ properties: {
+ dead: false,
+ dir: 1,
+ },
+ tick: function(pixel) {
+ if (isEmpty(pixel.x, pixel.y+1)) {
+ createPixel("warden_body", pixel.x, pixel.y+1);
+ pixel.element = "warden_head";
+ }
+ else if (isEmpty(pixel.x, pixel.y-1)) {
+ createPixel("warden_head", pixel.x, pixel.y-1);
+ pixelMap[pixel.x][pixel.y-1].color = pixel.color;
+ pixel.element = "warden_body";
+ pixel.color = pixelColorPick(pixel)
+ }
+ else {
+ deletePixel(pixel.x, pixel.y);
+ }
+ },
+ related: ["warden_body","warden_head"],
+ cooldown: defaultCooldown,
+}
+elements.warden_body = {
+ color: "#030b16",
+ category: "minecraft",
+ hidden: true,
+ density: 1500,
+ state: "solid",
+ conduct: .05,
+ properties: {
+ dead: false,
+ dir: 1,
+ panic: 0
+ },
+ tick: function(pixel) {
+ age = pixelTicks - pixel.start;
+ if (age > 15*30){
+ deletePixel(pixel.x, pixel.y);
+ }
+ if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
+ if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
+ var headpixel = pixelMap[pixel.x][pixel.y-2];
+ if (headpixel.element == "head") {
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
+ }
+ else {
+ swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
+ }
+ }
+ }
+ }
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.dead) {
+ // // Turn into rotten_meat if pixelTicks-dead > 500
+ if (pixelTicks-pixel.dead > 200 && Math.random() < 0.1) {
+ // changePixel(pixel,"rotten_meat");
+ // }
+ deletePixel(pixel.x, pixel.y);
+ return
+ }
+ }
+
+ // Find the head
+ if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == "warden_head") {
+ var head = pixelMap[pixel.x][pixel.y-1];
+ if (head.dead) { // If head is dead, kill body
+ pixel.dead = head.dead;
+ }
+ }
+ else { var head = null }
+ if (pixel.burning) {
+ pixel.panic += 0.1;
+ if (head && pixelTicks-pixel.burnStart > 240) {
+ pixel.color = head.color;
+ }
+ }
+ else if (pixel.panic > 0) {
+ pixel.panic -= 0.1;
+ }
+
+ if (isEmpty(pixel.x, pixel.y-1)) {
+ // create blood if decapitated 10% chance
+ /// if (Math.random() < 0.1 && !pixel.charge) {
+ // createPixel("blood", pixel.x, pixel.y-1);
+ // set dead to true 15% chance
+ // if (Math.random() < 0.15) {
+ pixel.dead = pixelTicks;
+ // }
+ // }
+ }
+ else if (head == null) { return }
+ else if (Math.random() < 0.1*(isEmpty(pixel.x, pixel.y+1) ? 1 : pixel.panic+1)) { // Move 10% chance
+ var movesToTry = [
+ [1*pixel.dir,0],
+ [1*pixel.dir,-1],
+ ];
+ // While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
+ while (movesToTry.length > 0) {
+ var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
+ if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
+ 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(head, head.x+move[0], head.y+move[1]);
+ break;
+ }
+ }
+ }
+ // 15% chance to change direction
+ if (Math.random() < 0.15) {
+ pixel.dir *= -1;
+ }
+ // homeostasis
+ if (pixel.temp > 37) { pixel.temp -= 1; }
+ else if (pixel.temp < 37) { pixel.temp += 1; }
+ }
+
+ },
+ reactions: {}
+},
+elements.warden_head = {
+ color: "#145377",
+ category: "minecraft",
+ hidden: true,
+ density: 1080,
+ state: "solid",
+ conduct: .05,
+ properties: {
+ dead: false
+ },
+ tick: function(pixel) {
+ age = pixelTicks - pixel.start;
+ if (age > 15*30){
+ deletePixel(pixel.x, pixel.y);
+ }
+ doHeat(pixel);
+ doBurning(pixel);
+ doElectricity(pixel);
+ if (pixel.dead) {
+ // Turn into rotten_meat if pixelTicks-dead > 500
+ if (pixelTicks-pixel.dead > 200 && Math.random() < 0.1) {
+ // changePixel(pixel,"rotten_meat");
+ deletePixel(pixel.x, pixel.y);
+ return
+ }
+ }
+
+ // Find the body
+ if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == "warden_body") {
+ var body = pixelMap[pixel.x][pixel.y+1];
+ if (body.dead) { // If body is dead, kill head
+ pixel.dead = body.dead;
+ }
+ }
+ else { var body = null; pixel.dead = pixelTicks }
+
+ 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("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; }
+ },
+ reactions: {}
+}
+for (i = 0; i < wardenMurderList.length; i++){
+ let e = wardenMurderList[i]
+ elements.warden_head.reactions[e] = {elem2: "meat", chance: 0.5}
+ elements.warden_body.reactions[e] = {elem2: "meat", chance: 0.5}
+}
+setInterval(function(){
+ if (canPlaySculk > 0){
+ canPlaySculk --
+ }
+ if (typeof currentPixels != "undefined"){
+ totalSculk = {
+ sculk: 0,
+ wardens: 0,
+ sensors: 0,
+ shriekers: 0
+ }
+ for (let i in currentPixels){
+ let pixel = currentPixels[i]
+ if (pixel.element == "warden_body"){
+ totalSculk.wardens ++
+ } else if (pixel.element == "sculk"){
+ if (pixel.type == "sculk"){
+ totalSculk.sculk ++
+ } else if (pixel.type == "sensor"){
+ totalSculk.sensors ++
+ } else if (pixel.type == "shrieker"){
+ totalSculk.shriekers ++
+ }
+ }
+ }
+ }
+ if (wardenCooldown > 0){
+ wardenCooldown --
+ }
+}, 1000/30)
+let channelVar = "0"
+elements.sculk_wifi_transmitter = {
+ color: "#142c47",
+ category: "minecraft",
+ behaviors: behaviors.WALL,
+ tempHigh: 250,
+ stateHigh: "dirt",
+ hoverStat: function(pixel){
+ return pixel.channel || "unset"
+ },
+ onSelect: function(){
+ let ans1 = prompt("What channel should this transmitter be? Wont work if you do multiple while paused. (This is meant to be used in machinery!)", channelVar||0)
+ channelVar = ans1
+ },
+ tick: function(pixel){
+ if (!pixel.channel){pixel.channel = channelVar}
+ for (let i in currentPixels){
+ let otherPixel = currentPixels[i]
+ if (otherPixel.element == "sculk_wifi_receiver" && otherPixel.channel == pixel.channel){
+ for (var j = 0; j < adjacentCoords.length; j++){
+ let coord = adjacentCoords[j]
+ let x = otherPixel.x + coord[0]
+ let y = otherPixel.y + coord[1]
+ if (!isEmpty(x, y, true)){
+ let neighborPixel = pixelMap[x][y]
+ if (elements[neighborPixel.element].conduct){
+ neighborPixel.charge = pixel.charge
+ }
+ }
+ }
+ }
+ }
+ if (pixel.charge && canPlaySculk <= 0){
+ canPlaySculk = 25
+ playSculk()
+ }
+ doDefaults(pixel)
+ },
+ conduct: 1
+}
+elements.sculk_wifi_receiver = {
+ color: "#142c47",
+ category: "minecraft",
+ behaviors: behaviors.WALL,
+ tempHigh: 250,
+ stateHigh: "dirt",
+ hoverStat: function(pixel){
+ return pixel.channel || "unset"
+ },
+ onSelect: function(){
+ let ans1 = prompt("What channel should this receiver be? Wont work if you do multiple while paused. (This is meant to be used in machinery!)", channelVar||0)
+ channelVar = ans1
+ },
+ tick: function(pixel){
+ if (!pixel.channel){pixel.channel = channelVar}
+ }
+}
\ No newline at end of file
diff --git a/mods/nicer_flame.js b/mods/nicer_flame.js
index a988a719..d69c8c50 100644
--- a/mods/nicer_flame.js
+++ b/mods/nicer_flame.js
@@ -1,7 +1,10 @@
-// Mod that makes fire look better with dark red at the top of the flame
+// RedBirdly's mod that makes fire look better with dark red at the top of the flame
-let topColor = 'rgb(130, 0, 0)';
-let blending = 0.7;
+var topColor = 'rgb(130, 0, 10)';
+var blending = 0.9;
+
+var topColdFireColor = 'rgb(30, 10, 110)';
+var coldFireBlending = 0.9;
function cssColorToRGB(color) {
let rgbMatch = color.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
@@ -24,8 +27,22 @@ elements.fire.tick = function(pixel) {
// Call the original tick function
originalFireTick(pixel);
- if (Math.random()<0.1) {
+ if (Math.random()<0.4) {
let originalColor = pixel.color;
pixel.color = blendColors(originalColor, topColor, blending);
}
};
+
+let originalColdFireTick = elements.cold_fire.tick;
+elements.cold_fire.tick = function(pixel) {
+ // Call the original tick function
+ originalColdFireTick(pixel);
+
+ if (Math.random()<0.4) {
+ let originalColor = pixel.color;
+ pixel.color = blendColors(originalColor, topColdFireColor, coldFireBlending);
+ }
+};
+
+elements.fire.color = ["#ffcb31","#ffab21","#ff9600"];
+elements.cold_fire.color = ["#11ddff","#2288dd"];
diff --git a/mods/periodic_and_more.js b/mods/periodic_and_more.js
new file mode 100644
index 00000000..d032bcee
--- /dev/null
+++ b/mods/periodic_and_more.js
@@ -0,0 +1,64 @@
+
+elements.beryllium = {
+ color: "#b3b3b3",
+ behavior: behaviors.WALL,
+ category: "solids",
+ viscosity: 100000,
+ state: "solid",
+ density: 720,
+ reactions: {
+ water: {elem1: "beryllium", elem2: "dirty_water"}
+ }
+};
+
+ elements.galinstan = {
+ color: "#a9a9a9",
+ behavior: behaviors.LIQUID,
+ category: "liquids",
+ viscosity: 26,
+ state: "liquid",
+ density: 0.026
+ };
+
+
+// Adding behavior presets:
+behaviors.SELFDELETE = [
+ "XX|XX|XX",
+ "XX|DL|XX",
+ "XX|XX|XX",
+];
+
+// Raw JavaScript behaviors:
+behaviors.mud.tick = function(pixel) {
+ if (tryMove(pixel, pixel.x, pixel.y+1)) {
+ console.log("Moved!");
+ }
+ else {
+ console.log("Couldn't move!")
+ }
+};
+
+elements.sand_exploder = {
+ color: "#ff0000",
+ tool: function(pixel) {
+ if (pixel.element == "sand") {
+ pixel.element = "explosion"
+ }
+ },
+ category: "tools",
+};
+
+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() {
+
+ console.log("Hello World!");
+});
+
+// Creating eLists:
+eLists.PERIODIC = ["beryllium", "scandium", "vanadium", "manganese", "cobalt"]
diff --git a/mods/stormlib.js b/mods/stormlib.js
new file mode 100644
index 00000000..83bd2731
--- /dev/null
+++ b/mods/stormlib.js
@@ -0,0 +1,99 @@
+class stormlibRandom {
+ int(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min
+ }
+
+ max(max) {
+ let treturn = Math.floor(Math.random() * max)
+ if (treturn !== 0) {
+ return treturn +1
+ } else {
+ return treturn
+ }
+ }
+
+ option(array) {
+ if (array.length < 1) return null;
+ return array[this.int(0, array.length -1)]
+ }
+
+ string(length = 8, disallowed = ['☭']) {
+ let chars = [
+ 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G',
+ 'h', 'H', 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N',
+ 'o', 'O', 'p', 'P', 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U',
+ 'v', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z', 'Z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+',
+ '[', ']', '{', '}', '\\', '|', ';', ':', '\'', '"', ',', '.', '/', '<',
+ '>', '?', '`', '~'
+ ]
+
+ let str = ''
+
+ while (str.length < length) {
+ let char = this.option(chars)
+ if (!disallowed.includes(char)) {
+ str += char
+ }
+ }
+
+ return str
+ }
+}
+
+class stormlibElement {
+ exists(name) {
+ return elements.hasOwnProperty(name)
+ }
+}
+
+class stormlibColor {
+ lighten(hex, percent = 10) {
+ let rgb = hexToRGB(hex)
+ if (rgb == null) return '#ffffff';
+ let r = rgb.r
+ let g = rgb.g
+ let b = rgb.b
+
+ r = Math.min(255, Math.floor(r + (255 - r) * (percent / 100)));
+ g = Math.min(255, Math.floor(g + (255 - g) * (percent / 100)));
+ b = Math.min(255, Math.floor(b + (255 - b) * (percent / 100)));
+
+ return RGBToHex({r: r, g: g, b: b})
+ }
+
+ darken(hex, percent = 10) {
+ let rgb = hexToRGB(hex)
+ if (rgb == null) return '#000000';
+ let r = rgb.r
+ let g = rgb.g
+ let b = rgb.b
+
+ r = Math.max(0, Math.floor(r * (1 - percent / 100)));
+ g = Math.max(0, Math.floor(g * (1 - percent / 100)));
+ b = Math.max(0, Math.floor(b * (1 - percent / 100)));
+
+ return RGBToHex({r: r, g: g, b: b})
+ }
+}
+
+class stormlibPixels {
+ create(x, y, color) {
+ let canvas = document.getElementById('game')
+ if (x < canvas.width && y < canvas.height) {
+ let old = ctx.fillStyle
+ ctx.fillStyle = color
+ ctx.fillRect(x, y, pixelSize, pixelSize)
+ }
+ }
+}
+
+let Elements = new stormlibElement
+let Random = new stormlibRandom
+let Color = new stormlibColor
+let Pixels = new stormlibPixels
+
+setInterval(() => {
+ Pixels.create(85, 45, '#ff0000')
+}, 1000/tps)
\ No newline at end of file
diff --git a/mods/wifi_draw.js b/mods/wifi_draw.js
index 4590ccaa..bd20c247 100644
--- a/mods/wifi_draw.js
+++ b/mods/wifi_draw.js
@@ -75,3 +75,4 @@ drawPixels = function(forceTick=false) {
updateLogicLists();
drawLinks();
};
+resetInterval(tps);