diff --git a/mod-list.html b/mod-list.html
index 2298a079..0b5c089c 100644
--- a/mod-list.html
+++ b/mod-list.html
@@ -288,7 +288,7 @@
| amogus.js | Adds a small amogus structure | Alice |
| citybuilding.js | Adds seeds that create miniature buildings and other city-related items | SquareScreamYT |
| collab_mod.js | Created by multiple people, adds random things | mrapple, ilikepizza, stefanblox |
-| Doom Mod (Unreleased) | As seen on TikTok - Not yet available! | ggod |
+| doom.js | As seen on TikTok - Select the Doom element to start, WASD | ggod |
| elem3.js | Adds all elements and combinations from Elemental 3 [Very Large] | Sophie |
| fools+.js | improves and makes fools.js EXTREMELY annoying. | SquareScreamYT |
| funny elements 2022-11-15.js | Adds a few curated randomly-generated elements | Alice |
diff --git a/mods/Science_mod.js b/mods/Science_mod.js
index 7f75597b..3b4b9a49 100644
--- a/mods/Science_mod.js
+++ b/mods/Science_mod.js
@@ -1,8 +1,14 @@
// Science mod for Sandboxels
// (Inspired by survival.js)
-// Build 26 (version alpha 0.0.26)
-console.log("version alpha 0.0.26")
-console.log("build 26")
+// Build 37 (version alpha 0.0.37)
+console.log("Version alpha 0.0.37")
+console.log("Build 37")
+console.log("If you see something that is alumium and not aluminium, just dm me on discord (this is a british/welsh mod aight)")
+console.log("THIS IS NOT DONE")
+// You'll see a lot more of my school account
+// Read comment at line 1523 for information on what I mean by null/NULL
+// This used to be a full time thing, but now it's basically just half-time now.
+// It has been confirmed, I am getting a pc on 25/06/2024 :D (I'm also going to be animating for my friends movies that are coming out soon)
// If there is anything you want to suggest or there's a bug then just dm me on discord (@a_british_proto)
// I've decided to start doing this project on my schools computer's (because they don't crash all the time) so there will be long delays in updates, sorry!
// Todo:
@@ -1537,3 +1543,249 @@ substance.Aluminum_Chlorate_Nonahydrate= {
state: "null",
hidden:true
}
+
+substance.Aluminum_Perchlorate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Potassium_Tetrachloroaluminate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+// Finally one I can actually do!
+substance.Lithium_Tetrachloroaluminate = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+// Nvm, back to null
+substance.Sodium_Tetrachloroaluminate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Titanium_Chloride_Aluminum_Chloride = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Cesium_Fluoroaluminate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Aluminum_Cesium_Sulfate_Dodecahydrate = {
+ behavior:behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+// Tf is this, I'm probs going to delete it later as i have no idea what it is
+substance.Devarda’s_Alloy = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",#
+ hidden:true
+}
+
+substance.Lithium_Aluminum_Deuteride = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+// Finally another one! Thank the ptable.com gods! :skull:
+substance.Aluminum_Floride = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+// AAAAAAAAAAAAAAAAAAAAAAAAAAA
+substance.aluminum_Fluoride_Trihydrate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+// aight, i give up on the comments now but this is one that I can actually do
+substance.Ammonium_Hexafluoroaluminate = {
+ behavior: behaviors.POWDER,
+ color: "FFFFFF",
+ category: "lands",
+ state: "powder",
+ hidden:true
+}
+
+substance.Potassium_Hexafluoroaluminate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Sodium_Hexafluoroaluminate = {
+ behavior: behaviors.POWDER,
+ color: "FFFFFF",
+ category: "lands",
+ state: "powder",
+ hidden:true
+}
+
+substance.Sodium_Phosphoaluminate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true,
+}
+
+substance.Aluminum_Hypophosphite = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Aluminum_Hydroxide = {
+ behavior: behaviors.POWDER,
+ color: "FFFFFF",
+ category: "lands",
+ state: "powder",
+ hidden:true
+}
+
+substance.Aluminum_Metasophate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Lithium_Aluminium_Hydride = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+substance.Sodium_Aluminium_Hydride = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+substance.Strontium_Lanthanum_Aluminate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Aluminum_Nitrate_Nonahydrate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Aluminium_Nitrate = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+substance.Potassium_Aluminum_Sulfate_Dodecahydrate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Alum = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+substance.Kalinite = {
+ behavior: behaviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solid",
+ hidden:true
+}
+
+substance.Potassium_Alum = {
+ behavior: behaviors.POWDER,
+ color: "FFFFFF",
+ category: "lands",
+ state: "powder",
+ hidden:true
+}
+
+substance.Sodium_Alum = {
+ behavior: behaviors.POWDER,
+ color: "FFFFFF",
+ category: "lands",
+ state: "powder",
+ hidden:true
+}
+
+substance.Aluminum_Ammonium_Sulfate_Dodecahydrate = {
+ behavior: behaviors.NULL,
+ color: "000000",
+ category: "null",
+ state: "null",
+ hidden:true
+}
+
+substance.Ammonium_Aluminium_Sulfate = {
+ behavior: beahviors.WALL,
+ color: "FFFFFF",
+ category: "lands",
+ state: "solids",
+ hidden:true
+}
diff --git a/mods/a_mod_by_alice.js b/mods/a_mod_by_alice.js
index 8e1235df..9149d9ff 100644
--- a/mods/a_mod_by_alice.js
+++ b/mods/a_mod_by_alice.js
@@ -171,6 +171,15 @@ try {
throw new TypeError(`Unexpected type: ${typeof(stringOrArray)}`);
};
};
+ //Shuffle not-in-place
+ function arrayToShuffled(array) {
+ var _array = structuredClone ? structuredClone(array) : JSON.parse(JSON.stringify(array));
+ for (let i = _array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [_array[i], _array[j]] = [_array[j], _array[i]];
+ };
+ return _array
+ };
//Checks
//Element exists in the elements object
function elementExists(elementName) {
@@ -391,6 +400,10 @@ try {
function addTwoNumbers(number1,number2) { //reducer
return number1 + number2
}
+ //Linear interpolation
+ function lerp(a,b,t) {
+ return (b * t) + (a * (1 - t))
+ };
//Logistic curve
//x = real number
//L = maximum value
@@ -1747,6 +1760,16 @@ try {
function getCirclePixels(x,y,radius) {
return circleCoords(x,y,radius).map(coordinates => pixelMap[coordinates.x]?.[coordinates.y]).filter(function(pixelOrUndefined) { return typeof(pixelOrUndefined) == "object" })
};
+ function getPixelsInRegion(x1,y1,x2,y2) {
+ var result = [];
+ for(var x = x1; x <= x2; x++) {
+ for(var y = y1; y <= y2; y++) {
+ var p = pixelMap[x]?.[y];
+ if(p && !(p.del)) { result.push(p) }
+ }
+ };
+ return result
+ };
function getPixelMooreNeighbors(pixel) {
var coordsToCheck = mooreDonutCoords.map(function(offsets) { return {x: offsets[0]+pixel.x, y: offsets[1]+pixel.y} } );
var neighbors = [];
@@ -2323,7 +2346,11 @@ td.inputCell {
sweepingLaserRotationSpeed: -0.03,
sweepingLaserBeamLength: 10,
sweepingLaserBeamTemperature: 2000,
- sweepingLaserBeamBrevity: 5
+ sweepingLaserBeamBrevity: 5,
+ noteBlockFrequency: 440,
+ noteBlockLength: 1,
+ noteBlockVolume: 1,
+ noteBlockDelay: 0
};
hidePropertySetter();
@@ -4056,15 +4083,19 @@ color1 and color2 spread through striped paint like dye does with itself. col
quickSlDetectorLastKeys = [];
};
});
+ /*if(urlParams.get("pause") !== null) {
+ paused = true;
+ document.getElementById("pauseButton").setAttribute("on","true")
+ };*/
gameLoaded = true;
};
//MORE CONFIGURABLE EXPLOSIONS (explodeAtPlus) ##
velocityBlacklist = [];
function explodeAtPlus(x,y,radius,firee="fire",smokee="smoke",beforeFunction=null,afterFunction=null,changeTemp=true) {
- var message = "Explosion ";
+ //var message = "Explosion ";
var pixel = pixelMap[x]?.[y];
- if(pixel) { message += `of ${pixel.element} ` };
- message += `with radius ${radius} at (${x},${y})`;
+ //if(pixel) { message += `of ${pixel.element} ` };
+ //message += `with radius ${radius} at (${x},${y})`;
// if fire contains , split it into an array
if(firee !== null) {
if (firee.indexOf(",") !== -1) {
@@ -4078,6 +4109,7 @@ color1 and color2 spread through striped paint like dye does with itself. col
};
var coords = circleCoords(x,y,radius);
var power = radius/10;
+ changePressure(x,y,radius ** 2,operationType="+",true);
//for (var p = 0; p < Math.round(radius/10+1); p++) {
for (var i = 0; i < coords.length; i++) {
var fire = firee;
@@ -5461,6 +5493,7 @@ color1 and color2 spread through striped paint like dye does with itself. col
}
//FIND MODE, PIXEL PROPERTIES LINKED TO SPECIAL CODE, CONFIGURABLE VISUAL DISTORTION AND VISUAL PIXEL SHAPE SETTINGS (acid_and_shapes.js) ##
//two separate things i.e. not "pixel properties linked to special code, configurable visual distortion, and visual pixel shape settings" though there's basically no semantic difference
+ //And also all other changes to drawPixels
var style = document.createElement('style');
style.type = 'text/css';
style.id = 'findStatusStylesheet';
@@ -5740,6 +5773,8 @@ color1 and color2 spread through striped paint like dye does with itself. col
}
};
+ console.log("1/8 loaded") //True 1.8 is inside one viewColorFunctions[2]
+
hiding = false
runAfterAutogen(function() {
@@ -5806,6 +5841,35 @@ color1 and color2 spread through striped paint like dye does with itself. col
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
if(!hiding) {
+ if(settings.dopressure && settings.drawpressure) {
+ for(var x = 0; x < pressureMap.length; x++) {
+ for(var y = 0; y < pressureMap[x].length; y++) {
+ var pressureValue = pressureMap[x][y];
+ if(typeof(pressureValue) == "number") {
+ var pressureSign = Math.sign(pressureValue);
+ pressureValue = bound(Math.abs(pressureValue),0,255) / 255;
+ switch(pressureSign) {
+ case -0:
+ case 0:
+ ctx.fillStyle = `rgb(0,0,0)`;
+ break
+ case 1:
+ ctx.fillStyle = `rgb(255,0,0)`;
+ break
+ case -1:
+ ctx.fillStyle = `rgb(0,0,255)`;
+ break
+ default: // covers NaN, since NaN != NaN
+ ctx.fillStyle = `rgb(255,255,0)`;
+ break
+ };
+ ctx.globalAlpha = isNaN(pressureSign) ? 0.5 : pressureValue;
+ ctx.fillRect(x*pixelSize*pressureCellSize, y*pixelSize*pressureCellSize, pixelSize*pressureCellSize, pixelSize*pressureCellSize)
+ }
+ }
+ }
+ ctx.globalAlpha = 1;
+ };
var pixelDrawList = pixelsFirst.concat(pixelsLast);
for (var i = 0; i < pixelDrawList.length; i++) {
var pixel = pixelDrawList[i];
@@ -6135,6 +6199,48 @@ color1 and color2 spread through striped paint like dye does with itself. col
rankineSettingSpan.appendChild(settingInput);
rankineSettingSpan.appendChild(newHelpMark);
acidSettingSpan.after(rankineSettingSpan);
+ var pressureSettingSpan = document.createElement("span");
+ pressureSettingSpan.setAttribute("setting","dopressure");
+ pressureSettingSpan.setAttribute("title","Default: OFF");
+ pressureSettingSpan.classList.add("setting-span","multisetting");
+ var settingInput = document.createElement("input");
+ settingInput.setAttribute("type","button");
+ settingInput.setAttribute("value",'Pressure simulation');
+ settingInput.setAttribute("state","0");
+ settingInput.classList.add("toggleInput");
+ settingInput.setAttribute("onclick","toggleInput(this,'dopressure',false)");
+ var options = {
+ "false": "Disabled",
+ "true": "Enabled"
+ };
+ var newHelpMark = document.createElement("span");
+ newHelpMark.setAttribute("title","Simplified pressure simulation (which may lag).");
+ newHelpMark.classList.add("helpMark");
+ newHelpMark.innerText = "?";
+ pressureSettingSpan.appendChild(settingInput);
+ pressureSettingSpan.appendChild(newHelpMark);
+ rankineSettingSpan.after(pressureSettingSpan);
+ var showPressureSettingSpan = document.createElement("span");
+ showPressureSettingSpan.setAttribute("setting","drawpressure");
+ showPressureSettingSpan.setAttribute("title","Default: OFF");
+ showPressureSettingSpan.classList.add("setting-span","multisetting");
+ var settingInput = document.createElement("input");
+ settingInput.setAttribute("type","button");
+ settingInput.setAttribute("value",'Show pressure');
+ settingInput.setAttribute("state","0");
+ settingInput.classList.add("toggleInput");
+ settingInput.setAttribute("onclick","toggleInput(this,'drawpressure',false)");
+ var options = {
+ "false": "Disabled",
+ "true": "Enabled"
+ };
+ var newHelpMark = document.createElement("span");
+ newHelpMark.setAttribute("title","Draw pressure (only applies if pressure simulation is enabled).");
+ newHelpMark.classList.add("helpMark");
+ newHelpMark.innerText = "?";
+ showPressureSettingSpan.appendChild(settingInput);
+ showPressureSettingSpan.appendChild(newHelpMark);
+ pressureSettingSpan.after(showPressureSettingSpan);
var sizeSetting = document.querySelector('span[setting="pixelsize"]');
var sizeDropdown = sizeSetting.querySelector("select");
sizeDropdown.setAttribute("onchange","var size = (this.value === 'null' ? null : parseFloat(this.value)); console.log(size); if((size >= 0.05) && (size <= 194.73749999999999) && (size !== null) && (size !== false) && !(isNaN(size))) { console.log(size); setSetting('pixelsize',size);this.nextElementSibling.innerText='Reset Scene' }");
@@ -9207,6 +9313,7 @@ color1 and color2 spread through striped paint like dye does with itself. col
//if(pixelTicks == pixel.start) { console.log("this range",pixel.range) };
if(pixel.range <= 0) { deletePixel(pixel.x,pixel.y); return };
var range = (pixel.range ?? (ambaPlaceProperties?.blackHoleRange ?? 15)) * 2;
+ if(settings.dopressure) { changePressure(pixel.x,pixel.y,10 + ((range / 2) ** 2),"-",true) };
var targets = mouseLikeRange(pixel.x,pixel.y,range,"circle",true);
shuffleArray(targets);
for (var i = 0; i < targets.length; i++) {
@@ -9256,7 +9363,7 @@ color1 and color2 spread through striped paint like dye does with itself. col
var taxicabDistance = Math.abs(newPixel.x - pixel.x) + Math.abs(newPixel.y - pixel.y);
if((taxicabDistance <= 3) && (taxicabDistance > 0)) {
pixel.temp += (newPixel.temp - (settings.abszero ?? 273.15));
- if(["amba_black_hole","amba_white_hole"].includes(newPixel.element) && (newPixel.range ?? 15) > 0) {
+ if(["amba_black_hole","amba_white_hole"].includes(newPixel.element) && ((newPixel.range ?? 15) > 0) && (newPixel !== pixel)) {
//console.log("adding range on tick",pixelTicks);
pixel.range ??= (ambaPlaceProperties?.blackHoleRange ?? 15);
var rangeChange = (newPixel.range ?? (ambaPlaceProperties?.blackHoleRange ?? 15));
@@ -9378,6 +9485,29 @@ color1 and color2 spread through striped paint like dye does with itself. col
maxSize: 1
};
+ elements.pus = {
+ color: "#bfba71",
+ behavior: behaviors.LIQUID,
+ reactions: {
+ "water": { elem1:["pus","pus","pus","pus","pus","pus","dirty_water"], elem2:"dirty_water", chance:0.01 },
+ "blood": { elem1:["pus","pus","pus","pus","pus","pus","infection"], elem2:"infection", chance:0.01 },
+ "poison": { elem1:"bio_ooze", elem2:"bio_ooze", chance:0.2 },
+ "bio_ooze": { elem1:"bio_ooze", chance:0.2 },
+ "frog": { elem2:"rotten_meat", chance:0.005 },
+ "fish": { elem2:"rotten_meat", chance:0.005 },
+ "meat": { elem2:"rotten_meat", chance:0.005 },
+ "alcohol": { elem1:"dirty_water", chance:0.2 }
+ },
+ viscosity: 30,
+ tempHigh: 124.55,
+ stateHigh: ["plague","stench","steam","steam","steam","salt"],
+ tempLow: -2,
+ category:"liquids",
+ hidden: true,
+ state: "liquid",
+ density: 1100,
+ stain: 0.08
+ };
//ASSORTED RAINBOW VARIANTS ##
elements.concoction.reactions.diorite_gravel = {
elem1: "static", elem2: null
@@ -11155,6 +11285,7 @@ color1 and color2 spread through striped paint like dye does with itself. col
density: 182,
temp: -20,
}
+ console.log("1/4 loaded")
//Volatile Roseyiede
elements.explosive_roseyiede = {
color: "#986118",
@@ -13138,6 +13269,9 @@ color1 and color2 spread through striped paint like dye does with itself. col
version: 1,
enabledMods: localStorage.enabledMods
};
+ if(settings.dopressure) {
+ simulationState.pressureMap = pressureMap
+ };
for(i = 0; i < simulationState.pixelMap.length; i++) {
var column = simulationState.pixelMap[i];
for(j = 0; j < column.length; j++) {
@@ -13371,6 +13505,7 @@ color1 and color2 spread through striped paint like dye does with itself. col
}
saveSettings
};
+ if((settings.dopressure) && json.pressureMap) { pressureMap = json.pressureMap };
//enabledMods handling {
var enMods = "[]";
if(typeof(json.enabledMods) !== "undefined") {
@@ -13498,6 +13633,9 @@ Pixel size (rendering only): (Use if the save looks cut o
if(enabledMods.includes("mods/betterStats.js") && typeof(realTps) !== "undefined") { stats += "" + realTps + "tps" }; //i'm sorry but there's no other way to add compatibility
//THAT CODE WAS MADE BY MOLLTHECODER FROM THEIR betterStats.js MOD
stats += "" + pixelTicks+"";
+ if((settings.dopressure) && (typeof(width) == "number") && (!(outOfBounds(mousePos.x,mousePos.y)))) {
+ stats += "P:" + getPressureAtPixelCoords(mousePos.x,mousePos.y).toFixed(2).replace(/\.?0+$/,"")+"";
+ };
if ((typeof pixelMap).length === 9) { return; }
if (pixelMap[mousePos.x] !== undefined) {
var currentPixel = pixelMap[mousePos.x][mousePos.y];
@@ -16336,13 +16474,13 @@ Pixel size (rendering only): (Use if the save looks cut o
return elements[e].category == "life";
})
});
- elements.bioooze = {
+ elements.bio_ooze = { //a.k.a. the water in the River Thames during July and August of 1858
+ name: "Bio-Ooze",
color: ["#53FF4F", "#53FF4F", "#06DE00", "#04A600", "#036E00"],
behavior: behaviors.LIQUID,
tempHigh: 100,
stateHigh: ["plague","slime","steam","poison"],
- //tempLow: -4,
- //stateLow: "bioooze_ice",
+ tempLow: -4,
category: "liquids",
heatCapacity: 3.52, //unimplemented feature
name: "bio-ooze",
@@ -16353,34 +16491,34 @@ Pixel size (rendering only): (Use if the save looks cut o
//"elder_fluid": { "elem1":"corrupt_slime" }, //acid should be sulfuric acid and product should be wastestone
//"mercury": { "elem1":"liquid_protocite" }, //acid should be sulfuric acid and product should be wastestone
//"blue_grav_liquid": { "elem1":"blue_grav_liquid" }, //bgl would set gravity to upwards gravity
- "blood": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "infection" },
+ "blood": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "infection" },
"soap": { "elem1": "slime", "chance": 0.02 },
- "plant": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "grass": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "algae": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "mushroom_spore": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "lichen": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "rat": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "frog": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "fish": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "bird": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "head": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "body": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "ant": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "dust" },
- "worm": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "dust" },
- "fly": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "dust" },
- "firefly": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "dust" },
- "bee": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "dust" },
- "slug": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "dust" },
- "snail": { "elem1": ["bioooze","bioooze","bioooze","bioooze","poison","slime",null], "elem2": "calcium" },
- "sapling": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "root": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "flower_seed": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "pistil": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "petal": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "grass_seed": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "dead_plant" },
- "meat": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "rotten_meat" },
- "wood": { "elem1": ["bioooze","bioooze","poison","slime",null], "elem2": "sawdust", "chance": 0.25 }
+ "plant": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "grass": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "algae": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "mushroom_spore": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "lichen": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "rat": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "frog": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "fish": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "bird": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "head": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "body": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "ant": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
+ "worm": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
+ "fly": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
+ "firefly": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
+ "bee": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
+ "slug": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "dust" },
+ "snail": { "elem1": ["bio_ooze","bio_ooze","bio_ooze","bio_ooze","poison","slime",null], "elem2": "calcium" },
+ "sapling": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "root": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "flower_seed": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "pistil": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "petal": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "grass_seed": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "dead_plant" },
+ "meat": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "rotten_meat" },
+ "wood": { "elem1": ["bio_ooze","bio_ooze","poison","slime",null], "elem2": "sawdust", "chance": 0.25 }
},
/*reactions: {
"dirt": { // React with (water reacts with dirt to make mud)
@@ -16799,6 +16937,7 @@ Pixel size (rendering only): (Use if the save looks cut o
category: "gases",
state: "gas"
},
+ console.log("3/8 loaded");
elements.cold_ash_cloud = {
color: ["#af8f50","#ab9c50","#af6d50"],
behavior: [
@@ -19227,7 +19366,7 @@ Pixel size (rendering only): (Use if the save looks cut o
conduct: 0.23,
};
elements.haseulite_gas = {
- color: ["#ffff9d", _cc.w.h, "#e9ffe6", "#ffffe5"],
+ color: ["#ffff9d", _cc.w.h, "#e9ffe6", "#ffffe5"],
fireColor: ["#08a953", "#2ea332", "#d1e0d3"],
properties: {
oldColor: null
@@ -19376,7 +19515,7 @@ Pixel size (rendering only): (Use if the save looks cut o
conduct: 0.22,
};
elements.heejinite_gas = {
- color: ["#fffab8", "#ffdab3", "#ffd1d1", "#ffc4df", "#ffb0eb"],
+ color: ["#fffab8", "#ffdab3", "#ffd1d1", "#ffc4df", "#ffb0eb"],
fireColor: ["#a9085e", "#a32e61", "#fca7c6"],
properties: {
oldColor: null
@@ -19652,7 +19791,7 @@ Pixel size (rendering only): (Use if the save looks cut o
conduct: 0.34,
};
elements.jinsoulite_gas = {
- color: ["#c0f0ef", "#c2c1db", "#c0bff5", "#cdcce6"],
+ color: ["#c0f0ef", "#c2c1db", "#c0bff5", "#cdcce6"],
behavior: [
"XX|CR:steam%0.5|XX",
"CR:steam%0.5|XX|CR:steam%0.5",
@@ -19832,7 +19971,7 @@ Pixel size (rendering only): (Use if the save looks cut o
conduct: 0.22,
};
elements.yvesite_gas = {
- color: ["#e34070", "#d13060", "#c2234a", "#db4866"],
+ color: ["#e34070", "#d13060", "#c2234a", "#db4866"],
fireColor: ["#b5103f", "#ab3254", "#cc2157", "#ba0936"],
behavior: behaviors.GAS,
state: "gas",
@@ -20154,8 +20293,8 @@ Pixel size (rendering only): (Use if the save looks cut o
stain: 0.04
};
elements.vivite_gas = {
- color: ["#ffedfe", "#ffe0fd", "#ffd9f9", "#ffd1f0", "#ffccdf"],
- colorOn: ["#eec7fc", "#f5b1fc", "#faa2f1", "#fa93c3", "#ff99b1"],
+ color: ["#ffedfe", "#ffe0fd", "#ffd9f9", "#ffd1f0", "#ffccdf"],
+ colorOn: ["#eec7fc", "#f5b1fc", "#faa2f1", "#fa93c3", "#ff99b1"],
fireColor: ["#ff66ba", "#ff85ef", "#ff99f7"],
tick: function(pixel) {
if(Math.random() < 0.032 && exposedToAir(pixel)) {
@@ -22914,6 +23053,7 @@ Pixel size (rendering only): (Use if the save looks cut o
};
rockClouds.push(rockCloudName);
};
+ console.log("1/2 loaded") //true halfway point is inside newIgneousCompositionFamily.
function standaloneBrokenFormMaker(elementName,suffixWithoutUnderscore,addBreakIntoToSourceElement=false,category=null,density=null,tempHigh=null,stateHigh=null,breakInto=null) {
var newName = elementName + "_" + suffixWithoutUnderscore;
elements[newName] = {
@@ -26102,7 +26242,7 @@ Pixel size (rendering only): (Use if the save looks cut o
//Metamorphism will be driven using solely temperature.
//Pressure simulation, due to how the game is coded, will be limited to requiring the rock to be surrounded.
elements.slate = {
- color: ["#787B80", "#535557", "#695E58", "#696969", "#6B5D5B"],
+ color: ["#787B80", "#535557", "#695E58", "#696969", "#6B5D5B"],
tempHigh: 200,
stateHigh: "felsic_magma",
category: "solid rock",
@@ -28087,6 +28227,7 @@ Make sure to save your command in a file if you want to add this preset again.`
desc: "Click here or press Shift+1 to open the command prompt.",
category:"special",
};
+ console.log("5/8 loaded");
//REPLACER TOOL ##
changeTo = "sand";
document.addEventListener("keydown", function(e) { //change prompt listener
@@ -28593,7 +28734,7 @@ Make sure to save your command in a file if you want to add this preset again.`
elements.bless.reactions.toxin = { elem2: "antidote" };
elements.bless.reactions.dead = { elem2: null };
elements.bless.reactions.brain = { elem2: null };
- elements.bless.reactions.bioooze = { elem2: null };
+ elements.bless.reactions.bio_ooze = { elem2: null };
elements.bless.tool = function(pixel) {
if (elements.bless.ignore.indexOf(pixel.element) !== -1) { return; }
if (pixel.burning) { // stop burning
@@ -33872,6 +34013,7 @@ Make sure to save your command in a file if you want to add this preset again.`
};
},
};
+ console.log("3/4 loaded"); //the real 3/4 point was inside Nothing There's tick function
runAfterLoad(function() {
if(typeof(badPixels) === "object") {
badPixels.nothing_there_phase_1 = { panicIncrease: 1, panicIncreaseChance: 1 } //insta-panic for "aleph" thing and "level 1" humans
@@ -36355,7 +36497,7 @@ Make sure to save your command in a file if you want to add this preset again.`
amalgamatedBombFire += ",resonant_ender".repeat(5);
amalgamatedBombFire += ",foof".repeat(8);
amalgamatedBombFire += ",liquid_irradium".repeat(7);
- amalgamatedBombFire += ",bioooze".repeat(8);
+ amalgamatedBombFire += ",bio_ooze".repeat(8);
});
//Fairies
runAfterLoad(function() {
@@ -39390,6 +39532,7 @@ Make sure to save your command in a file if you want to add this preset again.`
category: "machines",
hardness: 0.6
};
+ console.log("7/8 loaded"); //it was inside the weather controller code
//KETCUP ##
elements.ketcup = {
color: "#ab2513",
@@ -41622,10 +41765,14 @@ Make sure to save your command in a file if you want to add this preset again.`
elements.molten_steel ??= {};
elements.molten_steel.tempHigh = 2727;
elements.molten_steel.stateHigh = ["molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","molten_iron","carbon"]; //it may be FAR LESS than that irl; sus-304 steel has 0.08%
- elements.carbon.reactions ??= {};
- elements.carbon.reactions.molten_iron = {
- elem1: ["carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon",null],
- elem2: "molten_steel"
+ if(elements.carbon) {
+ elements.carbon.reactions ??= {};
+ elements.carbon.reactions.molten_iron = {
+ elem1: ["carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon","carbon",null],
+ elem2: "molten_steel"
+ }
+ } else {
+ logMessage("The mod that adds carbon failed to load in time. This is likely due to a race condition in the way Sandboxels applies mods, and not the fault of said mod's author, and will usually be fixed by reloading")
};
elements.support_steel = {
color: elements.steel.color,
@@ -42176,7 +42323,7 @@ Make sure to save your command in a file if you want to add this preset again.`
audioObject[oscillatorNodeName].connect(audioObject[gainNodeName])
audioObject[oscillatorNodeName].frequency.value = parameterObject.frequency
audioObject[gainNodeName].connect(audioContext.destination)
- audioObject[oscillatorNodeName].start(audioContext.currentTime + parameterObject.delay)
+ audioObject[oscillatorNodeName].start(audioContext.currentTime + (parameterObject.delay))
//stopping handler
if(parameterObject.endType === "exponential") { //starts fading immediately
audioObject[gainNodeName].gain.exponentialRampToValueAtTime(
@@ -42200,16 +42347,71 @@ Make sure to save your command in a file if you want to add this preset again.`
breakInto: ["plastic","metal_scrap","metal_scrap","metal_scrap"],
conduct: 1,
properties: {
- frequency: 440,
type: "sine",
endType: "none",
- length: 1,
- volume: 1,
- delay: 0,
debounce: 0,
debounceLength: tps
},
+ onSelect: function() {
+ showPropertySetter();
+
+ showSetterColumn("numeric",0);
+ var p0 = document.getElementById("propertynumeric0input");
+ var p0h = document.getElementById("propertynumeric0heading");
+ if(p0) {
+ p0.setAttribute("set","noteBlockFrequency");
+ p0.setAttribute("min","1");
+ p0.value = ambaPlaceProperties.noteBlockFrequency;
+ };
+ if(p0h) {
+ p0h.innerText = "Frequency";
+ };
+
+ showSetterColumn("numeric",1);
+ var p1 = document.getElementById("propertynumeric1input");
+ var p1h = document.getElementById("propertynumeric1heading");
+ if(p1) {
+ p1.setAttribute("set","noteBlockLength");
+ p1.setAttribute("min","0");
+ p1.value = ambaPlaceProperties.noteBlockLength;
+ };
+ if(p1h) {
+ p1h.innerText = "Length";
+ };
+
+ showSetterColumn("numeric",2);
+ var p2 = document.getElementById("propertynumeric2input");
+ var p2h = document.getElementById("propertynumeric2heading");
+ if(p2) {
+ p2.setAttribute("set","noteBlockVolume");
+ p2.setAttribute("min","0");
+ p2.value = ambaPlaceProperties.noteBlockVolume;
+ };
+ if(p2h) {
+ p2h.innerText = "Volume";
+ };
+
+ showSetterColumn("numeric",3);
+ var p3 = document.getElementById("propertynumeric3input");
+ var p3h = document.getElementById("propertynumeric3heading");
+ if(p3) {
+ p3.setAttribute("set","noteBlockDelay");
+ p3.setAttribute("min","0");
+ p3.value = ambaPlaceProperties.noteBlockDelay;
+ };
+ if(p3h) {
+ p3h.innerText = "Delay";
+ };
+ },
+ onUnselect: function() {
+ hideAllSetterColumns();
+ hidePropertySetter()
+ },
tick: function(pixel) {
+ pixel.frequency ??= (ambaPlaceProperties?.noteBlockFrequency ?? 440);
+ pixel.length ??= (ambaPlaceProperties?.noteBlockLength ?? 1);
+ pixel.volume ??= (ambaPlaceProperties?.noteBlockVolume ?? 1);
+ pixel.delay ??= (ambaPlaceProperties?.noteBlockDelay ?? 0);
var pixelSoundName = `x${pixel.x}y${pixel.y}`; //Generate unique-enough name
var pixelPropertyObject = { //Load sound properties from pixel as object;
frequency: pixel.frequency,
@@ -44292,7 +44494,12 @@ maxPixels (default 1000): Maximum amount of pixels/changes (if xSpacing and ySpa
}
});
//SPECIFY CURRENT ELEMENT, MOUSE SIZE, AND TPS ON LOAD ##
- window.addEventListener("load",function() {
+ /*if(urlParams.get("pause") !== null) {
+ paused = true;
+ document.getElementById("pauseButton").setAttribute("on","true")
+ };*/
+
+ window.addEventListener("load",function() {
currentElement = urlParams.get("currentElement") ?? "sand";
if(!elementExists(currentElement)) {
currentElement = "sand"
@@ -44316,15 +44523,492 @@ maxPixels (default 1000): Maximum amount of pixels/changes (if xSpacing and ySpa
if(shapeOrder.indexOf(shape) == -1) {
shape = "square"
};
- currentShape = shape
+ currentShape = shape;
+
+ /*if(urlParams.get("pause") !== null) {
+ paused = true;
+ document.getElementById("pauseButton").setAttribute("on","true")
+ };*/
});
+ //PRESSURE SYSTEM ##
+ loadSettings();
+ settings.dopressure ??= false;
+ settings.drawpressure ??= false;
+ saveSettings();
+ pressureCellSize = 4;
+
+ function getPressureAtPixelCoords(pixelX,pixelY) {
+ var pressureCellX = Math.floor(pixelX / pressureCellSize);
+ var pressureCellY = Math.floor(pixelY / pressureCellSize);
+ return pressureMap?.[pressureCellX]?.[pressureCellY] ?? null
+ };
+
+ function regeneratePressureMap(_width,_height) {
+ pressureMap.forEach(function(x) {
+ x.forEach(y => y = null);
+ x.length = 0;
+ x = null
+ });
+ pressureMap.length = 0;
+ pressureMap = null;
+ pressureMap = new Array(_width);
+ for(var i = 0; i < pressureMap.length; i++) {
+ pressureMap[i] = new Array(height).fill(0)
+ };
+ };
+
+ pressureChangeDivisor = 2;
+ minimumPressure = -9999999;
+
+ elements.sand.pressurePermeability = 0.44;
+ elements.snow.pressurePermeability = 0.7;
+ elements.ice.pressureHigh = 800;
+ elements.gravel.pressurePermeability = 0.53;
+ elements.rock.pressurePermeability = 0.56,
+ elements.wall.blockPressure = true;
+ elements.brick.pressurePermeability = 0.002; //given in L/s*m^2 //at 150Pa //per https://www.astm.org/stp157720130132.html //i don't know how to unit the pressure because it's not scaled to anything in reality
+ elements.brick.pressureHigh = 90; //arbitrary
+ elements.glass.pressureHigh = 70; //arbitrary
+ elements.wood.pressureHigh = 60; //arbitrary
+ runAfterLoad(function() {
+ var gravels = Object.keys(elements).filter(n => n.endsWith("gravel"));
+ for(var i = 0; i < gravels.length; i++) {
+ var gravelName = gravels[i];
+ elements[gravelName].pressureHigh ??= 400;
+ };
+ eLists.GRAVEL = gravels;
+
+ var shards = Object.keys(elements).filter(n => n.endsWith("shards"));
+ for(var i = 0; i < shards.length; i++) {
+ var shardName = shards[i];
+ var data = elements[shardName];
+ if(data.breakInto) {
+ data.pressureHigh ??= 400;
+ }
+ };
+ eLists.SHARD = shards;
+
+ var elementsThatBreakIntoScrap = Object.keys(elements).filter(n => elements[n].breakInto?.endsWith?.("scrap"));
+ for(var i = 0; i < elementsThatBreakIntoScrap.length; i++) {
+ var etbisName = elementsThatBreakIntoScrap[i];
+ var data = elements[etbisName]
+ var _hardness = data.hardness ?? 0.5;
+ data.pressureHigh ??= (_hardness * 625);
+ };
+
+ var rocks = Object.keys(elements).filter(n => elements[n]._data?.[2]?.endsWith?.("rock"));
+ for(var i = 0; i < rocks.length; i++) {
+ var rockName = rocks[i];
+ elements[rockName].pressureHigh ??= 250;
+ };
+ eLists.ROCK = rocks
+ });
+
+
+ function pressureTick(forceTick=false) {
+ if(!(settings.dopressure)) {
+ return
+ };
+ if(paused && !(forceTick)) {
+ return
+ } else if((!paused) || forceTick) { //shouldn't be necessary
+ var positions = [];
+ for(var x = 0; x < pressureMap.length; x++) {
+ for(var y = 0; y < pressureMap[x].length; y++) {
+ positions.push([x,y])
+ };
+ };
+ shuffleArray(positions);
+ for(var i = 0; i < positions.length; i++) {
+ var [x,y] = positions[i];
+ // yes i took this from doHeat lol
+ var v0 = pressureMap[x]?.[y];
+ if(typeof(v0) !== "undefined") {
+ var _ac = arrayToShuffled(mooreDonutCoords);
+ if(isNaN(v0) || (v0 < minimumPressure)) { pressureMap[x][y] = 0; v0 = 0 };
+ var cellLeftCoord = x * pressureCellSize;
+ var cellTopCoord = y * pressureCellSize;
+ var cellRightCoord = ((x + 1) * pressureCellSize) - 1;
+ var cellBottomCoord = ((y + 1) * pressureCellSize) - 1;
+ var pixels = getPixelsInRegion(cellLeftCoord,cellTopCoord,cellRightCoord,cellBottomCoord);
+ var howManyPixelsFitPerCell = (pressureCellSize ** 2);
+ var thisCellPermeability = 1;
+ if(pixels.length > 0) {
+ var pixelWasDeleted = false;
+ pixels.forEach(function(pixel) {
+ //var pressure = v0;
+ var data = elements[pixel.element];
+ if(!data) { return };
+ var highResult = data.highPressureTransition ?? data.breakInto
+ var lowResult = data.lowPressureTransition ?? data.breakInto
+ if((typeof(data.pressureHigh) == "number") && (typeof(highResult) !== "undefined")) {
+ //console.log(data.pressureHigh,highResult);
+ if(v0 >= data.pressureHigh) {
+ while(Array.isArray(highResult)) {
+ highResult = randomChoice(highResult)
+ };
+ if(highResult === null) {
+ deletePixel(pixel.x,pixel.y)
+ return
+ } else {
+ changePixel(pixel,highResult)
+ };
+ return
+ }
+ };
+ if((typeof(data.pressureLow) == "number") && (typeof(lowResult) !== "undefined")) {
+ if(v0 <= data.pressureLow) {
+ while(Array.isArray(lowResult)) {
+ lowResult = randomChoice(lowResult)
+ };
+ if(lowResult === null) {
+ deletePixel(pixel.x,pixel.y)
+ return
+ } else {
+ changePixel(pixel,lowResult)
+ };
+ return
+ }
+ }
+ });
+ if(pixelWasDeleted) {
+ pixels = getPixelsInRegion(cellLeftCoord,cellTopCoord,cellRightCoord,cellBottomCoord)
+ };
+ var emptySpaces = howManyPixelsFitPerCell - pixels.length;
+ var preThisCellPermeability = pixels.map(x => getElementPressurePermeability(x.element));
+ thisCellPermeability = (sumNumericArray(preThisCellPermeability) + emptySpaces) / howManyPixelsFitPerCell;
+ };
+ for (var j = 0; j < _ac.length; j++) {
+ var offsets = _ac[j];
+ var nx = x+(offsets[0]);
+ var ny = y+(offsets[1]);
+ var taxicabDistance = sumNumericArray(offsets.map(Math.abs));
+ var adjustment = 1/Math.sqrt(taxicabDistance);
+ var v1 = pressureMap[nx]?.[ny];
+ if(typeof(v1) === "number") {
+ if(isNaN(v1) || (v1 < minimumPressure)) { pressureMap[nx][ny] = 0; v1 = 0 };
+ if(v0 == v1) { continue }
+ //coords of new cell
+ var newCellLeftCoord = nx * pressureCellSize;
+ var newCellTopCoord = ny * pressureCellSize;
+ var newCellRightCoord = ((nx + 1) * pressureCellSize) - 1;
+ var newCellBottomCoord = ((ny + 1) * pressureCellSize) - 1;
+ var pixels = getPixelsInRegion(newCellLeftCoord,newCellTopCoord,newCellRightCoord,newCellBottomCoord);
+ var permeability = 1;
+ if(pixels.length > 0) {
+ var pixelWasDeleted = false;
+ pixels.forEach(function(pixel) {
+ //var pressure = v0;
+ var data = elements[pixel.element];
+ if(!data) { return };
+ var highResult = data.highPressureTransition ?? data.breakInto
+ var lowResult = data.lowPressureTransition ?? data.breakInto
+ if((typeof(data.pressureHigh) == "number") && (typeof(highResult) !== "undefined")) {
+ //console.log(data.pressureHigh,highResult);
+ if(v0 >= data.pressureHigh) {
+ while(Array.isArray(highResult)) {
+ highResult = randomChoice(highResult)
+ };
+ if(highResult === null) {
+ deletePixel(pixel.x,pixel.y);
+ pixelWasDeleted = true
+ } else {
+ changePixel(pixel,highResult)
+ };
+ return
+ }
+ };
+ if((typeof(data.pressureLow) == "number") && (typeof(lowResult) !== "undefined")) {
+ if(v0 <= data.pressureLow) {
+ while(Array.isArray(lowResult)) {
+ lowResult = randomChoice(lowResult)
+ };
+ if(lowResult === null) {
+ deletePixel(pixel.x,pixel.y);
+ pixelWasDeleted = true
+ } else {
+ changePixel(pixel,lowResult)
+ };
+ return
+ }
+ }
+ });
+ if(pixelWasDeleted) {
+ pixels = getPixelsInRegion(newCellLeftCoord,newCellTopCoord,newCellRightCoord,newCellBottomCoord)
+ };
+ var emptySpaces = howManyPixelsFitPerCell - pixels.length;
+ var prePermeability = pixels.map(x => getElementPressurePermeability(x.element));
+ permeability = (sumNumericArray(prePermeability) + emptySpaces) / howManyPixelsFitPerCell;
+ //console.log(" with pixels",permeability);
+ }/* else {
+ console.log("without pixels",permeability)
+ }*/;
+
+ if((thisCellPermeability == 0) || (permeability == 0)) {
+ continue
+ } else {
+ permeability = (thisCellPermeability + permeability) / 2; //average of source and destination permeabilities because it's simpler
+ var avg = (v0 + v1)/2;
+ // Set both cell araes to their average, permeability permitting
+ //console.log(pixelTicks,"c",change);
+ pressureMap[x][y] = lerp(pressureMap[x][y],avg,permeability);
+ pressureMap[nx][ny] = lerp(pressureMap[nx][ny],avg,permeability);
+ //set again the variables to the cell values
+ v0 = pressureMap[x][y];
+ v1 = pressureMap[nx][ny];
+ var change = avg - v1;
+ var direction = _ac[j];
+ var intensity = ((Math.sqrt(Math.abs(change)) / pressureChangeDivisor) * adjustment) * Math.sign(change);
+ //console.log(intensity);
+ if(Math.abs(intensity) >= 0.01) {
+ var baseMovement = direction.map(x => x * intensity); //Will be turned into an int when it's added to the pixels' velocities
+ if(!((baseMovement[0] === 0) && (baseMovement[1] === 0))) {
+ pixels.forEach(function(pixel) {
+ var drag = Math.min(4,1000/(elements[pixel.element]?.density ?? 1000)); //no more than 4 times the effect
+ var trueMovementX = Math.trunc(baseMovement[0] * drag);
+ var trueMovementY = Math.trunc(baseMovement[1] * drag);
+ pixel.vx ??= 0;
+ pixel.vy ??= 0;
+ pixel.vx += trueMovementX;
+ pixel.vy += trueMovementY;
+ })
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ function getElementPressurePermeability(elementName) {
+ if(typeof(elementName) == "object" && elementName.element) {
+ elementName = elementName.element
+ };
+ if(!(elementExists(elementName))) {
+ return 0
+ };
+ var elementData = elements[elementName];
+ if(elementData.blockPressure) {
+ return 0
+ } else {
+ if(elementData.state == "gas") {
+ return 1
+ } else {
+ return elementData.pressurePermeability ?? 0
+ };
+ };
+ };
+
+ function changePressure(x,y,value,operationType="+",trueIfPixelCoordinates_FalseIfPressureGridCoordinates=false) {
+ if(trueIfPixelCoordinates_FalseIfPressureGridCoordinates) {
+ x = Math.floor(x / pressureCellSize);
+ y = Math.floor(y / pressureCellSize);
+ };
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ switch(operationType.toLowerCase()) {
+ default:
+ case "+":
+ case "add":
+ case "addition":
+ case "plus":
+ case "increase":
+ case "increment":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] += value
+ };
+ break;
+ case "-":
+ case "subtract":
+ case "subtraction":
+ case "minus":
+ case "take away":
+ case "takeaway":
+ case "decrease":
+ case "decrement":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] -= value
+ };
+ break;
+ case "*":
+ case "x":
+ case "×":
+ case "multiply":
+ case "multiplication":
+ case "times":
+ case "by":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] *= value
+ };
+ break;
+ case "/":
+ case "÷":
+ case "divide":
+ case "division":
+ case "divided by":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] /= value
+ };
+ break;
+ case "%":
+ case "mod":
+ case "modulo":
+ case "modulus":
+ case "modulo by":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] %= value
+ };
+ break;
+ case "=":
+ case "set":
+ case "equals":
+ case "assign":
+ case "assignment":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] = value
+ };
+ break;
+ case ">": //lower-bounds the color
+ case ">=":
+ case "min":
+ case "minimum":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] = Math.max(value,pressureMap[x][y])
+ };
+ break;
+ case "<":
+ case "<=":
+ case "max": //upper-bounds the color
+ case "maximum":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ pressureMap[x][y] = Math.min(value,pressureMap[x][y])
+ };
+ break;
+ case "^":
+ case "**":
+ case "exp":
+ case "exponent":
+ case "exponentiate":
+ case "raise":
+ case "raise to":
+ case "raised to":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ var sign1 = Math.sign(pressureMap[x][y]);
+ var sign2 = Math.sign(value);
+ pressureMap[x][y] = (Math.abs(pressureMap[x][y]) ** Math.abs(value)) * sign1 * sign2;
+ };
+ break;
+ case "√":
+ case "n√":
+ case "root":
+ case "nth root":
+ if(typeof(pressureMap?.[x]?.[y]) === "number") {
+ var sign1 = Math.sign(pressureMap[x][y]);
+ var sign2 = Math.sign(value);
+ pressureMap[x][y] = (Math.abs(pressureMap[x][y]) ** Math.abs(1 / value)) * sign1 * sign2;
+ };
+ };
+ if(isNaN(pressureMap[x][y])) { pressureMap[x][y] = 0 };
+ return pressureMap[x][y];
+ } else {
+ return false
+ }
+ };
+
+ function setGlobalPressure(value) {
+ for(var x = 0; x < pressureMap.length; x++) {
+ for(var y = 0; y < pressureMap[x].length; y++) {
+ pressureMap[x][y] = value
+ }
+ }
+ }
+
+ function alertIfPressureDisabled() {
+ if(!(settings.dopressure)) {
+ logMessage("Pressure simulation is disabled")
+ }
+ };
+
+ elements.add_pressure = {
+ color: "#FF0000",
+ behavior: behaviors.WALL,
+ category: "special",
+ tool: function(pixel) {
+ changePressure(pixel.x,pixel.y,3 ** (shiftDown + 1),"+",true);
+ }
+ };
+
+ elements.subtract_pressure = {
+ color: "#0000FF",
+ behavior: behaviors.WALL,
+ category: "special",
+ tool: function(pixel) {
+ changePressure(pixel.x,pixel.y,3 ** (shiftDown + 1),"-",true);
+ }
+ };
+
+ elements.zero_pressure = {
+ color: "#000000",
+ behavior: behaviors.WALL,
+ category: "special",
+ tool: function(pixel) {
+ changePressure(pixel.x,pixel.y,0,"=",true);
+ }
+ };
+
+ elements.reset_pressure = {
+ color: "#000000",
+ maxSize: 1,
+ behavior: behaviors.WALL,
+ category: "special",
+ tool: function(pixel) {
+ setGlobalPressure(0)
+ }
+ };
+
+ function pressureTicker(forceTick=false) {
+ if(settings.dopressure && ((!paused) || forceTick)) {
+ pressureTick(forceTick)
+ }
+ };
+
+ oldDoFrame = doFrame;
+ doFrame = function() {
+ oldDoFrame();
+ pressureTicker(true)
+ };
+
+ runAfterButtons(function() {
+ //WIDTH AND HEIGHT AREN'T DEFINED UNTIL THEN FOR SOME FUCKING REASON
+ oldClearAll = clearAll;
+ clearAll = function() {
+ oldClearAll();
+ regeneratePressureMap(Math.ceil(width / pressureCellSize),Math.ceil(height / pressureCellSize)) // use the global width and height
+ };
+
+ pressureMap = new Array(Math.ceil(width / pressureCellSize));
+ for(var i = 0; i < pressureMap.length; i++) {
+ pressureMap[i] = new Array(Math.ceil(height / pressureCellSize)).fill(0)
+ };
+
+ afterEveryTick(pressureTicker)
+ })
//FIX ##
//fsr it's pausing silently on load now so this should fix that by silently unpausing it on load
window.addEventListener("load",function() {
- paused = false;
+ if(urlParams.get("paused") !== null) {
+ paused = true;
+ document.getElementById("pauseButton").setAttribute("on","true");
+ } else {
+ paused = false;
+ document.getElementById("pauseButton").setAttribute("on","false");
+ }
crimsonObject.dirt = "crimsoil"; //something is changing it to sand
});
+ //
+
//MISCELLANEOUS CHANGES ##
eLists.PIPE = ['pipe', 'destroyable_pipe', 'e_pipe', 'destroyable_e_pipe', 'channel_pipe', 'destroyable_channel_pipe', 'bridge_pipe'];
elements.pipe_stage_shifter = {
@@ -44442,7 +45126,7 @@ maxPixels (default 1000): Maximum amount of pixels/changes (if xSpacing and ySpa
//aChefsDream fix: (re-)define juice reactions
elements.juice.reactions ??= {};
- gigadebugMode = false;
+ gigadebugMode = false; //fights every-tick log spam by limiting each message to being logged 50 times
if(gigadebugMode) {
logLimit = 50;
logLimitCache = {};
@@ -44455,7 +45139,9 @@ maxPixels (default 1000): Maximum amount of pixels/changes (if xSpacing and ySpa
logLimitCache[argsKey]++
}
}
+
//END ##
+ console.log("Mod loaded")
} catch (error) {
alert(`Load failed (try reloading).\nThis is likely a sporadic failure caused by inconsistencies in how mods are loaded, and will likely fix itself in a refresh or two. If it persists, then it's an issue.\nError: ${error.stack}`);
console.error(error)
diff --git a/mods/doom.js b/mods/doom.js
new file mode 100644
index 00000000..1305e647
--- /dev/null
+++ b/mods/doom.js
@@ -0,0 +1,935 @@
+elements.screen = {
+ name: "Screen",
+ color: "#000000",
+ hidden: true
+}
+elements.doom = {
+ color: "#000000",
+ onSelect: function() {
+ startDoom()
+ }
+}
+
+let running = false;
+
+const offsetX = 0;
+const offsetY = 0;
+const screenWidth = 166 - (2 * offsetX);
+const screenHeight = 82 - (2 * offsetY);
+const halfHeight = screenHeight / 2 + offsetY;
+
+const fov = 50;
+const halfFov = fov / 2;
+
+const showDebugText = true;
+
+const map = [
+ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1],
+ [1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1],
+ [1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
+];
+
+const colors = ["#ff0000", "#0000ff", "#ffffff", "#808080", "#ff5000"];
+
+const defaults = {
+ x: 2,
+ y: 2,
+ angle: 90
+}
+
+const colorSettings = {
+ floor: "#cccccc",
+ ceiling: "#1e1e1e",
+}
+
+const mapHeight = map.length;
+const mapWidth = map[0].length;
+const minimapOffset = 5;
+
+const speed = {
+ movementSpeed: 0.5,
+ rotationalSpeed: 5,
+ verticalRotationalSpeed: 5,
+}
+
+const planeX = 0;
+const planeY = 0.66;
+
+const inc = fov / screenWidth;
+const precision_ = 64;
+const maxDist = 25;
+const accuracy = 1;
+
+
+// const colorSettings = {
+// floor: "#d1bd62",
+// ceiling: "#f0c743"
+// }
+
+const degToRad = (deg) => deg * (Math.PI / 180);
+const radToDeg = (rad) => rad * (180 / Math.PI);
+const splitHex = (hex) => hex.slice(1).match(/../g).map(a => Math.floor(parseInt(a, 16)));
+const hexify = (rgb) => rgb.map(a => Math.floor(a).toString(16).padStart(2, "0")).join("");
+function colorLerp(color_, color2_, t) {
+ const color = splitHex(color_);
+ const color2 = splitHex(color2_);
+ const r = (1 - t) * color[0] + t * color2[0];
+ const g = (1 - t) * color[1] + t * color2[1];
+ const b = (1 - t) * color[2] + t * color2[2];
+ return hexify([r, g, b]);
+}
+
+function clamp(x, min, max) {
+ return Math.max(min, Math.min(x, max));
+}
+
+class Player {
+ constructor(x, y, angle) {
+ this.x = x;
+ this.y = y;
+ this.angle = angle;
+ this.verticalOffset = 0;
+ }
+
+ update(key) {
+ // if (key.keyCode == 37) { // left
+ if (key.key == "a") {
+ this.angle -= speed.rotationalSpeed;
+ // } else if (key.keyCode == 39) { // right
+ } else if (key.key == "d") {
+ this.angle += speed.rotationalSpeed;
+ } else if (key.key == "b") { // up
+ this.verticalOffset = clamp(this.verticalOffset + 5, -45, 45);
+ } else if (key.key == "n") { // down
+ this.verticalOffset = clamp(this.verticalOffset - 5, -45, 45);
+ }
+ if (key.key == "w") {
+ console.log(this.angle);
+ const playerCos = Math.cos(degToRad(this.angle)) * speed.movementSpeed;
+ const playerSin = Math.sin(degToRad(this.angle)) * speed.movementSpeed;
+ const newX = this.x + playerCos;
+ const newY = this.y + playerSin;
+ const oldX = this.x;
+ const oldY = this.y;
+ if (map[Math.floor(newY)][Math.floor(oldX)] == 0) {
+ this.y = newY;
+ }
+ if (map[Math.floor(oldY)][Math.floor(newX)] == 0) {
+ this.x = newX;
+ }
+ } else if (key.key == "s") {
+ const playerCos = Math.cos(degToRad(this.angle)) * speed.movementSpeed;
+ const playerSin = Math.sin(degToRad(this.angle)) * speed.movementSpeed;
+ const newX = this.x - playerCos;
+ const newY = this.y - playerSin;
+ const oldX = this.x;
+ const oldY = this.y;
+ if (map[Math.floor(newY)][Math.floor(oldX)] == 0) {
+ this.y = newY;
+ }
+ if (map[Math.floor(oldY)][Math.floor(newX)] == 0) {
+ this.x = newX;
+ }
+ } else if (key.key == "a" && shiftDown) {
+ const playerCos = Math.cos(degToRad(this.angle + 90)) * speed.movementSpeed;
+ const playerSin = Math.sin(degToRad(this.angle + 90)) * speed.movementSpeed;
+ const newX = this.x - playerCos;
+ const newY = this.y - playerSin;
+ const oldX = this.x;
+ const oldY = this.y;
+ if (map[Math.floor(newY)][Math.floor(oldX)] == 0) {
+ this.y = newY;
+ }
+ if (map[Math.floor(oldY)][Math.floor(newX)] == 0) {
+ this.x = newX;
+ }
+ } else if (key.key == "d" && shiftDown) {
+ const playerCos = Math.cos(degToRad(this.angle - 90)) * speed.movementSpeed;
+ const playerSin = Math.sin(degToRad(this.angle - 90)) * speed.movementSpeed;
+ const newX = this.x - playerCos;
+ const newY = this.y - playerSin;
+ const oldX = this.x;
+ const oldY = this.y;
+ if (map[Math.floor(newY)][Math.floor(oldX)] == 0) {
+ this.y = newY;
+ }
+ if (map[Math.floor(oldY)][Math.floor(newX)] == 0) {
+ this.x = newX;
+ }
+ }
+ }
+}
+
+const player = new Player(defaults.x, defaults.y, defaults.angle);
+
+// 5x5
+const font = {
+ a: [
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1
+ ],
+ b: [
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 0
+ ],
+ c: [
+ 0, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1
+ ],
+ d: [
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 0
+ ],
+ e: [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1
+ ],
+ f: [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ g: [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 0, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ h: [
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1
+ ],
+ i: [
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ j: [
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 1, 1, 0
+ ],
+ k: [
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0
+ ],
+ l: [
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0
+ ],
+ m: [
+ 1, 1, 1, 1, 0,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1
+ ],
+ n: [
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1
+ ],
+ o: [
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 1, 1, 0
+ ],
+ p: [
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ q: [
+ 0, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1
+ ],
+ r: [
+ 1, 0, 1, 1, 1,
+ 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ s: [
+ 0, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 0
+ ],
+ t: [
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0
+ ],
+ u: [
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ v: [
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0
+ ],
+ w: [
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0
+ ],
+ x: [
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1
+ ],
+ y: [
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0
+ ],
+ z: [
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0
+ ],
+ "0": [
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0
+ ],
+ "1": [
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ "2": [
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1
+ ],
+ "3": [
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ "4": [
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1
+ ],
+ "5": [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ "6": [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ "7": [
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1
+ ],
+ "8": [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ "9": [
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1
+ ],
+ ".": [
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ ":": [
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+ ],
+ "-": [
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+ ],
+ "+": [
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ ],
+ ",": [
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ ],
+ "[": [
+ 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0
+ ],
+ "]": [
+ 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0
+ ],
+ "(": [
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0
+ ],
+ ")": [
+ 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ ";": [
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ "!": [
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ],
+ "{": [
+ 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 1, 0, 0
+ ],
+ "}": [
+ 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0
+ ],
+ "_": [
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0
+ ],
+ "°": [
+ 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+ ],
+ "|": [
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0
+ ]
+}
+
+const customWidth = {
+ i: 1,
+ l: 4,
+ z: 4,
+ "0": 4,
+ "1": 1,
+ ".": 1,
+ ":": 1,
+ "-": 3,
+ "+": 3,
+ ",": 1,
+ "[": 2,
+ "]": 2,
+ "(": 2,
+ ")": 2,
+ ";": 1,
+ "!": 1,
+ "{": 3,
+ "}": 3,
+ "_": 3,
+ "°": 3,
+ " ": 3,
+ "|": 1,
+}
+
+class TextRenderer {
+ static getCharWidth(char) {
+ return customWidth[char] ?? 5;
+ }
+
+ static drawChar(char, x, y, color) {
+ if (!font[char]) return;
+ const width = this.getCharWidth();
+ for (let i = 0; i < width; i++) {
+ for (let j = 0; j < 5; j++) {
+ if (font[char][j * 5 + i] == 1) {
+ pixelMap[x + offsetX + i][y + offsetY + j].color = color;
+ }
+ }
+ }
+ }
+
+ static drawText(text, x, y, color) {
+ let offset = 0;
+ for (const char of text.toLowerCase().split("")) {
+ const width = this.getCharWidth(char);
+ this.drawChar(char, x + offset, y, color);
+ offset += width + 1;
+ }
+ }
+
+ static getStringWidth(text) {
+ return text.split("").map(a => this.getCharWidth(a)).reduce((a, b) => a + b, 0) + text.length - 1;
+ }
+
+ static drawCenteredText(text, x1, y, color) {
+ const x = Math.floor(x1 - (this.getStringWidth(text) / 2));
+ this.drawText(text, x, y, color);
+ }
+}
+
+class ButtonRegistry {
+ constructor (screen, buttons) {
+ this.screen = screen;
+ this.buttons = buttons;
+ this.currentButton = 0;
+ if (this.buttons.length > 0) {
+ this.buttons[this.currentButton].toggleSelection();
+ }
+ }
+
+ next() {
+ this.buttons[this.currentButton].toggleSelection();
+ this.currentButton++;
+ if (this.currentButton >= this.buttons.length) {
+ this.currentButton %= this.buttons.length;
+ }
+ this.buttons[this.currentButton].toggleSelection();
+ }
+
+ prev() {
+ this.buttons[this.currentButton].toggleSelection();
+ this.currentButton--;
+ if (this.currentButton < 0) {
+ this.currentButton = this.buttons.length - 1;
+ }
+ this.buttons[this.currentButton].toggleSelection();
+ }
+
+ current() {
+ return this.buttons[this.currentButton];
+ }
+}
+
+class GameMenu {
+ constructor (name, screen, width, height, offsets = null) {
+ this.name = name;
+ this.screen = screen;
+ this.width = width;
+ this.height = height;
+ this.offsetX = Math.floor((screenWidth - width - (offsets ? offsets.x : 0)) / 2) + (offsets ? offsets.x : 0);
+ this.offsetY = Math.floor((screenHeight - height - 10 - (offsets ? offsets.y : 0)) / 2) + (offsets ? offsets.y : 0) + 10;
+ this.buttons = [];
+ this.buttonRegistry = new ButtonRegistry(this, []);
+ }
+
+ draw() {
+ for (const button of this.buttons) {
+ button.draw();
+ }
+ }
+
+ getOffsetX() {
+ return offsetX + this.offsetX;
+ }
+
+ getOffsetY() {
+ return offsetY + this.offsetY;
+ }
+
+ onKey(ev) {
+ if (ev.key == "b") { // up
+ this.buttonRegistry.prev();
+ } else if (ev.key == "n") { // down
+ this.buttonRegistry.next();
+ } else if (ev.key == "Enter") {
+ this.buttonRegistry.current().click();
+ }
+ }
+
+ addButtons(...buttons) {
+ this.buttons.push(...buttons);
+ this.updateButtonRegistry();
+ }
+
+ getButtons() {
+ return this.buttons;
+ }
+
+ updateButtonRegistry() {
+ this.buttonRegistry = new ButtonRegistry(this, this.buttons);
+ }
+}
+
+class GuiButton {
+ constructor (x, y, width, height, text, color, screen) {
+ this.x = x + screen.getOffsetX();
+ this.y = y + screen.getOffsetY();
+ this.width = width;
+ this.height = height;
+ this.text = text;
+ this.color = color;
+ this.onPressed = () => {};
+ this.selected = false;
+ this.screen = screen;
+ }
+
+ draw() {
+ for (let i = this.x; i < this.x + this.width; i++) {
+ for (let j = this.y; j < this.y + this.height; j++) {
+ if (this.selected && (i == this.x || j == this.y || i == this.x + this.width - 1 || j == this.y + this.height - 1)) {
+ pixelMap[i][j] = "#0080000";
+ } else pixelMap[i][j] = this.color
+ }
+ }
+ TextRenderer.drawCenteredText(this.text, this.x + (this.width / 2), Math.floor(this.y + (this.height / 2) - 5/2), "#ffffff");
+ }
+
+ onClick(cb) {
+ this.onPressed = cb;
+ }
+
+ click() {
+ this.onPressed();
+ }
+
+ toggleSelection() {
+ this.selected = !this.selected;
+ }
+}
+
+class GuiUtils {
+ static drawRect(x1, y1, x2, y2, color) {
+ for (let i = Math.max(Math.min(x1, x2), 0); i < Math.min(Math.max(x1, x2), width); i++) {
+ for (let j = Math.max(Math.min(y1, y2), 0); j < Math.min(Math.max(y1, y2), height); j++) {
+ pixelMap[i][j].color = color;
+ }
+ }
+ }
+
+ static drawOutline(x1, y1, x2, y2, color) {
+ const initI = Math.max(Math.min(x1, x2), 0);
+ const endI = Math.min(Math.max(x1, x2), width);
+ const initJ = Math.max(Math.min(y1, y2), 0);
+ const endJ = Math.min(Math.max(y1, y2), height);
+ for (let i = initI; i < endI; i++) {
+ for (let j = initJ; j < endJ; j++) {
+ if (i == initI || i == endI - 1 || j == initJ || j == endJ - 1) {
+ pixelMap[i][j].color = color;
+ }
+ }
+ }
+ }
+
+ static drawVerticalLine(x, y1, y2, color) {
+ for (let i = Math.max(Math.min(y1, y2), 0); i <= Math.min(Math.max(y1, y2), height); i++) {
+ if (!pixelMap[x][i]) continue;
+ pixelMap[x][i].color = color;
+ }
+ }
+}
+
+class TestGameMenu extends GameMenu {
+ constructor (screen, width, height, offsets = null) {
+ super("test menu screen", screen, width, height, offsets);
+ const button1 = new GuiButton(1, 1, width - 2, 20, "button", "#005555", this);
+ button1.onClick(() => {
+ button1.color = "#ff0000";
+ button2.color = "#005555";
+ })
+ const button2 = new GuiButton(1, 22, width - 2, 20, "button 2", "#005555", this);
+ button2.onClick(() => {
+ button2.color = "#ff0000";
+ button1.color = "#005555";
+ })
+ this.addButtons(
+ button1,
+ button2
+ )
+ }
+ draw() {
+ for (let i = this.getOffsetX(); i < this.width + this.getOffsetX(); i++) {
+ for (let j = this.getOffsetY(); j < this.height + this.getOffsetY(); j++) {
+ pixelMap[i][j].color = "#ffffff";
+ }
+ }
+ super.draw();
+ }
+}
+
+class GameScreen {
+ clock() {
+ this.fps = this.currentFrames;
+ this.currentFrames = 0;
+ }
+ clear() {
+ for (let i = offsetX; i < width - offsetX; i++) {
+ for (let j = offsetY; j < height - offsetY; j++) {
+ pixelMap[i][j].color = "#ffffff";
+ }
+ }
+ }
+
+ draw() {
+ if (!this.currentFrames) this.currentFrames = 0;
+ this.currentFrames++;
+ this.clear();
+ this.drawLevel();
+ this.drawMinimap();
+ if (showDebugText) {
+ TextRenderer.drawText(`angle: ${Math.floor(player.angle)}°`, 1, 1, "#ffffff");
+ TextRenderer.drawText(`pos: ${player.x.toFixed(2)} | ${player.y.toFixed(2)}`, 1, 7, "#ffffff");
+ TextRenderer.drawText(`fps: ${this.fps}`, 1, 13, "#ffffff");
+ TextRenderer.drawText(`vertangle: ${player.verticalOffset}`, 1, 19, "#ffffff");
+ }
+ if (this.menuScreen) {
+ this.drawMenu();
+ }
+ }
+
+ drawMenu() {
+ this.drawOverlay();
+ GuiUtils.drawRect(this.menuScreen.getOffsetX(), Math.floor((screenHeight - this.menuScreen.height) / 2) - 2, this.menuScreen.getOffsetX() + this.menuScreen.width, this.menuScreen.getOffsetY(), "#1e1e1e");
+ TextRenderer.drawCenteredText(this.menuScreen.name, (this.menuScreen.width / 2) + this.menuScreen.getOffsetX(), Math.floor((screenHeight - this.menuScreen.height) / 2) - 1, "#ffffff");
+ this.menuScreen.draw();
+ }
+
+ drawOverlay() {
+ for (let i = offsetX; i < width - offsetX; i++) {
+ for (let j = offsetY; j < height - offsetY; j++) {
+ pixelMap[i][j].color = "#" + colorLerp(pixelMap[i][j].color, "#000000", 0.5);
+ }
+ }
+ }
+
+ drawLevel() {
+ let rayAngle = player.angle - halfFov;
+ for (let i = 0; i < screenWidth; i += accuracy) {
+ let rayX = player.x;
+ let rayY = player.y;
+ const rayCos = Math.cos(degToRad(rayAngle)) / precision_;
+ const raySin = Math.sin(degToRad(rayAngle)) / precision_;
+ let wall = 0;
+
+ while (wall == 0) {
+ rayX += rayCos;
+ rayY += raySin;
+ wall = map[Math.floor(rayY)][Math.floor(rayX)];
+ }
+
+ const angle = radToDeg(Math.atan2(rayY, rayX));
+ const side = (angle >= 45 && angle <= 135) || (angle >= 275 && angle <= 315);
+
+ const distance = Math.sqrt((player.x - rayX) ** 2 + (player.y - rayY) ** 2) * Math.cos(degToRad(rayAngle - player.angle));
+
+ const wallHeight = Math.floor(halfHeight / distance);
+
+ let t = Math.min(1, (1 / maxDist) * distance);
+
+ const color = "#" + colorLerp(colors[wall - 1], "#000000", t);
+ const ceilingColor = colorSettings.ceiling;
+ const floorColor = colorSettings.floor;
+
+ GuiUtils.drawVerticalLine(offsetX + i, halfHeight - wallHeight - player.verticalOffset, halfHeight + wallHeight - player.verticalOffset, color);
+ GuiUtils.drawVerticalLine(offsetX + i, offsetY, halfHeight - wallHeight - 1 - player.verticalOffset, ceilingColor);
+ GuiUtils.drawVerticalLine(offsetX + i, halfHeight + wallHeight + 1 - player.verticalOffset, height - offsetY - 1, floorColor);
+
+ rayAngle += inc;
+ }
+ }
+
+ drawMinimap() {
+ for (let i = 0; i < mapWidth; i++) {
+ for (let j = 0; j < mapHeight; j++) {
+ const x = width - offsetX - minimapOffset - mapWidth + i;
+ const y = offsetY + minimapOffset + j;
+ if (map[j][i] == 0) {
+ pixelMap[x][y].color = colorSettings.floor;
+ } else {
+ pixelMap[x][y].color = colors[map[j][i] - 1];
+ }
+ if (i == Math.floor(player.x) && j == Math.floor(player.y)) {
+ pixelMap[x][y].color = "#00ffff";
+ }
+ }
+ }
+ }
+
+ onKey(ev) {
+ // if (ev.key == "Escape") {
+ // this.menuScreen = this.menuScreen ? null : new TestGameMenu(this, Math.floor(0.75 * screenWidth), Math.floor(0.75 * screenHeight));
+ // }
+ if (!this.menuScreen) {
+ player.update(ev);
+ } else {
+ this.menuScreen.onKey(ev);
+ }
+ }
+}
+
+const game = new GameScreen();
+
+setInterval(cellTick, (1000/(tps*4)));
+setInterval(() => {game.clock()}, 1000);
+
+function cellTick() {
+ if (running && !paused) {
+ game.draw();
+ }
+}
+
+function startDoom() {
+ if (!running) {
+ videoFrame = 0;
+
+ for (let i = offsetX; i < width - offsetX; i++) {
+ for (let j = offsetY; j < height - offsetY; j++) {
+ if (pixelMap[i][j]) deletePixel(i, j);
+ createPixel("screen", i, j);
+ }
+ }
+ }
+ running = !running;
+}
+
+window.addEventListener("keydown", (ev) => {
+ if (ev.key == "u") {
+ startDoom();
+ } else {
+ game.onKey(ev);
+ }
+})
\ No newline at end of file
diff --git a/mods/limewater.js b/mods/limewater.js
new file mode 100644
index 00000000..9fb271c8
--- /dev/null
+++ b/mods/limewater.js
@@ -0,0 +1,63 @@
+// first time making a mod so bare with me
+
+
+elements.limewater = {
+ color: "#3baaff",
+ behavior: behaviors.LIQUID,
+ category: "liquids",
+ state: "liquid",
+ density: 2211,
+ tempHigh: 100,
+ stateHigh: ["steam", "slaked_lime"],
+ tempLow: 0,
+ stateLow: "limewater_ice",
+ reactions: {"carbon_dioxide": {elem1: "calcium_carbonate_solution", elem2: null },
+ },
+};
+elements.limewater_ice = {
+ color: "#def0ff",
+ behavior: behaviors.WALL,
+ category: "solids",
+ state: "solid",
+ density: 2211,
+ temp: -5,
+ tempHigh: 2,
+ stateHigh: "limewater",
+};
+elements.calcium_carbonate_solution = {
+ color: "#ffffff",
+ behavior: behaviors.LIQUID,
+ category: "liquids",
+ state: "liquid",
+ density: 2710,
+ tempHigh: 100,
+ stateHigh: ["steam", "calcium_carbonate"],
+};
+
+elements.calcium_carbonate = {
+ color: ["#ffffff", "#e3e3e3"],
+ behavior: behaviors.POWDER,
+ category: "liquids",
+ state: "liquid",
+ density: 2710,
+ temp: 20,
+ tempHigh: 825,
+ stateHigh: "molten_calcium_carbonate",
+};
+
+elements.molten_calcium_carbonate = {
+ color: ["#f5190a", "#d4180b", "#f5190a", "#423f3e"],
+ behavior: behaviors.MOLTEN,
+ category: "states",
+ state: "solid",
+ density: 2710,
+ temp: 900,
+ tempLow: 820,
+ viscosity: 100,
+ stateLow: "calcium_carbonate",
+ reactions: {"water": {elem1: "steam", elem2:"calcium_carbonate"},
+ },
+};
+
+if (!elements.water.reactions) { elements.water.reactions = {} }
+elements.water.reactions.slaked_lime = { "elem1":"limewater", "elem2": "limewater"};